summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accel/qaic/qaic_control.c2
-rw-r--r--drivers/acpi/cppc_acpi.c29
-rw-r--r--drivers/ata/ahci_ceva.c18
-rw-r--r--drivers/ata/libata-core.c9
-rw-r--r--drivers/ata/libata-eh.c37
-rw-r--r--drivers/ata/libata-sata.c2
-rw-r--r--drivers/ata/libata-scsi.c119
-rw-r--r--drivers/ata/libata.h3
-rw-r--r--drivers/ata/sata_mv.c2
-rw-r--r--drivers/block/ublk_drv.c9
-rw-r--r--drivers/bluetooth/btintel.c3
-rw-r--r--drivers/bluetooth/btmtk.c86
-rw-r--r--drivers/bluetooth/btusb.c30
-rw-r--r--drivers/cpufreq/amd-pstate.c8
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c33
-rw-r--r--drivers/cpufreq/powernow-k8.c1
-rw-r--r--drivers/dibs/dibs_loopback.c47
-rw-r--r--drivers/dma/idxd/cdev.c4
-rw-r--r--drivers/dma/idxd/init.c36
-rw-r--r--drivers/dma/sun6i-dma.c11
-rw-r--r--drivers/dma/switchtec_dma.c2
-rw-r--r--drivers/dpll/dpll_core.c27
-rw-r--r--drivers/dpll/dpll_core.h1
-rw-r--r--drivers/dpll/dpll_netlink.c60
-rw-r--r--drivers/gpio/gpio-by-pinctrl.c18
-rw-r--r--drivers/gpio/gpio-pca953x.c34
-rw-r--r--drivers/gpio/gpio-pch.c28
-rw-r--r--drivers/gpio/gpio-sloppy-logic-analyzer.c10
-rw-r--r--drivers/gpio/gpiolib.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c32
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c146
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v15_0.c93
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc21.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c26
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c10
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c23
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_queue.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c78
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c16
-rw-r--r--drivers/gpu/drm/amd/include/kgd_pp_interface.h6
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm.c39
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_pm.c29
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h6
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c5
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h38
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c7
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c59
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c223
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c3
-rw-r--r--drivers/gpu/drm/bridge/display-connector.c11
-rw-r--r--drivers/gpu/drm/display/drm_dp_helper.c12
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c26
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.h2
-rw-r--r--drivers/gpu/drm/imagination/pvr_queue.c7
-rw-r--r--drivers/gpu/drm/imagination/pvr_trace.h16
-rw-r--r--drivers/gpu/drm/mediatek/mtk_crtc.c6
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c7
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c5
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_common.c11
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_v2.c8
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw.c47
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate.c29
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_object.c7
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_blit.c39
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c49
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_shader.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c17
-rw-r--r--drivers/gpu/drm/xe/xe_pt.c13
-rw-r--r--drivers/hv/connection.c47
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hv/mshv_eventfd.c39
-rw-r--r--drivers/hv/mshv_irq.c2
-rw-r--r--drivers/hv/mshv_portid_table.c9
-rw-r--r--drivers/hv/mshv_root_main.c41
-rw-r--r--drivers/hv/mshv_vtl_main.c13
-rw-r--r--drivers/hv/vmbus_drv.c28
-rw-r--r--drivers/hwmon/adt7470.c129
-rw-r--r--drivers/hwmon/ina2xx.c61
-rw-r--r--drivers/hwmon/lm63.c5
-rw-r--r--drivers/hwmon/lm90.c4
-rw-r--r--drivers/hwmon/ltc4282.c4
-rw-r--r--drivers/hwmon/nct6775-core.c20
-rw-r--r--drivers/hwmon/npcm750-pwm-fan.c11
-rw-r--r--drivers/hwmon/nzxt-smart2.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c7
-rw-r--r--drivers/hwmon/sht3x.c9
-rw-r--r--drivers/i2c/busses/i2c-amd-mp2-plat.c4
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c11
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c80
-rw-r--r--drivers/i2c/busses/i2c-imx.c54
-rw-r--r--drivers/i2c/busses/i2c-jz4780.c5
-rw-r--r--drivers/i2c/busses/i2c-k1.c10
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c18
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c15
-rw-r--r--drivers/iommu/io-pgfault.c24
-rw-r--r--drivers/iommu/iommufd/device.c2
-rw-r--r--drivers/iommu/iommufd/eventq.c2
-rw-r--r--drivers/iommu/iommufd/pages.c3
-rw-r--r--drivers/iommu/iommufd/viommu.c22
-rw-r--r--drivers/net/can/c_can/c_can_main.c8
-rw-r--r--drivers/net/can/ctucanfd/ctucanfd_base.c14
-rw-r--r--drivers/net/can/ctucanfd/ctucanfd_pci.c3
-rw-r--r--drivers/net/can/rcar/rcar_canfd.c32
-rw-r--r--drivers/net/can/softing/softing_fw.c46
-rw-r--r--drivers/net/can/usb/ems_usb.c43
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c1
-rw-r--r--drivers/net/can/usb/gs_usb.c4
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c1
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c13
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c1
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_fd.c40
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c20
-rw-r--r--drivers/net/dsa/mt7530-mdio.c11
-rw-r--r--drivers/net/dsa/mt7530.c86
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb_main.c16
-rw-r--r--drivers/net/dsa/realtek/rtl83xx.c14
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c19
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c27
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib_private.h1
-rw-r--r--drivers/net/ethernet/intel/ice/virt/queues.c21
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_dev.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_vf_dev.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.h2
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.c12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c79
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c22
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c29
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c2
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c19
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c8
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c4
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_main.c44
-rw-r--r--drivers/net/ethernet/realtek/rtase/rtase_main.c3
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c3
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.c2
-rw-r--r--drivers/net/phy/phylink.c29
-rw-r--r--drivers/net/tun.c109
-rw-r--r--drivers/net/veth.c4
-rw-r--r--drivers/net/vxlan/vxlan_core.c21
-rw-r--r--drivers/net/vxlan/vxlan_mdb.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_htt.c49
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_htt.h12
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.c75
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c165
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.c31
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c12
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.c7
-rw-r--r--drivers/net/wireless/intel/iwlegacy/debug.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c2
-rw-r--r--drivers/of/address.c22
-rw-r--r--drivers/of/of_reserved_mem.c14
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c52
-rw-r--r--drivers/phy/qualcomm/phy-qcom-m31-eusb2.c2
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c6
-rw-r--r--drivers/phy/xilinx/phy-zynqmp.c62
-rw-r--r--drivers/platform/x86/dell/dell-dw5826e-reset.c4
-rw-r--r--drivers/power/supply/bq25890_charger.c2
-rw-r--r--drivers/power/supply/macsmc-power.c52
-rw-r--r--drivers/power/supply/max17040_battery.c6
-rw-r--r--drivers/ptp/ptp_netc.c15
-rw-r--r--drivers/s390/block/dasd.c14
-rw-r--r--drivers/s390/block/dasd_eckd.c11
-rw-r--r--drivers/s390/block/dasd_ioctl.c2
-rw-r--r--drivers/s390/crypto/pkey_cca.c15
-rw-r--r--drivers/s390/crypto/zcrypt_api.c4
-rw-r--r--drivers/s390/crypto/zcrypt_ccamisc.c89
-rw-r--r--drivers/s390/crypto/zcrypt_ccamisc.h6
-rw-r--r--drivers/s390/net/qeth_core_main.c3
-rw-r--r--drivers/s390/scsi/zfcp_aux.c1
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c10
-rw-r--r--drivers/scsi/libiscsi.c2
-rw-r--r--drivers/scsi/libiscsi_tcp.c8
-rw-r--r--drivers/scsi/libsas/sas_init.c37
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c15
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c9
-rw-r--r--drivers/scsi/scsi_debug.c8
-rw-r--r--drivers/spi/spi-cadence.c26
-rw-r--r--drivers/spi/spi-nxp-fspi.c129
-rw-r--r--drivers/spi/spi-qcom-qspi.c3
-rw-r--r--drivers/spi/spi-qpic-snand.c22
-rw-r--r--drivers/spi/spi-spacemit-k1.c22
-rw-r--r--drivers/target/target_core_iblock.c6
-rw-r--r--drivers/target/target_core_transport.c12
-rw-r--r--drivers/ufs/core/ufs-rpmb.c2
-rw-r--r--drivers/ufs/core/ufshcd.c46
-rw-r--r--drivers/vhost/net.c21
258 files changed, 3495 insertions, 1443 deletions
diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c
index bb94d3556904..50bf3340e49c 100644
--- a/drivers/accel/qaic/qaic_control.c
+++ b/drivers/accel/qaic/qaic_control.c
@@ -786,7 +786,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
break;
}
trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
- if (trans_hdr->len < sizeof(trans_hdr) ||
+ if (trans_hdr->len < sizeof(*trans_hdr) ||
size_add(user_len, trans_hdr->len) > user_msg->len) {
ret = -EINVAL;
break;
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 9f572f481241..53d09ca98f06 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -475,17 +475,29 @@ bool acpi_cpc_valid(void)
}
EXPORT_SYMBOL_GPL(acpi_cpc_valid);
-bool cppc_allow_fast_switch(void)
+bool cppc_allow_fast_switch(const struct cpumask *cpus)
{
- struct cpc_register_resource *desired_reg;
+ struct cpc_register_resource *desired_reg, *min_reg, *max_reg;
struct cpc_desc *cpc_ptr;
int cpu;
- for_each_online_cpu(cpu) {
+ for_each_cpu(cpu, cpus) {
cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
+ if (!cpc_ptr)
+ return false;
desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF];
- if (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
- !CPC_IN_SYSTEM_IO(desired_reg))
+ min_reg = &cpc_ptr->cpc_regs[MIN_PERF];
+ max_reg = &cpc_ptr->cpc_regs[MAX_PERF];
+
+ if (!CPC_SUPPORTED(desired_reg) ||
+ (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
+ !CPC_IN_SYSTEM_IO(desired_reg)) ||
+ (CPC_SUPPORTED(min_reg) &&
+ !CPC_IN_SYSTEM_MEMORY(min_reg) &&
+ !CPC_IN_SYSTEM_IO(min_reg)) ||
+ (CPC_SUPPORTED(max_reg) &&
+ !CPC_IN_SYSTEM_MEMORY(max_reg) &&
+ !CPC_IN_SYSTEM_IO(max_reg)))
return false;
}
@@ -1951,16 +1963,17 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
cpc_desc->write_cmd_status = 0;
}
- cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
+ if (CPC_SUPPORTED(desired_reg))
+ cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
/*
* Only write if min_perf and max_perf not zero. Some drivers pass zero
* value to min and max perf, but they don't mean to set the zero value,
* they just don't want to write to those registers.
*/
- if (perf_ctrls->min_perf)
+ if (perf_ctrls->min_perf && CPC_SUPPORTED(min_perf_reg))
cpc_write(cpu, min_perf_reg, perf_ctrls->min_perf);
- if (perf_ctrls->max_perf)
+ if (perf_ctrls->max_perf && CPC_SUPPORTED(max_perf_reg))
cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf);
if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg))
diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c
index 2d6a08c23d6a..2961e53288f4 100644
--- a/drivers/ata/ahci_ceva.c
+++ b/drivers/ata/ahci_ceva.c
@@ -211,7 +211,7 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
rc = phy_init(hpriv->phys[i]);
if (rc)
- goto disable_rsts;
+ goto exit_phys;
}
/* De-assert the controller reset */
@@ -230,14 +230,24 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
return 0;
-disable_rsts:
- ahci_platform_deassert_rsts(hpriv);
-
disable_phys:
while (--i >= 0) {
+ if (ahci_ignore_port(hpriv, i))
+ continue;
+
phy_power_off(hpriv->phys[i]);
phy_exit(hpriv->phys[i]);
}
+ ahci_platform_assert_rsts(hpriv);
+ goto disable_clks;
+
+exit_phys:
+ while (--i >= 0) {
+ if (ahci_ignore_port(hpriv, i))
+ continue;
+
+ phy_exit(hpriv->phys[i]);
+ }
disable_clks:
ahci_platform_disable_clks(hpriv);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c43bd28b20b1..961d03fbc4d9 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4414,6 +4414,15 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "WDC WD3200JD-*", NULL, ATA_QUIRK_WD_BROKEN_LPM },
/*
+ * WD drives with LPM issues (irrespective of supported SATA speeds).
+ * (Unlike ATA_QUIRK_WD_BROKEN_LPM, which is only applied if the drive
+ * exposes SATA Gen1 speed support, and SATA Gen1 speed support only.)
+ */
+ { "WDC WD100EFGX-68CPLN0", NULL, ATA_QUIRK_NOLPM },
+ { "WDC WD102KFBX-68M95N0", NULL, ATA_QUIRK_NOLPM },
+ { "WD Green 2.5 480GB", NULL, ATA_QUIRK_NOLPM },
+
+ /*
* This sata dom device goes on a walkabout when the ATA_LOG_DIRECTORY
* log page is accessed. Ensure we never ask for this log page with
* these devices.
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 05df7ea6954a..c154103d892c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -106,6 +106,12 @@ static const unsigned int ata_eh_flush_timeouts[] = {
UINT_MAX,
};
+static const unsigned int ata_eh_standby_timeouts[] = {
+ 15000, /* Some drives may be slow to standby */
+ /* but don't hold up a suspend too long waiting for them */
+ UINT_MAX,
+};
+
static const unsigned int ata_eh_other_timeouts[] = {
5000, /* same rationale as identify timeout */
10000, /* ditto */
@@ -147,6 +153,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
.timeouts = ata_eh_other_timeouts, },
{ .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
.timeouts = ata_eh_flush_timeouts },
+ { .commands = CMDS(ATA_CMD_STANDBYNOW1),
+ .timeouts = ata_eh_standby_timeouts },
{ .commands = CMDS(ATA_CMD_VERIFY),
.timeouts = ata_eh_reset_timeouts },
};
@@ -650,29 +658,12 @@ int 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->scsicmd != scmd)
- continue;
- if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
- qc == qc->dev->link->deferred_qc)
+ if (qc->scsicmd == scmd &&
+ qc->flags & ATA_QCFLAG_ACTIVE)
break;
}
- if (i < ATA_MAX_QUEUE && qc == qc->dev->link->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);
- qc->dev->link->deferred_qc = NULL;
- cancel_work(&qc->dev->link->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) {
+ if (i < ATA_MAX_QUEUE) {
/* the scmd has an associated qc */
if (!(qc->flags & ATA_QCFLAG_EH)) {
/* which hasn't failed yet, timeout */
@@ -948,10 +939,10 @@ static void ata_eh_set_pending(struct ata_port *ap, bool fastdrain)
ap->pflags |= ATA_PFLAG_EH_PENDING;
/*
- * If we have a deferred qc, requeue it so that it is retried once EH
- * completes.
+ * If we have deferred QCs, requeue them so that the SCSI EH task can
+ * run.
*/
- ata_scsi_requeue_deferred_qc(ap);
+ ata_scsi_requeue_deferred_qc(ap, NULL);
if (!fastdrain)
return;
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index b0706c30da05..ad40f516c6d4 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -913,7 +913,7 @@ static bool ata_scsi_lpm_supported(struct ata_port *ap)
return false;
ata_for_each_link(link, ap, EDGE) {
- ata_for_each_dev(dev, &ap->link, ENABLED) {
+ ata_for_each_dev(dev, link, ENABLED) {
if (dev->quirks & ATA_QUIRK_NOLPM)
return false;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 5868526301a2..d2160ee7ca7d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1685,26 +1685,80 @@ void ata_scsi_deferred_qc_work(struct work_struct *work)
spin_unlock_irqrestore(ap->lock, flags);
}
-void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
+enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
+ struct scsi_cmnd *timedout_scmd)
{
+ enum scsi_timeout_action action = SCSI_EH_NOT_HANDLED;
+ struct ata_queued_cmd *qc;
struct ata_link *link;
+ u32 host_byte;
lockdep_assert_held(ap->lock);
/*
- * If we have a deferred qc when a reset occurs or NCQ commands fail,
- * do not try to be smart about what to do with this deferred command
- * and simply requeue it by completing it with DID_REQUEUE.
+ * If we have deferred QCs when a reset, a timeout or an NCQ command
+ * fails, do not try to be smart about what to do with the deferred
+ * commands and simply terminate them and let the SCSI layer decide
+ * what to do.
*/
ata_for_each_link(link, ap, PMP_FIRST) {
- struct ata_queued_cmd *qc = link->deferred_qc;
+ qc = link->deferred_qc;
+ if (!qc)
+ continue;
- if (qc) {
- link->deferred_qc = NULL;
- cancel_work(&link->deferred_qc_work);
- ata_scsi_qc_done(qc, true, DID_REQUEUE << 16);
+ /*
+ * Clear the deferred QC so that the deferred work does not try
+ * to issue it.
+ */
+ link->deferred_qc = NULL;
+ cancel_work(&link->deferred_qc_work);
+
+ /*
+ * We are going to complete some scsi command, either with
+ * DID_TIME_OUT if the command timed out while waiting for being
+ * issued, or with DID_REQUEUE if another command timed out or
+ * we had a failed command. However, the block layer may re-issue
+ * these commands immediately, keeping the scsi host busy and
+ * thus preventing the SCSI EH task from running.
+ * So schedule EH on the port to prevent accepting new commands
+ * until everything is sorted out with the error or timeout that
+ * got us here in the first place. Note that we set EH pending
+ * on the port before calling ata_port_schedule_eh() so that we
+ * do not reenter this function from ata_eh_set_pending() with
+ * timedout_scmd being NULL and erroneously retry deferred QCs
+ * that have timed out on other links.
+ */
+ if (!ata_port_eh_scheduled(ap)) {
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_port_schedule_eh(ap);
}
+
+ /*
+ * If we are being called from scsi_timeout(), then we have a
+ * non-NULL timedout_scmd. If the timed out command is for a
+ * deferred QC, terminate that deferred QC with DID_TIME_OUT and
+ * requeue all other deferred QCs. In this case we need to
+ * return SCSI_EH_DONE, because the timed out command was
+ * handled.
+ * If the timed out command is not for a deferred QC, we need to
+ * requeue all deferred QCs, and return SCSI_EH_NOT_HANDLED so
+ * that the timed out command gets added to the EH work queue
+ * with scsi_eh_scmd_add(), for later handling with libata EH
+ * ata_scsi_cmd_error_handler().
+ * If timedout_scmd is NULL, we simply need to requeue all
+ * deferred QCs and the return value does not matter as we were
+ * not called from scsi_timeout().
+ */
+ if (timedout_scmd && qc->scsicmd == timedout_scmd) {
+ host_byte = DID_TIME_OUT;
+ action = SCSI_EH_DONE;
+ } else {
+ host_byte = DID_REQUEUE;
+ }
+ ata_scsi_qc_done(qc, true, host_byte << 16);
}
+
+ return action;
}
static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
@@ -1723,13 +1777,42 @@ static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
return;
if (ata_port_eh_scheduled(ap)) {
- ata_scsi_requeue_deferred_qc(ap);
+ ata_scsi_requeue_deferred_qc(ap, NULL);
return;
}
if (!ap->ops->qc_defer(qc))
queue_work(system_highpri_wq, &link->deferred_qc_work);
}
+enum scsi_timeout_action ata_scsi_retry_deferred_qc(struct ata_port *ap,
+ struct scsi_cmnd *scmd)
+{
+ enum scsi_timeout_action action;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+ action = ata_scsi_requeue_deferred_qc(ap, scmd);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return action;
+}
+EXPORT_SYMBOL_GPL(ata_scsi_retry_deferred_qc);
+
+enum scsi_timeout_action ata_scsi_eh_timed_out(struct scsi_cmnd *scmd)
+{
+ struct ata_port *ap = ata_shost_to_port(scmd->device->host);
+
+ /*
+ * ata_scsi_cmd_error_handler() takes care of commands that timed out
+ * while executing. However, if we have deferred QCs while a timeout
+ * triggers, we must requeue these commands for retry so that we do not
+ * unnecessarily delay starting the SCSI EH task until these deferred
+ * commands also time out.
+ */
+ return ata_scsi_retry_deferred_qc(ap, scmd);
+}
+EXPORT_SYMBOL_GPL(ata_scsi_eh_timed_out);
+
static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_link *link = qc->dev->link;
@@ -2911,6 +2994,7 @@ static void atapi_fixup_inquiry(struct scsi_cmnd *cmd)
static void atapi_qc_complete(struct ata_queued_cmd *qc)
{
+ struct ata_link *link = qc->dev->link;
struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int err_mask = qc->err_mask;
@@ -2936,8 +3020,16 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;
- ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
- return;
+ if (cmd->result)
+ ata_scsi_qc_done(qc, false, 0);
+ else
+ ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
+ goto schedule_deferred;
+ }
+
+ if (cmd->result) {
+ ata_scsi_qc_done(qc, false, 0);
+ goto schedule_deferred;
}
/* successful completion path */
@@ -2945,6 +3037,9 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
atapi_fixup_inquiry(cmd);
ata_scsi_qc_done(qc, true, SAM_STAT_GOOD);
+
+schedule_deferred:
+ ata_scsi_schedule_deferred_qc(link);
}
/**
* atapi_xlat - Initialize PACKET taskfile
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 700627596ce1..8dacc1daabf0 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -180,7 +180,8 @@ enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
struct ata_port *ap)
__must_hold(ap->lock);
void ata_scsi_deferred_qc_work(struct work_struct *work);
-void ata_scsi_requeue_deferred_qc(struct ata_port *ap);
+enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
+ struct scsi_cmnd *scmd);
/* libata-eh.c */
extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 41647a56a9f4..365454390d7e 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -4027,7 +4027,7 @@ static int mv_platform_probe(struct platform_device *pdev)
/*
* Simple resource validation ..
*/
- if (unlikely(pdev->num_resources != 1)) {
+ if (unlikely(pdev->num_resources != 1 && pdev->num_resources != 2)) {
dev_err(&pdev->dev, "invalid number of resources\n");
return -EINVAL;
}
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 4ca6ec738c93..2a22f9dc1f2f 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -4765,6 +4765,15 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
ub->dev_info.dev_id = ub->ub_number;
/*
+ * ->state and ->ublksrv_pid are owned by the driver and only read back
+ * by userspace, but they come from the copied-in dev_info, so reset
+ * them. Otherwise a device added with ->state != DEAD looks live while
+ * ->ub_disk is still NULL.
+ */
+ ub->dev_info.state = UBLK_S_DEV_DEAD;
+ ub->dev_info.ublksrv_pid = -1;
+
+ /*
* 64bit flags will be copied back to userspace as feature
* negotiation result, so have to clear flags which driver
* doesn't support yet, then userspace can get correct flags
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 5e9cac090bd8..bf567b7c5f00 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -3771,6 +3771,9 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
struct intel_tlv *tlv = (void *)&skb->data[5];
+ if (skb->len < 5 + sizeof(*tlv) + sizeof(tlv->val[0]))
+ goto recv_frame;
+
/* The first event is always an event type TLV */
if (tlv->type != INTEL_TLV_TYPE_ID)
goto recv_frame;
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 02a96342e964..66b346761043 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -804,56 +804,44 @@ static int btmtk_usb_uhw_reg_write(struct hci_dev *hdev, u32 reg, u32 val)
static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
- int pipe, err;
- void *buf;
-
- buf = kzalloc(4, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ u8 buf[sizeof(u32)];
+ int err;
- pipe = usb_rcvctrlpipe(data->udev, 0);
- err = usb_control_msg(data->udev, pipe, 0x01,
- 0xDE,
- reg >> 16, reg & 0xffff,
- buf, 4, USB_CTRL_GET_TIMEOUT);
- if (err < 0) {
+ *val = 0;
+ err = usb_control_msg_recv(data->udev, 0, 0x01,
+ 0xDE,
+ reg >> 16, reg & 0xffff,
+ buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
+ if (err) {
bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
- goto err_free_buf;
+ return err;
}
*val = get_unaligned_le32(buf);
bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
-err_free_buf:
- kfree(buf);
-
- return err;
+ return 0;
}
static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
- int pipe, err, size = sizeof(u32);
- void *buf;
-
- buf = kzalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ u8 buf[sizeof(u32)];
+ int err;
- pipe = usb_rcvctrlpipe(data->udev, 0);
- err = usb_control_msg(data->udev, pipe, 0x63,
- USB_TYPE_VENDOR | USB_DIR_IN,
- reg >> 16, reg & 0xffff,
- buf, size, USB_CTRL_GET_TIMEOUT);
+ *val = 0;
+ err = usb_control_msg_recv(data->udev, 0, 0x63,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ reg >> 16, reg & 0xffff,
+ buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
if (err < 0)
- goto err_free_buf;
+ return err;
*val = get_unaligned_le32(buf);
-err_free_buf:
- kfree(buf);
-
- return err;
+ return 0;
}
static int btmtk_usb_id_get(struct hci_dev *hdev, u32 reg, u32 *id)
@@ -877,7 +865,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (dev_id == 0x7922) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
val |= 0x00002020;
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@@ -887,7 +875,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
val |= BIT(0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@@ -896,14 +884,14 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
msleep(100);
} else if (dev_id == 0x7925 || dev_id == 0x6639) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val |= (1 << 5);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val &= 0xFFFF00FF;
val |= (1 << 13);
@@ -914,7 +902,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val |= (1 << 0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
@@ -924,13 +912,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
- if (err < 0)
+ if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
- if (err < 0)
+ if (err)
return err;
msleep(100);
} else {
@@ -940,7 +928,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
- if (err < 0)
+ if (err)
return err;
/* Reset the bluetooth chip via USB interface. */
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
@@ -950,13 +938,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
- if (err < 0)
+ if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
- if (err < 0)
+ if (err)
return err;
/* MT7921 need to delay 20ms between toggle reset bit */
msleep(20);
@@ -964,7 +952,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
}
@@ -980,7 +968,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
}
err = btmtk_usb_id_get(hdev, 0x70010200, &val);
- if (err < 0 || (!val && dev_id != 0x6639))
+ if (err || (!val && dev_id != 0x6639))
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
return err;
@@ -1324,24 +1312,24 @@ int btmtk_usb_setup(struct hci_dev *hdev)
calltime = ktime_get();
err = btmtk_usb_id_get(hdev, 0x80000008, &dev_id);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
if (!dev_id || dev_id != 0x7663) {
err = btmtk_usb_id_get(hdev, 0x70010200, &dev_id);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x80021004, &fw_version);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x70010020, &fw_flavor);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
return err;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8f7ed469cac6..184e95c1625e 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3424,28 +3424,16 @@ static const char *qca_get_fw_subdirectory(const struct qca_version *ver)
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
void *data, u16 size)
{
- int pipe, err;
- u8 *buf;
-
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ int err;
/* Found some of USB hosts have IOT issues with ours so that we should
* not wait until HCI layer is ready.
*/
- pipe = usb_rcvctrlpipe(udev, 0);
- err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
- 0, 0, buf, size, USB_CTRL_GET_TIMEOUT);
- if (err < 0) {
+ err = usb_control_msg_recv(udev, 0, request, USB_TYPE_VENDOR | USB_DIR_IN,
+ 0, 0, data, size, USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
+ if (err)
dev_err(&udev->dev, "Failed to access otp area (%d)", err);
- goto done;
- }
-
- memcpy(data, buf, size);
-
-done:
- kfree(buf);
return err;
}
@@ -3652,7 +3640,7 @@ static bool btusb_qca_need_patch(struct usb_device *udev)
struct qca_version ver;
if (btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
- sizeof(ver)) < 0)
+ sizeof(ver)))
return false;
/* only low ROM versions need patches */
return !(le32_to_cpu(ver.rom_version) & ~0xffffU);
@@ -3670,7 +3658,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
- if (err < 0)
+ if (err)
return err;
ver_rom = le32_to_cpu(ver.rom_version);
@@ -3693,7 +3681,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_CHECK_STATUS, &status,
sizeof(status));
- if (err < 0)
+ if (err)
return err;
if (!(status & QCA_PATCH_UPDATED)) {
@@ -3704,7 +3692,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
- if (err < 0)
+ if (err)
return err;
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index a74a4cf99d22..3a6b4b224a66 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1031,7 +1031,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
return -EINVAL;
}
- if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq) {
+ if (lowest_nonlinear_freq < min_freq || lowest_nonlinear_freq > nominal_freq) {
pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n",
lowest_nonlinear_freq, min_freq, nominal_freq);
return -EINVAL;
@@ -2167,6 +2167,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
};
/*
+ * Processors without frequency scaling support can't do CPPC.
* CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F.
* show the debug message that helps to check if the CPU has CPPC support for loading issue.
*/
@@ -2175,6 +2176,11 @@ static bool amd_cppc_supported(void)
struct cpuinfo_x86 *c = &cpu_data(0);
bool warn = false;
+ if (!cpu_feature_enabled(X86_FEATURE_HW_PSTATE)) {
+ pr_debug_once("frequency scaling is not supported by the processor\n");
+ return false;
+ }
+
if ((boot_cpu_data.x86 == 0x17) && (boot_cpu_data.x86_model < 0x30)) {
pr_debug_once("CPPC feature is not supported by the processor\n");
return false;
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index f6cea0c54dd9..6fe0e972952a 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -290,19 +290,32 @@ static inline void cppc_freq_invariance_exit(void)
}
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
-static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
- struct cpufreq_policy *policy)
+static void cppc_cpufreq_get_perf_limits(struct cppc_cpudata *cpu_data,
+ struct cpufreq_policy *policy,
+ u32 *min_perf, u32 *max_perf)
{
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
- u32 min_perf, max_perf;
+ unsigned int min_freq, max_freq;
+ u32 min, max;
+
+ min_freq = READ_ONCE(policy->min);
+ max_freq = READ_ONCE(policy->max);
+ if (unlikely(min_freq > max_freq))
+ min_freq = max_freq;
+
+ min = cppc_khz_to_perf(caps, min_freq);
+ max = cppc_khz_to_perf(caps, max_freq);
- min_perf = cppc_khz_to_perf(caps, policy->min);
- max_perf = cppc_khz_to_perf(caps, policy->max);
+ *min_perf = clamp_t(u32, min, caps->lowest_perf, caps->highest_perf);
+ *max_perf = clamp_t(u32, max, caps->lowest_perf, caps->highest_perf);
+}
- cpu_data->perf_ctrls.min_perf =
- clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf);
- cpu_data->perf_ctrls.max_perf =
- clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf);
+static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
+ struct cpufreq_policy *policy)
+{
+ cppc_cpufreq_get_perf_limits(cpu_data, policy,
+ &cpu_data->perf_ctrls.min_perf,
+ &cpu_data->perf_ctrls.max_perf);
}
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -693,7 +706,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto out;
}
- policy->fast_switch_possible = cppc_allow_fast_switch();
+ policy->fast_switch_possible = cppc_allow_fast_switch(policy->cpus);
policy->dvfs_possible_from_any_cpu = true;
/*
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 2b791f1ec51b..909a3f0598a9 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1084,6 +1084,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
err_out_exit_acpi:
powernow_k8_cpu_exit_acpi(data);
+ kfree(data->powernow_table);
err_out:
kfree(data);
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 0f2e09311152..fd5caf1e19a8 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -118,14 +118,9 @@ err_bit:
return rc;
}
-static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
- struct dibs_lo_dmb_node *dmb_node)
+static void dibs_lo_free_dmb(struct dibs_lo_dev *ldev,
+ struct dibs_lo_dmb_node *dmb_node)
{
- /* remove dmb from hash table */
- write_lock_bh(&ldev->dmb_ht_lock);
- hash_del(&dmb_node->list);
- write_unlock_bh(&ldev->dmb_ht_lock);
-
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
folio_put(virt_to_folio(dmb_node->cpu_addr));
kfree(dmb_node);
@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
unsigned long flags;
+ bool last;
ldev = dibs->drv_priv;
/* find dmb from hash table */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
if (tmp_node->token == dmb->dmb_tok) {
dmb_node = tmp_node;
break;
}
}
- read_unlock_bh(&ldev->dmb_ht_lock);
- if (!dmb_node)
+ if (!dmb_node) {
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
+ }
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
- if (refcount_dec_and_test(&dmb_node->refcnt)) {
+ if (last) {
spin_lock_irqsave(&dibs->lock, flags);
dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
spin_unlock_irqrestore(&dibs->lock, flags);
- __dibs_lo_unregister_dmb(ldev, dmb_node);
+ dibs_lo_free_dmb(ldev, dmb_node);
}
return 0;
}
@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
+ refcount_inc(&dmb_node->refcnt);
read_unlock_bh(&ldev->dmb_ht_lock);
- if (!refcount_inc_not_zero(&dmb_node->refcnt))
- /* the dmb is being unregistered, but has
- * not been removed from the hash table.
- */
- return -EINVAL;
-
/* provide dmb information */
dmb->idx = dmb_node->sba_idx;
dmb->dmb_tok = dmb_node->token;
@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
{
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
+ bool last;
ldev = dibs->drv_priv;
/* find dmb_node according to dmb->dmb_tok */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
if (tmp_node->token == token) {
dmb_node = tmp_node;
@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
}
}
if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
- read_unlock_bh(&ldev->dmb_ht_lock);
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (last)
+ dibs_lo_free_dmb(ldev, dmb_node);
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __dibs_lo_unregister_dmb(ldev, dmb_node);
return 0;
}
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index 0366c7cf3502..82b07cf942ef 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -288,6 +288,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
fdev->parent = cdev_dev(idxd_cdev);
fdev->bus = &dsa_bus_type;
fdev->type = &idxd_cdev_file_type;
+ idxd_wq_get(wq);
rc = dev_set_name(fdev, "file%d", ctx->id);
if (rc < 0) {
@@ -301,13 +302,14 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
goto failed_dev_add;
}
- idxd_wq_get(wq);
mutex_unlock(&wq->wq_lock);
return 0;
failed_dev_add:
failed_dev_name:
+ mutex_unlock(&wq->wq_lock);
put_device(fdev);
+ return rc;
failed_ida:
failed_set_pasid:
if (device_user_pasid_enabled(idxd))
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index f1cfc7790d95..4b827a329756 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -159,18 +159,12 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)
static void idxd_clean_wqs(struct idxd_device *idxd)
{
- struct idxd_wq *wq;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_wqs; i++) {
- wq = idxd->wqs[i];
- if (idxd->hw.wq_cap.op_config)
- bitmap_free(wq->opcap_bmap);
- kfree(wq->wqcfg);
- conf_dev = wq_confdev(wq);
+ conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
- kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
@@ -212,7 +206,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(wq);
goto err_unwind;
}
@@ -227,7 +220,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
if (!wq->wqcfg) {
put_device(conf_dev);
- kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -235,9 +227,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
if (idxd->hw.wq_cap.op_config) {
wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
if (!wq->opcap_bmap) {
- kfree(wq->wqcfg);
put_device(conf_dev);
- kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -252,13 +242,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
err_unwind:
while (--i >= 0) {
- wq = idxd->wqs[i];
- if (idxd->hw.wq_cap.op_config)
- bitmap_free(wq->opcap_bmap);
- kfree(wq->wqcfg);
- conf_dev = wq_confdev(wq);
+ conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
- kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
@@ -270,15 +255,12 @@ err_free_wqs:
static void idxd_clean_engines(struct idxd_device *idxd)
{
- struct idxd_engine *engine;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_engines; i++) {
- engine = idxd->engines[i];
- conf_dev = engine_confdev(engine);
+ conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
- kfree(engine);
}
kfree(idxd->engines);
}
@@ -313,7 +295,6 @@ static int idxd_setup_engines(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(engine);
goto err;
}
@@ -324,10 +305,8 @@ static int idxd_setup_engines(struct idxd_device *idxd)
err:
while (--i >= 0) {
- engine = idxd->engines[i];
- conf_dev = engine_confdev(engine);
+ conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
- kfree(engine);
}
kfree(idxd->engines);
@@ -336,13 +315,10 @@ static int idxd_setup_engines(struct idxd_device *idxd)
static void idxd_clean_groups(struct idxd_device *idxd)
{
- struct idxd_group *group;
int i;
for (i = 0; i < idxd->max_groups; i++) {
- group = idxd->groups[i];
- put_device(group_confdev(group));
- kfree(group);
+ put_device(group_confdev(idxd->groups[i]));
}
kfree(idxd->groups);
}
@@ -377,7 +353,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(group);
goto err;
}
@@ -402,7 +377,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
while (--i >= 0) {
group = idxd->groups[i];
put_device(group_confdev(group));
- kfree(group);
}
kfree(idxd->groups);
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a9a254dbf8cb..f47a326dd7ff 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -945,16 +945,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
spin_lock_irqsave(&vchan->vc.lock, flags);
- if (vchan->cyclic) {
- vchan->cyclic = false;
- if (pchan && pchan->desc) {
- struct virt_dma_desc *vd = &pchan->desc->vd;
- struct virt_dma_chan *vc = &vchan->vc;
+ if (pchan && pchan->desc && pchan->desc != pchan->done) {
+ struct virt_dma_desc *vd = &pchan->desc->vd;
- list_add_tail(&vd->node, &vc->desc_completed);
- }
+ vchan_terminate_vdesc(vd);
}
+ vchan->cyclic = false;
vchan_get_all_descriptors(&vchan->vc, &head);
if (pchan) {
diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
index 3ef928640615..71d9868ce613 100644
--- a/drivers/dma/switchtec_dma.c
+++ b/drivers/dma/switchtec_dma.c
@@ -1099,7 +1099,7 @@ static int switchtec_dma_chan_init(struct switchtec_dma_dev *swdma_dev,
dev_dbg(&pdev->dev, "Channel %d: SE buffer count %d\n", i, se_buf_len);
thresh = se_buf_len / 2;
- valid_en_se |= FIELD_GET(SE_THRESH_MASK, thresh);
+ valid_en_se |= FIELD_PREP(SE_THRESH_MASK, thresh);
writel(valid_en_se, &swdma_chan->mmio_chan_fw->valid_en_se);
/* request irqs */
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 2e8690cb3c16..43d51d942ead 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -1142,6 +1142,33 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
return reg->priv;
}
+/**
+ * dpll_pin_own_dpll_ref_first - find the first owner dpll ref of a pin
+ * @pin: pointer to a dpll pin
+ *
+ * Search pin's dpll_refs for a ref whose dpll matches the pin's
+ * (module, clock_id) tuple, i.e. the dpll registered by the driver
+ * that created the pin. This ensures pin-level attributes are
+ * reported and modified using the owner's ops even when the pin is
+ * also registered with dplls from other drivers.
+ *
+ * Return: pointer to the owner's dpll_pin_ref, or NULL if no
+ * owner ref is found.
+ */
+struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin)
+{
+ struct dpll_pin_ref *ref;
+ unsigned long i;
+
+ xa_for_each(&pin->dpll_refs, i, ref) {
+ if (ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id)
+ return ref;
+ }
+
+ return NULL;
+}
+
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
{
struct dpll_pin_registration *reg;
diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h
index e24577113431..da8a369556ed 100644
--- a/drivers/dpll/dpll_core.h
+++ b/drivers/dpll/dpll_core.h
@@ -93,6 +93,7 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin);
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll);
struct dpll_device *dpll_device_get_by_id(int id);
+struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin);
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref);
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
extern struct xarray dpll_device_xa;
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 5703667593a7..afb31c004038 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -699,7 +699,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref;
int ret;
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref)
+ ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ASSERT_NOT_NULL(ref);
ret = dpll_msg_add_pin_handle(msg, pin);
@@ -1090,12 +1092,19 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->frequency_set || !ops->frequency_get) {
- NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
+ if ((!ops->frequency_set || !ops->frequency_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
+ NL_SET_ERR_MSG(extack,
+ "frequency set not supported by the device");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -1109,6 +1118,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->frequency_set)
+ continue;
dpll = ref->dpll;
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), freq, extack);
@@ -1128,6 +1139,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->frequency_set)
+ continue;
dpll = ref->dpll;
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_freq, extack))
@@ -1151,13 +1164,19 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->esync_set || !ops->esync_get) {
+ if ((!ops->esync_set || !ops->esync_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack,
"embedded sync feature is not supported by this device");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -1181,6 +1200,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
void *pin_dpll_priv;
ops = dpll_pin_ops(ref);
+ if (!ops->esync_set)
+ continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@@ -1204,6 +1225,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->esync_set)
+ continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@@ -1238,8 +1261,11 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
NL_SET_ERR_MSG(extack, "reference sync pin not available");
return -EINVAL;
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
- ASSERT_NOT_NULL(ref);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set || !ops->ref_sync_get) {
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
@@ -1258,6 +1284,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->ref_sync_set)
+ continue;
dpll = ref->dpll;
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@@ -1280,6 +1308,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->ref_sync_set)
+ continue;
dpll = ref->dpll;
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@@ -1471,12 +1501,18 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
+ if ((!ops->phase_adjust_set || !ops->phase_adjust_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack, "phase adjust not supported");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1491,6 +1527,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->phase_adjust_set)
+ continue;
dpll = ref->dpll;
ret = ops->phase_adjust_set(pin,
dpll_pin_on_dpll_priv(dpll, pin),
@@ -1513,6 +1551,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->phase_adjust_set)
+ continue;
dpll = ref->dpll;
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_phase_adj,
diff --git a/drivers/gpio/gpio-by-pinctrl.c b/drivers/gpio/gpio-by-pinctrl.c
index 7d7c48ce5163..fb8440acb31d 100644
--- a/drivers/gpio/gpio-by-pinctrl.c
+++ b/drivers/gpio/gpio-by-pinctrl.c
@@ -27,12 +27,6 @@ static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int off
return GPIO_LINE_DIRECTION_IN;
}
-static int pin_control_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int val)
-{
- return pinctrl_gpio_direction_output(chip, offset);
-}
-
static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
unsigned long config;
@@ -55,6 +49,18 @@ static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset,
return pinctrl_gpio_set_config(chip, offset, config);
}
+static int pin_control_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int val)
+{
+ int ret;
+
+ ret = pinctrl_gpio_direction_output(chip, offset);
+ if (ret)
+ return ret;
+
+ return pin_control_gpio_set(chip, offset, val);
+}
+
static int pin_control_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index f6b870b7b352..aac9ea7520b6 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -604,20 +604,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
return 0;
}
-static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc,
+ unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = pca953x_get_bit_mask(chip, off);
- guard(mutex)(&chip->i2c_lock);
-
if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE)
return regmap_update_bits(chip->regmap, dirreg, bit, 0);
return regmap_update_bits(chip->regmap, dirreg, bit, bit);
}
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
+{
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
+
+ guard(mutex)(&chip->i2c_lock);
+
+ return pca953x_gpio_direction_input_unlocked(gc, off);
+}
+
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
@@ -855,9 +863,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
DECLARE_BITMAP(reg_direction, MAX_LINE);
int level;
+ guard(mutex)(&chip->i2c_lock);
+
if (chip->driver_data & PCA_PCAL) {
DECLARE_BITMAP(latched_inputs, MAX_LINE);
- guard(mutex)(&chip->i2c_lock);
/* Enable latch on edge-triggered interrupt-enabled inputs */
bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
@@ -879,7 +888,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Look for any newly setup interrupt */
for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
- pca953x_gpio_direction_input(&chip->gpio_chip, level);
+ pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
}
@@ -1369,9 +1378,20 @@ static int pca953x_restore_context(struct pca953x_chip *chip)
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(chip);
if (ret)
- return ret;
+ goto err;
+
+ ret = regcache_sync(chip->regmap);
+ if (ret)
+ goto err;
+
+ return 0;
- return regcache_sync(chip->regmap);
+err:
+ if (chip->client->irq > 0)
+ disable_irq(chip->client->irq);
+ regcache_cache_only(chip->regmap, true);
+
+ return ret;
}
static void pca953x_save_context(struct pca953x_chip *chip)
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 4ffa0955a9e3..07a5617b314b 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -96,7 +96,7 @@ struct pch_gpio {
struct pch_gpio_reg_data pch_gpio_reg;
int irq_base;
enum pch_type_t ioh;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
};
static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
@@ -105,7 +105,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
struct pch_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
reg_val = ioread32(&chip->reg->po);
if (val)
reg_val |= BIT(nr);
@@ -113,7 +113,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -133,7 +133,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
u32 reg_val;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
reg_val = ioread32(&chip->reg->po);
if (val)
@@ -147,7 +147,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
pm |= BIT(nr);
iowrite32(pm, &chip->reg->pm);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -158,12 +158,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
u32 pm;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
pm = ioread32(&chip->reg->pm);
pm &= BIT(gpio_pins[chip->ioh]) - 1;
pm &= ~BIT(nr);
iowrite32(pm, &chip->reg->pm);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -265,7 +265,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
return 0;
}
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
/* Set interrupt mode */
im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
@@ -277,7 +277,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
else if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -374,7 +374,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
chip->ioh = id->driver_data;
chip->reg = chip->base;
pci_set_drvdata(pdev, chip);
- spin_lock_init(&chip->spinlock);
+ raw_spin_lock_init(&chip->spinlock);
pch_gpio_setup(chip);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
@@ -407,9 +407,9 @@ static int pch_gpio_suspend(struct device *dev)
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
pch_gpio_save_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -419,11 +419,11 @@ static int pch_gpio_resume(struct device *dev)
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
iowrite32(0x01, &chip->reg->reset);
iowrite32(0x00, &chip->reg->reset);
pch_gpio_restore_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c
index 2bbd308ca08e..aa23b5779802 100644
--- a/drivers/gpio/gpio-sloppy-logic-analyzer.c
+++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c
@@ -160,6 +160,13 @@ static int fops_buf_size_get(void *data, u64 *val)
return 0;
}
+static void fops_buf_release(void *data)
+{
+ struct gpio_la_poll_priv *priv = data;
+
+ vfree(priv->blob.data);
+}
+
static int fops_buf_size_set(void *data, u64 val)
{
struct gpio_la_poll_priv *priv = data;
@@ -238,6 +245,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
return ret;
fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);
+ ret = devm_add_action_or_reset(dev, fops_buf_release, priv);
+ if (ret)
+ return ret;
priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN);
if (IS_ERR(priv->descs))
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e5fb60111151..c433a095907f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -999,14 +999,17 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode)
if (ret < 0)
return ret;
- if (fwnode_property_present(fwnode, "input"))
+ if (fwnode_property_present(fwnode, "input")) {
dflags |= GPIOD_IN;
- else if (fwnode_property_present(fwnode, "output-low"))
+ } else if (fwnode_property_present(fwnode, "output-low")) {
dflags |= GPIOD_OUT_LOW;
- else if (fwnode_property_present(fwnode, "output-high"))
+ } else if (fwnode_property_present(fwnode, "output-high")) {
dflags |= GPIOD_OUT_HIGH;
- else
- return -EINVAL;
+ } else {
+ gpiochip_warn(gc, "%pfwP: no hogging state specified, bailing out\n",
+ fwnode);
+ return 0;
+ }
fwnode_property_read_string(fwnode, "line-name", &name);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
index 6a364357522b..b0299d861903 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
@@ -92,7 +92,7 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f)
return NULL;
fence = container_of(f, struct amdgpu_amdkfd_fence, base);
- if (f->ops == &amdkfd_fence_ops)
+ if (rcu_access_pointer(f->ops) == &amdkfd_fence_ops)
return fence;
return NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 35fe2c974699..f0f516a79424 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -3096,7 +3096,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
process_info->eviction_fence = new_fence;
replace_eviction_fence(ef, dma_fence_get(&new_fence->base));
} else {
- WARN_ONCE(*ef != &process_info->eviction_fence->base,
+ WARN_ONCE(rcu_access_pointer(*ef) != &process_info->eviction_fence->base,
"KFD eviction fence doesn't match KGD process_info");
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index e714cee2997a..5445f75741b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -1177,19 +1177,6 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.bo);
}
- if (adev->debug_vm) {
- /* Invalidate all BOs to test for userspace bugs */
- amdgpu_bo_list_for_each_entry(e, p->bo_list) {
- struct amdgpu_bo *bo = e->bo;
-
- /* ignore duplicates */
- if (!bo)
- continue;
-
- amdgpu_vm_bo_invalidate(bo, false);
- }
- }
-
return 0;
}
@@ -1378,6 +1365,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
/* Cleanup the parser structure */
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser)
{
+ struct amdgpu_device *adev = parser->adev;
+ struct amdgpu_bo_list_entry *e;
unsigned int i;
amdgpu_sync_free(&parser->sync);
@@ -1393,8 +1382,21 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser)
if (parser->ctx)
amdgpu_ctx_put(parser->ctx);
- if (parser->bo_list)
+ if (parser->bo_list) {
+ if (adev->debug_vm) {
+ /* Invalidate all BOs to test for userspace bugs */
+ amdgpu_bo_list_for_each_entry(e, parser->bo_list) {
+ struct amdgpu_bo *bo = e->bo;
+
+ /* ignore duplicates */
+ if (!bo)
+ continue;
+
+ amdgpu_vm_bo_invalidate(bo, false);
+ }
+ }
amdgpu_bo_list_put(parser->bo_list);
+ }
for (i = 0; i < parser->nchunks; i++)
kvfree(parser->chunks[i].kdata);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index 389bad724273..df2588642817 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -43,6 +43,11 @@
#if defined(CONFIG_DEBUG_FS)
+/* Encode milliwatts in the raw Q24.8 sensor report format used by UMR. */
+#define AMDGPU_DEBUGFS_PWR_MW_TO_Q24_8(power_mw) \
+ DIV_ROUND_CLOSEST_ULL((u64)(power_mw) * BIT(8), \
+ MILLIWATT_PER_WATT)
+
/**
* amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes
*
@@ -1104,6 +1109,10 @@ static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
return r;
}
+ if (idx == AMDGPU_PP_SENSOR_GPU_AVG_POWER ||
+ idx == AMDGPU_PP_SENSOR_GPU_INPUT_POWER)
+ values[0] = AMDGPU_DEBUGFS_PWR_MW_TO_Q24_8(values[0]);
+
if (size > valuesize) {
amdgpu_virt_disable_access_debugfs(adev);
return -EINVAL;
@@ -1319,8 +1328,8 @@ err:
* @size: Number of bytes to read
* @pos: Offset to seek to
*
- * Read the last residency value logged. It doesn't auto update, one needs to
- * stop logging before getting the current value.
+ * Read a live GFXOFF residency sample from firmware. One needs to start logging
+ * before getting the current value.
*/
static ssize_t amdgpu_debugfs_gfxoff_residency_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 2860f12915c0..5e83edbd313b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2304,6 +2304,7 @@ static int amdgpu_discovery_set_psp_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &psp_v14_0_ip_block);
break;
case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 9):
amdgpu_device_ip_block_add(adev, &psp_v15_0_ip_block);
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 4c0c77eafbd1..1aed121f4ddb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2908,6 +2908,19 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
return 0;
}
+static void amdgpu_restore_umd_profile_pstate_after_runpm(struct amdgpu_device *adev)
+{
+ enum amd_dpm_forced_level level;
+ uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
+ AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
+
+ level = amdgpu_dpm_get_performance_level(adev);
+ if (level & profile_mode_mask)
+ amdgpu_asic_update_umd_stable_pstate(adev, true);
+}
+
static int amdgpu_pmops_runtime_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2952,6 +2965,8 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+
+ amdgpu_restore_umd_profile_pstate_after_runpm(adev);
adev->in_runpm = false;
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 71272f40feef..8bb9c198ddec 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1210,7 +1210,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return -EINVAL;
}
}
- ui32 >>= 8;
+ ui32 /= MILLIWATT_PER_WATT;
break;
case AMDGPU_INFO_SENSOR_GPU_INPUT_POWER:
/* get input GPU power */
@@ -1219,7 +1219,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
(void *)&ui32, &ui32_size)) {
return -EINVAL;
}
- ui32 >>= 8;
+ ui32 /= MILLIWATT_PER_WATT;
break;
case AMDGPU_INFO_SENSOR_VDDNB:
/* get VDDNB in millivolts */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index e0c0d7872e45..7139cb3b2db5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -275,6 +275,7 @@ static int psp_early_init(struct amdgpu_ip_block *ip_block)
psp->boot_time_tmr = false;
break;
case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 9):
psp_v15_0_0_set_psp_funcs(psp);
psp->boot_time_tmr = false;
@@ -1222,6 +1223,33 @@ int psp_memory_partition(struct psp_context *psp, int mode)
return ret;
}
+int psp_set_mmhub_eco_sec_level(struct amdgpu_device *adev)
+{
+ int ret;
+ struct psp_context *psp = &adev->psp;
+ struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
+
+ cmd->cmd_id = GFX_CMD_ID_SET_MMHUB_ECO_SEC_LEVEL;
+
+ ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+ if (ret) {
+ dev_err(psp->adev->dev,
+ "PSP request failed to set mmuhub eco sec level with ret=%d\n", ret);
+ release_psp_cmd_buf(psp);
+ return ret;
+ }
+
+ if (cmd->resp.status) {
+ dev_err(psp->adev->dev,
+ "MMHUB ECO SEC LEVEL command 0x%x failed, PSP response status: 0x%X\n",
+ cmd->cmd_id, cmd->resp.status);
+ ret = -EIO;
+ }
+ release_psp_cmd_buf(psp);
+
+ return ret;
+}
+
static int psp_ptl_fmt_verify(struct psp_context *psp, enum amdgpu_ptl_fmt fmt,
uint32_t *ptl_fmt)
{
@@ -3476,8 +3504,10 @@ static int psp_load_non_psp_fw(struct psp_context *psp)
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 0) ||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
- IP_VERSION(15, 0, 8) ||
+ IP_VERSION(15, 0, 5) ||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
+ IP_VERSION(15, 0, 8) ||
+ amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 9)) &&
(ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 ||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 2d838b1b2b11..3d7744d60fac 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -656,5 +656,6 @@ int amdgpu_psp_reg_program_no_ring(struct psp_context *psp, uint32_t val,
void amdgpu_psp_debugfs_init(struct amdgpu_device *adev);
int amdgpu_psp_get_fw_type(struct amdgpu_firmware_info *ucode,
enum psp_gfx_fw_type *type);
+int psp_set_mmhub_eco_sec_level(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index eb8bbfc7e6d9..5fc91f45db5b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -2173,6 +2173,18 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
gtt_size = configured_size;
}
+ /* Cap GTT so that it does not exceed total physical RAM. */
+ if (adev->flags & AMD_IS_APU) {
+ u64 phys_ram = (u64)totalram_pages() << PAGE_SHIFT;
+
+ if (gtt_size > phys_ram) {
+ gtt_size = phys_ram;
+ dev_info(adev->dev,
+ "Capping GTT to %uM to not exceed available system memory\n",
+ (unsigned int)(gtt_size / (1024 * 1024)));
+ }
+ }
+
/* Initialize GTT memory pool */
r = amdgpu_gtt_mgr_init(adev, gtt_size);
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 572f2949cb64..3efe1ae27386 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -965,6 +965,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
struct amdgpu_vm *vm = &fpriv->vm;
unsigned long key, tmp_key;
struct amdgpu_bo_va *bo_va;
+ struct amdgpu_usermode_queue *queue;
struct amdgpu_bo *bo;
struct drm_exec exec;
struct xarray xa;
@@ -1080,6 +1081,24 @@ retry_lock:
dma_fence_wait(bo_va->last_pt_update, false);
dma_fence_wait(vm->last_update, false);
+ xa_for_each(&uq_mgr->userq_xa, tmp_key, queue) {
+ bo = queue->wptr_obj.obj;
+ if (!bo) {
+ ret = -EINVAL;
+ goto unlock_all;
+ }
+
+ ret = amdgpu_ttm_alloc_gart(&bo->tbo);
+ if (unlikely(ret)) {
+ drm_file_err(uq_mgr->file,
+ "failed to bind wptr bo to gart on resume, qid=%lu ret=%d\n",
+ tmp_key, ret);
+ goto unlock_all;
+ }
+
+ queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(bo);
+ }
+
ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
if (ret)
drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index f224d33c4bc4..dc6a9d7dd0b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1553,6 +1553,8 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
struct amdgpu_sync sync;
int r;
+ if (list_empty(&vm->freed))
+ return 0;
/*
* Implicitly sync to command submissions in the same VM before
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
index d80f01c0e754..b02561f41b58 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
@@ -379,7 +379,7 @@ struct amd_sriov_msg_vf2pf_info {
struct {
uint8_t id;
uint32_t version;
- } ucode_info[AMD_SRIOV_MSG_RESERVE_UCODE];
+ } __packed ucode_info[AMD_SRIOV_MSG_RESERVE_UCODE];
uint64_t dummy_page_addr;
/* FB allocated for guest MES to record UQ info */
uint64_t mes_info_addr;
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
index e7546816baba..2c3e6d9f52a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c
@@ -399,6 +399,25 @@ static void jpeg_v5_3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
}
/**
+ * jpeg_v5_3_0_set_mmhub_eco_sec_level - set jpeg sec lvl reg
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * request psp to set secure lvl
+ */
+static int jpeg_v5_3_0_set_mmhub_eco_sec_level(struct amdgpu_device *adev)
+{
+ int r = 0;
+
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+ /* Request to PSP to program JPEG secure lvl */
+ r = psp_set_mmhub_eco_sec_level(adev);
+ }
+
+ return r;
+}
+
+/**
* jpeg_v5_3_0_start - start JPEG block
*
* @adev: amdgpu_device pointer
@@ -423,6 +442,11 @@ static int jpeg_v5_3_0_start(struct amdgpu_device *adev)
if (r)
return r;
+ /* program JPEG secure lvl register */
+ r = jpeg_v5_3_0_set_mmhub_eco_sec_level(adev);
+ if (r)
+ return r;
+
/* JPEG disable CGC */
jpeg_v5_3_0_disable_clock_gating(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 16625c31bfd3..4e44a581a78a 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -70,27 +70,23 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
ret = -EINVAL;
goto fail_map;
}
-
- /* TODO use eviction fence instead of pinning. */
- ret = amdgpu_bo_pin(wptr_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
+ /* Keep WPTR BO under eviction-fence control instead of pinning. */
+ ret = amdgpu_evf_mgr_attach_fence(&uq_mgr_to_fpriv(uq_mgr)->evf_mgr, wptr_obj->obj);
if (ret) {
- DRM_ERROR("Failed to pin wptr bo. ret %d\n", ret);
+ DRM_ERROR("Failed to attach eviction fence to wptr bo. ret %d\n", ret);
goto fail_map;
}
ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
if (ret) {
- DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
- goto fail_alloc_gart;
+ DRM_ERROR("Failed to bind wptr bo to GART. ret %d\n", ret);
+ goto fail_map;
}
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
drm_exec_fini(&exec);
return 0;
-
-fail_alloc_gart:
- amdgpu_bo_unpin(wptr_obj->obj);
fail_map:
amdgpu_bo_unref(&wptr_obj->obj);
fail_lock:
@@ -468,9 +464,6 @@ static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
&queue->mqd.cpu_ptr);
- amdgpu_bo_reserve(queue->wptr_obj.obj, true);
- amdgpu_bo_unpin(queue->wptr_obj.obj);
- amdgpu_bo_unreserve(queue->wptr_obj.obj);
amdgpu_bo_unref(&queue->wptr_obj.obj);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
index c78f0598637f..000516b5845a 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
@@ -30,70 +30,76 @@
#include "ivsrcid/nbio/irqsrcs_nbif_7_4.h"
#include <uapi/linux/kfd_ioctl.h>
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL_nbif_4_10 0x4f0aeb
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL1_nbif_4_10 0x4f0aec
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL1_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10 0x4f0aed
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1_nbif_4_10 0x4f0aee
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10 0x4f0aef
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1_nbif_4_10 0x4f0af0
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL_nbif_4_10 0x4f0af1
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL1_nbif_4_10 0x4f0af2
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL1_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10 0x4f0af3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL1_nbif_4_10 0x4f0af4
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL1_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10 0x4f0af5
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10_BASE_IDX 3
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10 0x4f0af6
-#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10_BASE_IDX 3
-#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10 0x0021
-#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10_BASE_IDX 2
-
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5 0x8e13
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5_BASE_IDX 5
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5 0x8e14
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5_BASE_IDX 5
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5 0x8e15
-#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5_BASE_IDX 5
-
-#define regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5 0x8e4d
-#define regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
-#define regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5 0x8e4e
-#define regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
-
-#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5 0xd000
-#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5_BASE_IDX 5
-
-#define regBIF_BX0_BIF_FB_EN_nbio_7_11_5 0x8e20
-#define regBIF_BX0_BIF_FB_EN_nbio_7_11_5_BASE_IDX 5
-
-#define regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5 0x8e11
-#define regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5_BASE_IDX 5
-#define regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5 0x8e12
-#define regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5_BASE_IDX 5
-
-#define regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5 0x8e26
-#define regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5_BASE_IDX 5
-#define regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5 0x8e27
-#define regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5_BASE_IDX 5
-
-#define regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5 0x8e17
-#define regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL_nbif_4_10 0x4f0aeb
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL1_nbif_4_10 0x4f0aec
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL1_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10 0x4f0aed
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1_nbif_4_10 0x4f0aee
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10 0x4f0aef
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1_nbif_4_10 0x4f0af0
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL_nbif_4_10 0x4f0af1
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL1_nbif_4_10 0x4f0af2
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL1_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10 0x4f0af3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL1_nbif_4_10 0x4f0af4
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL1_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10 0x4f0af5
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10_BASE_IDX 3
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10 0x4f0af6
+#define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10_BASE_IDX 3
+#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10 0x0021
+#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10_BASE_IDX 2
+
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5 0x8e13
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5_BASE_IDX 5
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5 0x8e14
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5_BASE_IDX 5
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5 0x8e15
+#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5_BASE_IDX 5
+
+#define regBIF_BX1_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5 0x012d
+#define regBIF_BX1_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 2
+#define regBIF_BX1_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5 0x012e
+#define regBIF_BX1_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 2
+
+#define regRCC_STRAP1_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5 0x0021
+#define regRCC_STRAP1_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5_BASE_IDX 2
+
+#define regBIF_BX1_BIF_FB_EN_nbio_7_11_5 0x0100
+#define regBIF_BX1_BIF_FB_EN_nbio_7_11_5_BASE_IDX 2
+
+#define regBIF_BX1_INTERRUPT_CNTL_nbio_7_11_5 0x00f1
+#define regBIF_BX1_INTERRUPT_CNTL_nbio_7_11_5_BASE_IDX 2
+#define regBIF_BX1_INTERRUPT_CNTL2_nbio_7_11_5 0x00f2
+#define regBIF_BX1_INTERRUPT_CNTL2_nbio_7_11_5_BASE_IDX 2
+
+#define regBIF_BX_PF1_GPU_HDP_FLUSH_REQ_nbio_7_11_5 0x0106
+#define regBIF_BX_PF1_GPU_HDP_FLUSH_REQ_nbio_7_11_5_BASE_IDX 2
+#define regBIF_BX_PF1_GPU_HDP_FLUSH_DONE_nbio_7_11_5 0x0107
+#define regBIF_BX_PF1_GPU_HDP_FLUSH_DONE_nbio_7_11_5_BASE_IDX 2
+
+#define regBIF_BX_PF1_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5 0x00f7
+#define regBIF_BX_PF1_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 2
+
+//BIF_BX1_BIF_FB_EN
+#define BIF_BX1_BIF_FB_EN__FB_READ_EN__SHIFT_nbio_7_11_5 0x0
+#define BIF_BX1_BIF_FB_EN__FB_WRITE_EN__SHIFT_nbio_7_11_5 0x1
+#define BIF_BX1_BIF_FB_EN__FB_READ_EN_MASK_nbio_7_11_5 0x00000001L
+#define BIF_BX1_BIF_FB_EN__FB_WRITE_EN_MASK_nbio_7_11_5 0x00000002L
static void nbif_v6_3_1_remap_hdp_registers(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5)) {
- WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5,
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
- WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5,
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
} else {
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL,
@@ -110,7 +116,7 @@ static u32 nbif_v6_3_1_get_rev_id(struct amdgpu_device *adev)
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4))
tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10);
else if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
- tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5);
+ tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP1_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5);
else
tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0);
@@ -124,11 +130,11 @@ static void nbif_v6_3_1_mc_access_enable(struct amdgpu_device *adev, bool enable
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5)) {
if (enable)
- WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN_nbio_7_11_5,
- BIF_BX0_BIF_FB_EN__FB_READ_EN_MASK |
- BIF_BX0_BIF_FB_EN__FB_WRITE_EN_MASK);
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_BIF_FB_EN_nbio_7_11_5,
+ BIF_BX1_BIF_FB_EN__FB_READ_EN_MASK_nbio_7_11_5 |
+ BIF_BX1_BIF_FB_EN__FB_WRITE_EN_MASK_nbio_7_11_5);
else
- WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN_nbio_7_11_5, 0);
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_BIF_FB_EN_nbio_7_11_5, 0);
} else {
if (enable)
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN,
@@ -383,12 +389,12 @@ static void nbif_v6_3_1_ih_control(struct amdgpu_device *adev)
/* setup interrupt control */
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
- WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5,
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_INTERRUPT_CNTL2_nbio_7_11_5,
adev->dummy_page_addr >> 8);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
- interrupt_cntl = RREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5);
+ interrupt_cntl = RREG32_SOC15(NBIO, 0, regBIF_BX1_INTERRUPT_CNTL_nbio_7_11_5);
/*
* BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
* BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
@@ -401,7 +407,7 @@ static void nbif_v6_3_1_ih_control(struct amdgpu_device *adev)
IH_REQ_NONSNOOP_EN, 0);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
- WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5, interrupt_cntl);
+ WREG32_SOC15(NBIO, 0, regBIF_BX1_INTERRUPT_CNTL_nbio_7_11_5, interrupt_cntl);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL, interrupt_cntl);
}
@@ -427,7 +433,7 @@ nbif_v6_3_1_get_clockgating_state(struct amdgpu_device *adev,
static u32 nbif_v6_3_1_get_hdp_flush_req_offset(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
- return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5);
+ return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF1_GPU_HDP_FLUSH_REQ_nbio_7_11_5);
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_REQ);
}
@@ -435,7 +441,7 @@ static u32 nbif_v6_3_1_get_hdp_flush_req_offset(struct amdgpu_device *adev)
static u32 nbif_v6_3_1_get_hdp_flush_done_offset(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
- return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5);
+ return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF1_GPU_HDP_FLUSH_DONE_nbio_7_11_5);
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_DONE);
}
@@ -622,7 +628,7 @@ static void nbif_v6_3_1_set_reg_remap(struct amdgpu_device *adev)
} else {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0,
- regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5) << 2;
+ regBIF_BX_PF1_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5) << 2;
else
adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0,
regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL) << 2;
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
index ac34bac3c839..ad618b78685f 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
+++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
@@ -110,6 +110,7 @@ enum psp_gfx_cmd_id
GFX_CMD_ID_PERF_HW = 0x0000004C, /* performance monitor */
GFX_CMD_ID_FB_FW_RESERV_ADDR = 0x00000050, /* Query FW reservation addr */
GFX_CMD_ID_FB_FW_RESERV_EXT_ADDR = 0x00000051, /* Query FW reservation extended addr */
+ GFX_CMD_ID_SET_MMHUB_ECO_SEC_LEVEL = 0x0000005D, /* Set MMHUB ECO sec lvls on VCN block */
};
/* PSP boot config sub-commands */
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
index 2a4d91368ac6..abaa40b6def9 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
@@ -33,9 +33,22 @@
MODULE_FIRMWARE("amdgpu/psp_15_0_0_toc.bin");
MODULE_FIRMWARE("amdgpu/psp_15_0_0_ta.bin");
+MODULE_FIRMWARE("amdgpu/psp_15_0_5_toc.bin");
+MODULE_FIRMWARE("amdgpu/psp_15_0_5_ta.bin");
MODULE_FIRMWARE("amdgpu/psp_15_0_9_toc.bin");
MODULE_FIRMWARE("amdgpu/psp_15_0_9_ta.bin");
+#define regMPASP_PCRU0_MPASP_C2PMSG_64 0x4280
+#define regMPASP_PCRU0_MPASP_C2PMSG_64_BASE_IDX 2
+#define regMPASP_PCRU0_MPASP_C2PMSG_67 0x4283
+#define regMPASP_PCRU0_MPASP_C2PMSG_67_BASE_IDX 2
+#define regMPASP_PCRU0_MPASP_C2PMSG_69 0x4285
+#define regMPASP_PCRU0_MPASP_C2PMSG_69_BASE_IDX 2
+#define regMPASP_PCRU0_MPASP_C2PMSG_70 0x4286
+#define regMPASP_PCRU0_MPASP_C2PMSG_70_BASE_IDX 2
+#define regMPASP_PCRU0_MPASP_C2PMSG_71 0x4287
+#define regMPASP_PCRU0_MPASP_C2PMSG_71_BASE_IDX 2
+
static int psp_v15_0_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -71,14 +84,25 @@ static int psp_v15_0_0_ring_stop(struct psp_context *psp,
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_101),
0x80000000, 0x80000000, false);
} else {
- /* Write the ring destroy command*/
- 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_PCRU1_MPASP_C2PMSG_64),
- 0x80000000, 0x80000000, false);
+ if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(15, 0, 5)) {
+ /* Write the ring destroy command*/
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU0_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_PCRU0_MPASP_C2PMSG_64),
+ 0x80000000, 0x80000000, false);
+ } else {
+ /* Write the ring destroy command*/
+ 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_PCRU1_MPASP_C2PMSG_64),
+ 0x80000000, 0x80000000, false);
+ }
}
return ret;
@@ -118,9 +142,10 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
0x80000000, 0x8000FFFF, false);
} else {
- /* Wait for sOS ready for ring creation */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
- 0x80000000, 0x80000000, false);
+ if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(15, 0, 5)) {
+ /* Wait for sOS ready for ring creation */
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU0_MPASP_C2PMSG_64),
+ 0x80000000, 0x80000000, false);
if (ret) {
DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
return ret;
@@ -128,6 +153,35 @@ 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_PCRU0_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_PCRU0_MPASP_C2PMSG_70, psp_ring_reg);
+ /* Write size of ring to C2PMSG_71 */
+ psp_ring_reg = ring->ring_size;
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU0_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_PCRU0_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_PCRU0_MPASP_C2PMSG_64),
+ 0x80000000, 0x8000FFFF, false);
+ } else {
+ /* Wait for sOS ready for ring creation */
+ 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");
+ return ret;
+ }
+
+ /* 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_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);
@@ -146,6 +200,7 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
/* Wait for response flag (bit 31) in C2PMSG_64 */
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x8000FFFF, false);
+ }
}
return ret;
@@ -176,8 +231,12 @@ 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_PCRU1_MPASP_C2PMSG_67);
+ else {
+ if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(15, 0, 5))
+ data = RREG32_SOC15(MP0, 0, regMPASP_PCRU0_MPASP_C2PMSG_67);
+ else
+ data = RREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67);
+ }
return data;
}
@@ -190,8 +249,12 @@ static void psp_v15_0_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_102, value);
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_101,
GFX_CTRL_CMD_ID_CONSUME_CMD);
- } else
- WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67, value);
+ } else {
+ if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(15, 0, 5))
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU0_MPASP_C2PMSG_67, value);
+ else
+ 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 e0b80abcd075..e9d51e992a8c 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -406,6 +406,7 @@ soc21_asic_reset_method(struct amdgpu_device *adev)
case IP_VERSION(14, 0, 4):
case IP_VERSION(14, 0, 5):
case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 9):
return AMD_RESET_METHOD_MODE2;
default:
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 45580e9c4e0c..886e2c2074a9 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -796,6 +796,27 @@ static int vcn_v5_0_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst,
}
/**
+ * vcn_v5_0_0_set_mmhub_eco_sec_level - set vcn sec lvl reg
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * request psp to set sec lvl
+ */
+static int vcn_v5_0_0_set_mmhub_eco_sec_level(struct amdgpu_device *adev)
+{
+ int r = 0;
+
+ if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(5, 3, 0)) {
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+ /* Request to PSP to program VCN secure lvl */
+ r = psp_set_mmhub_eco_sec_level(adev);
+ }
+ }
+
+ return r;
+}
+
+/**
* vcn_v5_0_0_start - VCN start
*
* @vinst: VCN instance
@@ -819,6 +840,11 @@ static int vcn_v5_0_0_start(struct amdgpu_vcn_inst *vinst)
fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+ /* program VCN secure lvl register */
+ r = vcn_v5_0_0_set_mmhub_eco_sec_level(adev);
+ if (r)
+ return r;
+
if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
return vcn_v5_0_0_start_dpg_mode(vinst, adev->vcn.inst[i].indirect_sram);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index c7edebd2fd8a..e1689b3d2add 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -3109,10 +3109,14 @@ static int kfd_ioctl_set_debug_trap(struct file *filep, struct kfd_process *p, v
goto out;
}
- /* Check if target is still PTRACED. */
+ /*
+ * Verify debugger has permission to debug target process.
+ * For cross-process debugging, require active ptrace relationship.
+ * This applies to ALL operations to prevent unauthorized interference.
+ */
rcu_read_lock();
- if (target != p && args->op != KFD_IOC_DBG_TRAP_DISABLE
- && ptrace_parent(target->lead_thread) != current) {
+ if (target != p && ptrace_parent(target->lead_thread) != current
+ && target->debugger_process != p) {
pr_err("PID %i is not PTRACED and cannot be debugged\n", args->pid);
r = -EPERM;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 2a239f45fc24..6e0df685503d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -1412,6 +1412,15 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,
break;
}
+ /* Validate subtype fits within remaining image */
+ if ((char *)sub_type_hdr + sub_type_hdr->length >
+ (char *)crat_image + image_len) {
+ pr_warn("CRAT subtype length %u exceeds image bounds\n",
+ sub_type_hdr->length);
+ ret = -EINVAL;
+ break;
+ }
+
if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) {
ret = kfd_parse_subtype(sub_type_hdr, device_list);
if (ret)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index 2e97da597b3d..f705c61bdb1d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -524,6 +524,9 @@ int kfd_criu_restore_event(struct file *devkfd,
ret = create_other_event(p, ev, &ev_priv->event_id);
break;
+ default:
+ ret = -EINVAL;
+ break;
}
mutex_unlock(&p->event_mutex);
@@ -545,15 +548,27 @@ int kfd_criu_checkpoint_events(struct kfd_process *p,
int ret = 0;
struct kfd_event *ev;
uint32_t ev_id;
+ uint32_t num_events;
- uint32_t num_events = kfd_get_num_events(p);
+ /* Serialize the count and the walk below against concurrent event
+ * create/destroy. Those paths take only p->event_mutex, not the
+ * p->mutex held by the CRIU checkpoint caller, so without this the
+ * event_idr can grow between kfd_get_num_events() and the loop and the
+ * walk writes past the ev_privs allocation.
+ */
+ mutex_lock(&p->event_mutex);
- if (!num_events)
+ num_events = kfd_get_num_events(p);
+ if (!num_events) {
+ mutex_unlock(&p->event_mutex);
return 0;
+ }
ev_privs = kvzalloc(num_events * sizeof(*ev_privs), GFP_KERNEL);
- if (!ev_privs)
+ if (!ev_privs) {
+ mutex_unlock(&p->event_mutex);
return -ENOMEM;
+ }
idr_for_each_entry(&p->event_idr, ev, ev_id) {
@@ -594,6 +609,8 @@ int kfd_criu_checkpoint_events(struct kfd_process *p,
i++;
}
+ mutex_unlock(&p->event_mutex);
+
ret = copy_to_user(user_priv_data + *priv_data_offset,
ev_privs, num_events * sizeof(*ev_privs));
if (ret) {
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 9ccbc6e5b27b..503176f00204 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -383,7 +383,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
false);
if (retval) {
dev_err(dev->adev->dev, "failed to allocate process context bo\n");
- return retval;
+ goto err_allocate_pqn;
}
memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
index 98a5512b701b..b249e7d1af48 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
@@ -288,7 +288,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
}
err = kfd_queue_buffer_get(vm, (void *)properties->eop_ring_buffer_address,
&properties->eop_buf_bo,
- ALIGN(properties->eop_ring_buffer_size, PAGE_SIZE));
+ ALIGN((u64)properties->eop_ring_buffer_size, PAGE_SIZE));
if (err)
goto out_err_unreserve;
}
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 eaf19ec843e8..1820547b1dde 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9903,25 +9903,6 @@ static void remove_stream(struct amdgpu_device *adev,
acrtc->enabled = false;
}
-static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
-{
-
- assert_spin_locked(&acrtc->base.dev->event_lock);
- WARN_ON(acrtc->event);
-
- acrtc->event = acrtc->base.state->event;
-
- /* Set the flip status */
- acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
-
- /* Mark this event as consumed */
- acrtc->base.state->event = NULL;
-
- drm_dbg_state(acrtc->base.dev,
- "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
- acrtc->crtc_id);
-}
-
static void update_freesync_state_on_stream(
struct amdgpu_display_manager *dm,
struct dm_crtc_state *new_crtc_state,
@@ -10274,17 +10255,47 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
return;
if (pflip_update) {
- drm_crtc_vblank_get(&acrtc->base);
WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
- /* Arm flip completion handling and event delivery after programming. */
- prepare_flip_isr(acrtc);
+ WARN_ON(acrtc->event);
+
+ acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+ acrtc->event = acrtc->base.state->event;
+ acrtc->base.state->event = NULL;
+
+ drm_dbg_state(acrtc->base.dev,
+ "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+ acrtc->crtc_id);
} else if (cursor_update) {
- drm_crtc_vblank_get(&acrtc->base);
acrtc->event = acrtc->base.state->event;
acrtc->base.state->event = NULL;
}
}
+/**
+ * dm_arm_vblank_event_pre_programming - Prepare for programming
+ * @acrtc: The amdgpu CRTC to prepare
+ * @acrtc_state: The new CRTC state
+ * @pflip_update: Whether a page flip is being programmed
+ * @cursor_update: Whether a cursor update is being programmed
+ *
+ * Grab a reference on the vblank counter if a page flip or cursor update is to
+ * be programmed. Do this before programming so the HW is not in any
+ * idle-optimized state (such as PSR).
+ */
+static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc,
+ struct dm_crtc_state *acrtc_state,
+ bool pflip_update,
+ bool cursor_update)
+{
+ assert_spin_locked(&acrtc->base.dev->event_lock);
+
+ if (!acrtc->base.state->event || acrtc_state->active_planes == 0)
+ return;
+
+ if (pflip_update || cursor_update)
+ drm_crtc_vblank_get(&acrtc->base);
+}
+
static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
struct drm_device *dev,
struct amdgpu_display_manager *dm,
@@ -10550,16 +10561,19 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
}
- /*
- * DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for
- * event delivery. Only GRPH_FLIP handler can send pflip events, and it
- * only fires if HW latched to the flip. Maintain legacy behavior by
- * arming event before programming.
- */
- if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
- scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+ scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+ dm_arm_vblank_event_pre_programming(acrtc_attach, acrtc_state,
+ pflip_present,
+ cursor_update);
+ /*
+ * DCE depends on a combination of GRPH_FLIP, VLINE0, and
+ * VUPDATE for event delivery. Only GRPH_FLIP handler can send
+ * pflip events, and it only fires if HW latched to the flip.
+ * Maintain legacy behavior by arming event before programming.
+ */
+ if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
dm_arm_vblank_event(acrtc_attach, acrtc_state,
- pflip_present, cursor_update);
+ pflip_present, cursor_update);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
index ecb8493ec523..8e3862f6dac2 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -45,9 +45,7 @@
clk_src->base.ctx
#define DC_LOGGER \
- calc_pll_cs->ctx->logger
-#define DC_LOGGER_INIT() \
- struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll
+ CTX->logger
#undef FN
#define FN(reg_name, field_name) \
@@ -287,6 +285,7 @@ static bool calc_pll_dividers_in_range(
}
static uint32_t calculate_pixel_clock_pll_dividers(
+ struct dce110_clk_src *clk_src,
struct calc_pll_clock_source *calc_pll_cs,
struct pll_settings *pll_settings)
{
@@ -474,7 +473,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
{
uint32_t field = 0;
uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
- DC_LOGGER_INIT();
+
/* Check if reference clock is external (not pcie/xtalin)
* HW Dce80 spec:
* 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
@@ -517,12 +516,14 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
/*Calculate Dividers by HDMI object, no SS case or SS case */
pll_calc_error =
calculate_pixel_clock_pll_dividers(
+ clk_src,
&clk_src->calc_pll_hdmi,
pll_settings);
else
/*Calculate Dividers by default object, no SS case or SS case */
pll_calc_error =
calculate_pixel_clock_pll_dividers(
+ clk_src,
&clk_src->calc_pll,
pll_settings);
@@ -568,7 +569,6 @@ static uint32_t dce110_get_pix_clk_dividers(
{
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
- DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
|| pix_clk_params->requested_pix_clk_100hz == 0) {
@@ -600,7 +600,6 @@ static uint32_t dce112_get_pix_clk_dividers(
struct pll_settings *pll_settings)
{
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
- DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
|| pix_clk_params->requested_pix_clk_100hz == 0) {
@@ -1442,8 +1441,6 @@ static uint32_t dcn3_get_pix_clk_dividers(
unsigned long long actual_pix_clk_100Hz = pix_clk_params ? pix_clk_params->requested_pix_clk_100hz : 0;
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
- DC_LOGGER_INIT();
-
if (pix_clk_params == NULL || pll_settings == NULL
|| pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
@@ -1513,7 +1510,6 @@ static const struct clock_source_funcs dce110_clk_src_funcs = {
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
};
-
static void get_ss_info_from_atombios(
struct dce110_clk_src *clk_src,
enum as_signal_type as_signal,
@@ -1526,7 +1522,7 @@ static void get_ss_info_from_atombios(
struct spread_spectrum_info *ss_info_cur;
struct spread_spectrum_data *ss_data_cur;
uint32_t i;
- DC_LOGGER_INIT();
+
if (ss_entries_num == NULL) {
DC_LOG_SYNC(
"Invalid entry !!!\n");
@@ -1657,6 +1653,7 @@ static void ss_info_from_atombios_create(
}
static bool calc_pll_max_vco_construct(
+ struct dce110_clk_src *clk_src,
struct calc_pll_clock_source *calc_pll_cs,
struct calc_pll_clock_source_init_data *init_data)
{
@@ -1808,6 +1805,7 @@ bool dce110_clk_src_construct(
ss_info_from_atombios_create(clk_src);
if (!calc_pll_max_vco_construct(
+ clk_src,
&clk_src->calc_pll,
&calc_pll_cs_init_data)) {
ASSERT_CRITICAL(false);
@@ -1822,7 +1820,7 @@ bool dce110_clk_src_construct(
if (!calc_pll_max_vco_construct(
- &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
+ clk_src, &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
ASSERT_CRITICAL(false);
goto unexpected_failure;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
index 835fece1d46a..50e445275b14 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
@@ -359,14 +359,13 @@ void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *c
main_plane = main_stream_status->plane_states[dc_plane_index];
/* create phantom planes for subvp enabled plane */
- dml21_add_phantom_plane(dml_ctx,
- dc,
- context,
- phantom_stream,
- main_plane,
- &dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]);
-
- phantoms_added = true;
+ if (dml21_add_phantom_plane(dml_ctx,
+ dc,
+ context,
+ phantom_stream,
+ main_plane,
+ &dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]))
+ phantoms_added = true;
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index f338e733318e..b4e2264ef408 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -2452,7 +2452,7 @@ static void calculate_mcache_row_bytes(
DML_ASSERT(*p->num_mcaches > 0);
}
-static void calculate_mcache_setting(
+static bool calculate_mcache_setting(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_calculate_mcache_setting_params *p)
{
@@ -2478,7 +2478,7 @@ static void calculate_mcache_setting(
*p->lc_comb_mcache = 0;
if (!p->dcc_enable)
- return;
+ return true;
l->is_dual_plane = dml_is_420(p->source_format) || p->source_format == dml2_rgbe_alpha;
@@ -2515,7 +2515,14 @@ static void calculate_mcache_setting(
l->l_p.mvmpg_per_mcache_lb = &l->mvmpg_per_mcache_lb_l;
calculate_mcache_row_bytes(scratch, &l->l_p);
- DML_ASSERT(*p->num_mcaches_l > 0);
+ if (*p->num_mcaches_l == 0 ||
+ (p->surf_vert ? l->mvmpg_height_l : l->mvmpg_width_l) == 0) {
+ DML_LOG_VERBOSE("DML::%s: degenerate luma viewport (num_mcaches_l=%u mvmpg_%s_l=%u) — mode not supported\n",
+ __func__, *p->num_mcaches_l,
+ p->surf_vert ? "height" : "width",
+ p->surf_vert ? l->mvmpg_height_l : l->mvmpg_width_l);
+ return false;
+ }
if (l->is_dual_plane) {
l->c_p.num_chans = p->num_chans;
@@ -2551,7 +2558,14 @@ static void calculate_mcache_setting(
l->c_p.mvmpg_per_mcache_lb = &l->mvmpg_per_mcache_lb_c;
calculate_mcache_row_bytes(scratch, &l->c_p);
- DML_ASSERT(*p->num_mcaches_c > 0);
+ if (*p->num_mcaches_c == 0 ||
+ (p->surf_vert ? l->mvmpg_height_c : l->mvmpg_width_c) == 0) {
+ DML_LOG_VERBOSE("DML::%s: degenerate chroma viewport (num_mcaches_c=%u mvmpg_%s_c=%u) — mode not supported\n",
+ __func__, *p->num_mcaches_c,
+ p->surf_vert ? "height" : "width",
+ p->surf_vert ? l->mvmpg_height_c : l->mvmpg_width_c);
+ return false;
+ }
}
// Sharing for iMALL access
@@ -2661,6 +2675,7 @@ static void calculate_mcache_setting(
*p->mcache_shift_granularity_l = l->mvmpg_access_width_l;
*p->mcache_shift_granularity_c = l->mvmpg_access_width_c;
+ return true;
}
static void calculate_mall_bw_overhead_factor(
@@ -9457,7 +9472,10 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
calculate_mcache_setting_params->mall_comb_mcache_c = &mode_lib->ms.mall_comb_mcache_c[k];
calculate_mcache_setting_params->lc_comb_mcache = &mode_lib->ms.lc_comb_mcache[k];
- calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params);
+ if (!calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params)) {
+ mode_lib->ms.support.ModeSupport = false;
+ return false;
+ }
}
calculate_mall_bw_overhead_factor(
@@ -10933,7 +10951,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
calculate_mcache_setting_params->mall_comb_mcache_l = &mode_lib->mp.mall_comb_mcache_l[k];
calculate_mcache_setting_params->mall_comb_mcache_c = &mode_lib->mp.mall_comb_mcache_c[k];
calculate_mcache_setting_params->lc_comb_mcache = &mode_lib->mp.lc_comb_mcache[k];
- calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params);
+ if (!calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params))
+ return false;
}
calculate_mall_bw_overhead_factor(
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 042602c50e35..53fffe58602f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -1337,8 +1337,27 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
{
- if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL)
+ if (pipe_ctx == NULL || pipe_ctx->stream_res.stream_enc == NULL)
+ return;
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable);
+
+ /* Wait for three frames to make sure AV mute is sent out.
+ * Some HDMI sinks need additional GCP packets to properly
+ * process the mute state, especially after link re-establishment
+ * with HDMI 2.0 scrambling enabled.
+ */
+ if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
+ int i;
+
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ for (i = 0; i < 3; i++) {
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ }
+ }
+ }
}
enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index a7c85a2302ab..2d3587a31bc8 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -847,13 +847,19 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
pipe_ctx->stream_res.stream_enc,
enable);
- /* Wait for two frame to make sure AV mute is sent out */
+ /* Wait for three frames to make sure AV mute is sent out.
+ * Some HDMI sinks need additional GCP packets to properly
+ * process the mute state, especially after link re-establishment
+ * with HDMI 2.0 scrambling enabled.
+ */
if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
+ int i;
+
pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ for (i = 0; i < 3; i++) {
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ }
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 42e7f0e9b3ce..ca5997748799 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -384,7 +384,7 @@ static bool write_i2c_retimer_vga(
for (size_t i = 0; i < ARRAY_SIZE(vga_data); i++) {
if (!write_i2c_retimer_offset_value(link, address, vga_data[i][0], vga_data[i][1])) {
- DC_LOG_ERROR("Set retimer failed, vga index: %zu\n", i);
+ DC_LOG_DEBUG("Set retimer failed, vga index: %zu\n", i);
return false;
}
}
@@ -405,7 +405,7 @@ static bool write_i2c_retimer_byte(
return true;
if (!write_i2c_retimer_offset_value(link, address, index, value)) {
- DC_LOG_ERROR("Set retimer failed, 3g index: 0x%x, value: 0x%x\n", index, value);
+ DC_LOG_DEBUG("Set retimer failed, 3g index: 0x%x, value: 0x%x\n", index, value);
return false;
}
@@ -421,14 +421,14 @@ static bool write_i2c_retimer_byte(
if (!link_query_ddc_data(
link->ddc, address, &offset, 1, &value, 1
)) {
- DC_LOG_ERROR("Set retimer failed, link_query_ddc_data\n");
+ DC_LOG_DEBUG("Set retimer failed, link_query_ddc_data\n");
return false;
}
}
value |= apply_rx_tx_change;
if (!write_i2c_retimer_offset_value(link, address, offset, value)) {
- DC_LOG_ERROR("Set retimer failed, 3g offset: 0x%x, value: 0x%x\n", offset, value);
+ DC_LOG_DEBUG("Set retimer failed, 3g offset: 0x%x, value: 0x%x\n", offset, value);
return false;
}
}
@@ -449,7 +449,7 @@ static bool write_i2c_retimer_setting(
uint8_t value = settings->reg_settings[i].i2c_reg_val;
if (!write_i2c_retimer_byte(link, address, index, value)) {
- DC_LOG_ERROR("Set retimer failed, index: %zu\n", i);
+ DC_LOG_DEBUG("Set retimer failed, index: %zu\n", i);
return false;
}
}
@@ -460,7 +460,7 @@ static bool write_i2c_retimer_setting(
uint8_t value = settings->reg_settings_6g[i].i2c_reg_val;
if (!write_i2c_retimer_byte(link, address, index, value)) {
- DC_LOG_ERROR("Set retimer failed, 6g index: %zu\n", i);
+ DC_LOG_DEBUG("Set retimer failed, 6g index: %zu\n", i);
return false;
}
}
@@ -492,7 +492,7 @@ static bool write_i2c_default_retimer_setting(
for (size_t i = 0; i < ARRAY_SIZE(data); i++) {
if (!write_i2c_retimer_offset_value(link, address, data[i][0], data[i][1])) {
- DC_LOG_ERROR("Set default retimer failed, index: %zu\n", i);
+ DC_LOG_DEBUG("Set default retimer failed, index: %zu\n", i);
return false;
}
}
@@ -524,7 +524,7 @@ static bool write_i2c_redriver_setting(
);
if (!success)
- DC_LOG_ERROR("Set redriver failed");
+ DC_LOG_DEBUG("Set redriver failed");
return success;
}
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index 6371f292f2d8..606d48115301 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -24,6 +24,8 @@
#ifndef __KGD_PP_INTERFACE_H__
#define __KGD_PP_INTERFACE_H__
+#include <linux/units.h>
+
extern const struct amdgpu_ip_block_version pp_smu_ip_block;
extern const struct amdgpu_ip_block_version smu_v11_0_ip_block;
extern const struct amdgpu_ip_block_version smu_v12_0_ip_block;
@@ -150,8 +152,8 @@ enum amd_pp_sensors {
AMDGPU_PP_SENSOR_MEM_TEMP,
AMDGPU_PP_SENSOR_VCE_POWER,
AMDGPU_PP_SENSOR_UVD_POWER,
- AMDGPU_PP_SENSOR_GPU_AVG_POWER,
- AMDGPU_PP_SENSOR_GPU_INPUT_POWER,
+ AMDGPU_PP_SENSOR_GPU_AVG_POWER, /* milliwatts */
+ AMDGPU_PP_SENSOR_GPU_INPUT_POWER, /* milliwatts */
AMDGPU_PP_SENSOR_SS_APU_SHARE,
AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK,
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index f76ba6753551..e5e89294958a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -1183,20 +1183,36 @@ int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table)
+static bool amdgpu_dpm_is_pp_table_allowed(struct amdgpu_device *adev)
+{
+ return !amdgpu_sriov_vf(adev) &&
+ !(adev->flags & AMD_IS_APU) &&
+ !adev->scpm_enabled;
+}
+
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ char *pptable = NULL;
int ret = 0;
- if (!table)
+ if ((!table && size) || (table && !size))
return -EINVAL;
- if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
+ if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
+ !pp_funcs->get_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle,
- table);
+ &pptable);
+ if (ret > 0 && !pptable) {
+ ret = -EINVAL;
+ } else if (ret > 0 && table) {
+ ret = min_t(size_t, ret, size);
+ memcpy(table, pptable, ret);
+ }
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -1426,17 +1442,23 @@ int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table)
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+ size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- int ret = 0;
+ void *table;
+ ssize_t ret;
if (!pp_funcs->get_gpu_metrics)
return 0;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_gpu_metrics(adev->powerplay.pp_handle,
- table);
+ &table);
+ if (ret > 0) {
+ ret = min_t(ssize_t, ret, size);
+ memcpy(buf, table, ret);
+ }
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -1703,7 +1725,8 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
if (!buf || !size)
return -EINVAL;
- if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)
+ if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
+ !pp_funcs->set_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index 97da01aff76c..85b089a3dc41 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -41,8 +41,6 @@
#define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name)
-#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff))
-
struct od_attribute {
struct kobj_attribute attribute;
struct list_head entry;
@@ -564,25 +562,19 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- char *table = NULL;
int size, ret;
ret = amdgpu_pm_get_access_if_active(adev);
if (ret)
return ret;
- size = amdgpu_dpm_get_pp_table(adev, &table);
+ size = amdgpu_dpm_get_pp_table(adev, buf, PAGE_SIZE - 1);
amdgpu_pm_put_access(adev);
if (size <= 0)
return size;
- if (size >= PAGE_SIZE)
- size = PAGE_SIZE - 1;
-
- memcpy(buf, table, size);
-
return size;
}
@@ -1780,7 +1772,6 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- void *gpu_metrics;
ssize_t size = 0;
int ret;
@@ -1788,15 +1779,10 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
if (ret)
return ret;
- size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics);
+ size = amdgpu_dpm_get_gpu_metrics(adev, buf, PAGE_SIZE - 1);
if (size <= 0)
goto out;
- if (size >= PAGE_SIZE)
- size = PAGE_SIZE - 1;
-
- memcpy(buf, gpu_metrics, size);
-
out:
amdgpu_pm_put_access(adev);
@@ -2726,10 +2712,9 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_table)) {
int ret;
- char *tmp = NULL;
- ret = amdgpu_dpm_get_pp_table(adev, &tmp);
- if (ret == -EOPNOTSUPP || !tmp)
+ ret = amdgpu_dpm_get_pp_table(adev, NULL, 0);
+ if (ret <= 0)
*states = ATTR_STATE_UNSUPPORTED;
else
*states = ATTR_STATE_SUPPORTED;
@@ -3364,7 +3349,7 @@ static int amdgpu_hwmon_get_power(struct device *dev,
return r;
/* convert to microwatts */
- return power_2_mwatt(query) * 1000;
+ return query * 1000;
}
static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
@@ -4932,7 +4917,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
seq_printf(m, "\t%u mV (VDDNB)\n", value);
size = sizeof(uint32_t);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) {
- mwatt = power_2_mwatt(query);
+ mwatt = query;
centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
if (adev->flags & AMD_IS_APU)
seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
@@ -4941,7 +4926,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
}
size = sizeof(uint32_t);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) {
- mwatt = power_2_mwatt(query);
+ mwatt = query;
centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
if (adev->flags & AMD_IS_APU)
seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index aa3f427819a0..8d1b097a3c3c 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -487,7 +487,8 @@ int amdgpu_dpm_get_pp_num_states(struct amdgpu_device *adev,
int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
enum amd_pp_task task_id,
enum amd_pm_state_type *user_state);
-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table);
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size);
int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev,
uint32_t type,
long *input,
@@ -517,7 +518,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
char *buf);
int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
long *input, uint32_t size);
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+ size_t size);
ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
void *table);
ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
index bc82ba2e4c9b..f8a5648095d1 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
@@ -4062,7 +4062,7 @@ static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query)
(adev->asic_type != CHIP_FIJI) &&
(adev->asic_type != CHIP_TONGA)) {
smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetCurrPkgPwr, 0, &tmp);
- *query = tmp;
+ *query = PP_PWR_Q24_8_TO_MW(tmp);
if (tmp != 0)
return 0;
@@ -4081,7 +4081,7 @@ static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query)
if (tmp != 0)
break;
}
- *query = tmp;
+ *query = PP_PWR_Q24_8_TO_MW(tmp);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
index 4b92b52aba2b..c283309efe87 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
@@ -3934,8 +3934,8 @@ static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr,
if (ret)
return ret;
- /* SMC returning actual watts, keep consistent with legacy asics, low 8 bit as 8 fractional bits */
- *query = value << 8;
+ /* SMC returns whole Watts, while power sensors use milliwatts. */
+ *query = value * MILLIWATT_PER_WATT;
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
index 69a9074058ce..b466b08e4a67 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
@@ -1419,7 +1419,7 @@ static int vega12_get_gpu_power(struct pp_hwmgr *hwmgr, uint32_t *query)
if (ret)
return ret;
- *query = metrics_table.CurrSocketPower << 8;
+ *query = metrics_table.CurrSocketPower * MILLIWATT_PER_WATT;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
index 7b8f4c1b80eb..e9c194056e32 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
@@ -2154,12 +2154,13 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int idx,
switch (idx) {
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
if (hwmgr->smu_version == 0x282e00)
- *query = metrics_table.AverageSocketPower << 8;
+ *query = metrics_table.AverageSocketPower *
+ MILLIWATT_PER_WATT;
else
ret = -EOPNOTSUPP;
break;
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
- *query = metrics_table.CurrSocketPower << 8;
+ *query = metrics_table.CurrSocketPower * MILLIWATT_PER_WATT;
break;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
index ca71efaa1656..368200f7cf16 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
@@ -35,6 +35,11 @@ struct pp_hwmgr;
struct phm_fan_speed_info;
struct pp_atomctrl_voltage_table;
+/* Decode legacy unsigned Q24.8 watts to internal milliwatts. */
+#define PP_PWR_Q24_8_TO_MW(power) \
+ DIV_ROUND_CLOSEST_ULL((u64)(power) * MILLIWATT_PER_WATT, \
+ BIT(8))
+
#define VOLTAGE_SCALE 4
#define VOLTAGE_VID_OFFSET_SCALE1 625
#define VOLTAGE_VID_OFFSET_SCALE2 100
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index e3a89e9a9df4..64a64973fb86 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -1348,7 +1348,7 @@ struct pptable_funcs {
u32 (*set_gfx_off_residency)(struct smu_context *smu, bool start);
/**
- * @get_gfx_off_residency: Average GFXOFF residency % during the logging interval
+ * @get_gfx_off_residency: Live GFXOFF residency percentage
*/
u32 (*get_gfx_off_residency)(struct smu_context *smu, uint32_t *residency);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
index 47ddf533b08f..a5d3e8d88860 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
@@ -144,6 +144,44 @@ typedef struct {
uint32_t MaxGfxClk;
} DpmClocks_t;
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+
+ uint32_t VPEClocks[NUM_VPE_DPM_LEVELS];
+ uint32_t FclkClocks_Freq[NUM_FCLK_DPM_LEVELS];
+ uint32_t FclkClocks_Voltage[NUM_FCLK_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ MemPstateTable_t MemPstateTable[NUM_MEM_PSTATE_LEVELS];
+
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+
+ uint8_t VpeClkLevelsEnabled;
+
+ uint8_t NumMemPstatesEnabled;
+ uint8_t NumFclkLevelsEnabled;
+ uint8_t Spare1;
+ uint8_t Spare2;
+
+ uint8_t Spare3;
+ uint8_t Spare4;
+ uint8_t Spare5[2];
+
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+
+ uint32_t Spare6[8];
+ uint32_t Spare7[8];
+ uint32_t Spare8[8];
+ uint32_t Spare9[8];
+} DpmClocks_t_v15_0_5;
+
typedef struct {
uint16_t CoreFrequency[16]; //Target core frequency [MHz]
uint16_t CorePower[16]; //CAC calculated core power [mW]
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
index 7471e2df2828..4206514765cd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
@@ -110,8 +110,10 @@
#define PPSMC_MSG_GetSlowPPTLimit 0x4C
#define PPSMC_MSG_GetGfxOffStatus 0x50
#define PPSMC_MSG_GetGfxOffEntryCount 0x51
-#define PPSMC_MSG_LogGfxOffResidency 0x52
-#define PPSMC_Message_Count 0x53
+#define PPSMC_MSG_GfxOffResidencyLogReadSample 0x52
+#define PPSMC_MSG_StopGfxOffResidencyLogging 0x53
+#define PPSMC_MSG_StartGfxOffResidencyLogging 0x56
+#define PPSMC_Message_Count 0x57
//Argument for PPSMC_MSG_GfxDeviceDriverReset
enum {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index 636ff90923d9..acf03838d49d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -252,7 +252,9 @@
__SMU_DUMMY_MAP(DriverMode2Reset), \
__SMU_DUMMY_MAP(GetGfxOffStatus), \
__SMU_DUMMY_MAP(GetGfxOffEntryCount), \
- __SMU_DUMMY_MAP(LogGfxOffResidency), \
+ __SMU_DUMMY_MAP(StartGfxOffResidencyLogging), \
+ __SMU_DUMMY_MAP(GfxOffResidencyLogReadSample), \
+ __SMU_DUMMY_MAP(StopGfxOffResidencyLogging), \
__SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired), \
__SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel), \
__SMU_DUMMY_MAP(AllowGpo), \
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
index e6fd8be2cc4a..0fa32fd041da 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
@@ -26,7 +26,7 @@
#include "amdgpu_smu.h"
#define SMU15_DRIVER_IF_VERSION_INV 0xFFFFFFFF
-#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x7
+#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x9
#define FEATURE_MASK(feature) (1ULL << feature)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 54d3dba7d354..cfad8cd74773 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -658,7 +658,7 @@ static int arcturus_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->VcnActivityPercentage;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
index e6e009df9840..bb9620666dae 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
@@ -158,12 +158,10 @@ cyan_skillfish_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->Current.MemclkFrequency;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->Current.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Current.CurrentSocketPower;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->Average.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Average.CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->Current.GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index cd0457e13f54..6dfc3b585c6b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -602,7 +602,7 @@ static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -691,7 +691,7 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -777,7 +777,7 @@ static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -866,7 +866,7 @@ static int navi12_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index f799e489b481..dccca6ddd5ad 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -855,9 +855,10 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = use_metrics_v3 ? metrics_v3->AverageSocketPower << 8 :
- use_metrics_v2 ? metrics_v2->AverageSocketPower << 8 :
- metrics->AverageSocketPower << 8;
+ *value = use_metrics_v3 ? metrics_v3->AverageSocketPower :
+ use_metrics_v2 ? metrics_v2->AverageSocketPower :
+ metrics->AverageSocketPower;
+ *value *= MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = (use_metrics_v3 ? metrics_v3->TemperatureEdge :
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index 016a5c893fee..3e3c68448ba9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -72,6 +72,12 @@ static const struct smu_feature_bits vangogh_dpm_features = {
}
};
+/*
+ * SMU support new GFXOFF residency log interface since version 4.63.62.00,
+ * use this to get live readings of GFXOFF residency
+ */
+#define SUPPORT_LIVE_RESIDENCY_MSG_VERSION 0x043f3e00
+
static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 0),
@@ -142,7 +148,9 @@ static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(GetSlowPPTLimit, PPSMC_MSG_GetSlowPPTLimit, 0),
MSG_MAP(GetGfxOffStatus, PPSMC_MSG_GetGfxOffStatus, 0),
MSG_MAP(GetGfxOffEntryCount, PPSMC_MSG_GetGfxOffEntryCount, 0),
- MSG_MAP(LogGfxOffResidency, PPSMC_MSG_LogGfxOffResidency, 0),
+ MSG_MAP(StartGfxOffResidencyLogging, PPSMC_MSG_StartGfxOffResidencyLogging, 0),
+ MSG_MAP(GfxOffResidencyLogReadSample, PPSMC_MSG_GfxOffResidencyLogReadSample, 0),
+ MSG_MAP(StopGfxOffResidencyLogging, PPSMC_MSG_StopGfxOffResidencyLogging, 0),
};
static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
@@ -310,8 +318,7 @@ static int vangogh_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) /
- 1000 ;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
@@ -379,12 +386,10 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->Current.UvdActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->Average.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Average.CurrentSocketPower;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->Current.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Current.CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->Current.GfxTemperature / 100 *
@@ -2449,19 +2454,32 @@ static int vangogh_set_power_limit(struct smu_context *smu,
static u32 vangogh_set_gfxoff_residency(struct smu_context *smu, bool start)
{
int ret = 0;
- u32 residency;
struct amdgpu_device *adev = smu->adev;
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_LogGfxOffResidency,
- start, &residency);
- if (ret)
- return ret;
+ if (smu->smc_fw_version < SUPPORT_LIVE_RESIDENCY_MSG_VERSION) {
+ u32 residency;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxOffResidencyLogReadSample,
+ start, &residency);
+ if (ret)
+ return ret;
- if (!start)
- adev->gfx.gfx_off_residency = residency;
+ if (!start)
+ adev->gfx.gfx_off_residency = residency;
+ } else {
+ if (start) {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_StartGfxOffResidencyLogging, NULL);
+ if (ret)
+ return ret;
+ } else {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_StopGfxOffResidencyLogging, NULL);
+ if (ret)
+ return ret;
+ }
+ }
return ret;
}
@@ -2478,11 +2496,20 @@ static u32 vangogh_set_gfxoff_residency(struct smu_context *smu, bool start)
*/
static u32 vangogh_get_gfxoff_residency(struct smu_context *smu, uint32_t *residency)
{
+ int ret = 0;
struct amdgpu_device *adev = smu->adev;
- *residency = adev->gfx.gfx_off_residency;
+ if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
+ return 0;
+
+ if (smu->smc_fw_version < SUPPORT_LIVE_RESIDENCY_MSG_VERSION) {
+ *residency = adev->gfx.gfx_off_residency;
+ } else {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GfxOffResidencyLogReadSample,
+ residency);
+ }
- return 0;
+ return ret;
}
/**
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75335da224c7..175c44190caa 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -1215,9 +1215,10 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu,
((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
IP_VERSION(12, 0, 0)) &&
(adev->pm.fw_version >= 0x373200)))
- *value = metrics->CurrentSocketPower << 8;
+ *value = metrics->CurrentSocketPower *
+ MILLIWATT_PER_WATT;
else
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = (metrics->GfxTemperature / 100) *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
index 9d8b1227388f..18c0b43b93b9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
@@ -677,7 +677,8 @@ static int aldebaran_get_smu_metrics_data(struct smu_context *smu,
case METRICS_AVERAGE_SOCKETPOWER:
/* Valid power data is available only from primary die */
if (aldebaran_is_primary(smu))
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower *
+ MILLIWATT_PER_WATT;
else
ret = -EOPNOTSUPP;
break;
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 acbd7046d8a5..0be34fbdac26 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
@@ -807,7 +807,7 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
index fe929bd89058..8d476a60d62f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -434,7 +434,8 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ *value = SMUQ10_ROUND(metrics->SocketPower) *
+ MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_HOTSPOT:
*value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index ba91bf590eed..a9d558f5b739 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -338,10 +338,10 @@ static int smu_v13_0_4_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->AverageSocketPower << 8) / 1000;
+ *value = metrics->AverageSocketPower;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
index 27372a60e83d..f95b15af436d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
@@ -295,7 +295,7 @@ static int smu_v13_0_5_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
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 b12388134489..41608574bc61 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
@@ -1321,7 +1321,8 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version));
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) << 8;
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) *
+ MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_HOTSPOT:
*value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) *
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 42c9ceeb4f7d..5d11ed8be4c3 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
@@ -817,7 +817,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
*value = smu_safe_u16_nn(metrics->AverageUclkActivity);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
index 7bf88ffd311b..edc3fedca9f8 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
@@ -372,7 +372,7 @@ static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index 3d73f2050bbe..568665265a13 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -312,8 +312,7 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
break;
case METRICS_AVERAGE_SOCKETPOWER:
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->SocketPower / 1000 << 8) +
- (metrics->SocketPower % 1000 / 10);
+ *value = metrics->SocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
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 a6a88e7b2668..bd054cbfbae0 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
@@ -695,7 +695,7 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
index bb8d09e73c7d..0da1ffb3a567 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
@@ -168,7 +168,7 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
+ SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t_v15_0_5),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -178,7 +178,7 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t_v15_0_5);
if (!smu_table->clocks_table)
goto err1_out;
@@ -378,8 +378,7 @@ static int smu_v15_0_0_get_smu_metrics_data(struct smu_context *smu,
break;
case METRICS_AVERAGE_SOCKETPOWER:
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->SocketPower / 1000 << 8) +
- (metrics->SocketPower % 1000 / 10);
+ *value = metrics->SocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
@@ -752,11 +751,48 @@ static int smu_v15_0_0_get_dpm_freq_by_index(struct smu_context *smu,
return 0;
}
+static int smu_v15_0_5_get_dpm_freq_by_index(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t dpm_level,
+ uint32_t *freq)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ if (!clk_table || clk_type >= SMU_CLK_COUNT)
+ return -EINVAL;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->SocClocks[dpm_level];
+ break;
+ case SMU_UCLK:
+ case SMU_MCLK:
+ if (dpm_level >= clk_table->NumMemPstatesEnabled)
+ return -EINVAL;
+ *freq = clk_table->MemPstateTable[dpm_level].MemClk;
+ break;
+ case SMU_FCLK:
+ if (dpm_level >= clk_table->NumFclkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->FclkClocks_Freq[dpm_level];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_freq_by_index(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t dpm_level,
uint32_t *freq)
{
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq);
+ else
smu_v15_0_0_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq);
return 0;
@@ -907,12 +943,116 @@ failed:
return ret;
}
+static int smu_v15_0_5_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min,
+ uint32_t *max)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+ uint32_t clock_limit;
+ uint32_t max_dpm_level, min_dpm_level;
+ int ret = 0;
+
+ if (!smu_v15_0_0_clk_dpm_is_enabled(smu, clk_type)) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ clock_limit = smu->smu_table.boot_values.uclk;
+ break;
+ case SMU_FCLK:
+ clock_limit = smu->smu_table.boot_values.fclk;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ clock_limit = smu->smu_table.boot_values.gfxclk;
+ break;
+ case SMU_SOCCLK:
+ clock_limit = smu->smu_table.boot_values.socclk;
+ break;
+ default:
+ clock_limit = 0;
+ break;
+ }
+
+ /* clock in Mhz unit */
+ if (min)
+ *min = clock_limit / 100;
+ if (max)
+ *max = clock_limit / 100;
+
+ return 0;
+ }
+
+ if (max) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *max = clk_table->MaxGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ max_dpm_level = 0;
+ break;
+ case SMU_FCLK:
+ max_dpm_level = clk_table->NumFclkLevelsEnabled - 1;
+ break;
+ case SMU_SOCCLK:
+ max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type,
+ max_dpm_level, max);
+ if (ret)
+ goto failed;
+ }
+ }
+
+ if (min) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *min = clk_table->MinGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ min_dpm_level = clk_table->NumMemPstatesEnabled - 1;
+ break;
+ case SMU_FCLK:
+ min_dpm_level = 0;
+ break;
+ case SMU_SOCCLK:
+ min_dpm_level = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type,
+ min_dpm_level, min);
+ if (ret)
+ goto failed;
+ }
+ }
+
+failed:
+ return ret;
+}
+
static int smu_v15_0_common_get_dpm_ultimate_freq(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t *min,
uint32_t *max)
{
- if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_ultimate_freq(smu, clk_type, min, max);
+ else if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
smu_v15_0_0_get_dpm_ultimate_freq(smu, clk_type, min, max);
return 0;
@@ -986,11 +1126,36 @@ static int smu_v15_0_0_get_dpm_level_count(struct smu_context *smu,
return 0;
}
+static int smu_v15_0_5_get_dpm_level_count(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *count)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ *count = clk_table->NumSocClkLevelsEnabled;
+ break;
+ case SMU_MCLK:
+ *count = clk_table->NumMemPstatesEnabled;
+ break;
+ case SMU_FCLK:
+ *count = clk_table->NumFclkLevelsEnabled;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t *count)
{
- if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_level_count(smu, clk_type, count);
+ else if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
smu_v15_0_0_get_dpm_level_count(smu, clk_type, count);
return 0;
@@ -1363,9 +1528,24 @@ static int smu_v15_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
return 0;
}
+static int smu_v15_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
+ smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
+ smu->gfx_actual_hard_min_freq = 0;
+ smu->gfx_actual_soft_max_freq = 0;
+
+ return 0;
+}
+
static int smu_v15_0_common_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
{
- smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu);
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_set_fine_grain_gfx_freq_parameters(smu);
+ else
+ smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu);
return 0;
}
@@ -1405,9 +1585,36 @@ static int smu_v15_0_0_get_dpm_table(struct smu_context *smu, struct dpm_clocks
return 0;
}
+static int smu_v15_0_5_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+ uint8_t idx;
+
+ /*
+ * Only the Clock information of SOC and
+ * VPE is copied to provide VPE DPM settings for use.
+ */
+ for (idx = 0; idx < NUM_SOCCLK_DPM_LEVELS; idx++) {
+ clock_table->SocClocks[idx].Freq =
+ (idx < clk_table->NumSocClkLevelsEnabled) ? clk_table->SocClocks[idx]:0;
+ clock_table->SocClocks[idx].Vol = 0;
+ }
+
+ for (idx = 0; idx < NUM_VPE_DPM_LEVELS; idx++) {
+ clock_table->VPEClocks[idx].Freq =
+ (idx < clk_table->VpeClkLevelsEnabled) ? clk_table->VPEClocks[idx]:0;
+ clock_table->VPEClocks[idx].Vol = 0;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
{
- smu_v15_0_0_get_dpm_table(smu, clock_table);
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_table(smu, clock_table);
+ else
+ smu_v15_0_0_get_dpm_table(smu, clock_table);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
index 2105a1d7bb34..118eda5429ff 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
@@ -411,7 +411,8 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ *value = SMUQ10_ROUND(metrics->SocketPower) *
+ MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_HOTSPOT:
*value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c
index 16c0631adeb1..6b128fabe3a9 100644
--- a/drivers/gpu/drm/bridge/display-connector.c
+++ b/drivers/gpu/drm/bridge/display-connector.c
@@ -40,6 +40,13 @@ static int display_connector_attach(struct drm_bridge *bridge,
return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
}
+static void display_connector_destroy(struct drm_bridge *bridge)
+{
+ struct display_connector *conn = to_display_connector(bridge);
+
+ i2c_put_adapter(conn->bridge.ddc);
+}
+
static enum drm_connector_status display_connector_detect(struct drm_bridge *bridge)
{
struct display_connector *conn = to_display_connector(bridge);
@@ -177,6 +184,7 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge,
static const struct drm_bridge_funcs display_connector_bridge_funcs = {
.attach = display_connector_attach,
+ .destroy = display_connector_destroy,
.detect = display_connector_bridge_detect,
.edid_read = display_connector_edid_read,
.atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts,
@@ -403,9 +411,6 @@ static void display_connector_remove(struct platform_device *pdev)
regulator_disable(conn->supply);
drm_bridge_remove(&conn->bridge);
-
- if (!IS_ERR(conn->bridge.ddc))
- i2c_put_adapter(conn->bridge.ddc);
}
static const struct of_device_id display_connector_match[] = {
diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
index 9c31e14cc413..e623ccb4c1d8 100644
--- a/drivers/gpu/drm/display/drm_dp_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
@@ -3686,6 +3686,18 @@ int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
int bw;
u8 buf;
+ if (!drm_dp_is_branch(dpcd))
+ return 0;
+
+ if (dpcd[DP_DPCD_REV] < 0x11)
+ return 0;
+
+ if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
+ return 0;
+
+ if ((port_cap[0] & DP_DS_PORT_TYPE_MASK) != DP_DS_PORT_TYPE_HDMI)
+ return 0;
+
buf = port_cap[2];
bw = buf & DP_PCON_MAX_FRL_BW;
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 6296635c4e79..95008e0c0eb8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3501,6 +3501,8 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state,
}
intel_ddi_buf_enable(encoder, buf_ctl);
+
+ intel_hdmi_poll_for_scrambling_enable(crtc_state, connector);
}
static void intel_ddi_enable(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7ff5712f8b19..5733d2e7ac7f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4242,7 +4242,14 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
rate_per_lane = info->hdmi.max_frl_rate_per_lane;
max_frl_rate = max_lanes * rate_per_lane;
- if (info->hdmi.dsc_cap.v_1p2) {
+ /*
+ * The sink's DSC max FRL rate only applies to compressed video
+ * transport, which requires a DSC 1.2 encoder in the PCON. Without
+ * one the HDMI link always carries uncompressed video, for which
+ * the regular max FRL rate is the limit.
+ */
+ if (drm_dp_pcon_enc_is_dsc_1_2(intel_dp->pcon_dsc_dpcd) &&
+ info->hdmi.dsc_cap.v_1p2) {
max_dsc_lanes = info->hdmi.dsc_cap.max_lanes;
dsc_rate_per_lane = info->hdmi.dsc_cap.max_frl_rate_per_lane;
if (max_dsc_lanes && dsc_rate_per_lane)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 9076c2b176ec..b9d11fb8559d 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2729,6 +2729,32 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_
}
/*
+ * HDMI 2.0 spec, section 6.1.3.1 (Scrambling Control): after
+ * enabling Scrambling_Enable and starting scrambled video
+ * transmission, poll Scrambling_Status for up to 200 ms.
+ */
+void
+intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state,
+ struct drm_connector *_connector)
+{
+ struct intel_connector *connector = to_intel_connector(_connector);
+ struct intel_display *display = to_intel_display(crtc_state);
+ bool scrambling_enabled = false;
+ int ret;
+
+ if (!crtc_state->hdmi_scrambling)
+ return;
+
+ /* Poll for a max of 200 msec as per HDMI spec */
+ ret = poll_timeout_us(scrambling_enabled = drm_scdc_get_scrambling_status(&connector->base),
+ scrambling_enabled, 1000, 200 * 1000, false);
+ if (ret)
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Timed out waiting for scrambling enable\n",
+ connector->base.base.id, connector->base.name);
+}
+
+/*
* intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup
* @encoder: intel_encoder
* @connector: drm_connector
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index be2fad57e4ad..0fa3661568e8 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -70,5 +70,7 @@ void hsw_read_infoframe(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
unsigned int type,
void *frame, ssize_t len);
+void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state,
+ struct drm_connector *_connector);
#endif /* __INTEL_HDMI_H__ */
diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c
index 941c017399fc..d13726401d92 100644
--- a/drivers/gpu/drm/imagination/pvr_queue.c
+++ b/drivers/gpu/drm/imagination/pvr_queue.c
@@ -726,8 +726,6 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job)
cmd->partial_render_geom_frag_fence.value = job->done_fence->seqno - 1;
}
- trace_pvr_job_submit_fw(job);
-
/* Submit job to FW */
pvr_cccb_write_command_with_header(cccb, job->fw_ccb_cmd_type, job->cmd_len, job->cmd,
job->id, job->id);
@@ -802,6 +800,9 @@ static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job)
job->hwrt,
frag_job->fw_ccb_cmd_type ==
ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR);
+
+ trace_pvr_job_submit_fw(geom_job);
+ trace_pvr_job_submit_fw(frag_job);
} else {
struct pvr_queue *queue = container_of(job->base.sched,
struct pvr_queue, scheduler);
@@ -809,6 +810,8 @@ static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job)
pvr_cccb_send_kccb_kick(pvr_dev, &queue->cccb,
pvr_context_get_fw_addr(job->ctx) + queue->ctx_offset,
job->hwrt);
+
+ trace_pvr_job_submit_fw(job);
}
return dma_fence_get(job->done_fence);
diff --git a/drivers/gpu/drm/imagination/pvr_trace.h b/drivers/gpu/drm/imagination/pvr_trace.h
index ffbbde3b2bcc..943d6b2418cb 100644
--- a/drivers/gpu/drm/imagination/pvr_trace.h
+++ b/drivers/gpu/drm/imagination/pvr_trace.h
@@ -41,6 +41,17 @@ TRACE_EVENT(pvr_job_submit_ioctl,
__entry->count)
);
+#define PVR_JOB_GET_HWRT_FW_ADDR(job) \
+ ({ \
+ struct pvr_job *_job = (job); \
+ u32 _hwrt_fw_addr = 0; \
+ \
+ if (_job && _job->hwrt) \
+ pvr_fw_object_get_fw_addr(_job->hwrt->fw_obj, &_hwrt_fw_addr); \
+ \
+ _hwrt_fw_addr; \
+ })
+
#define PVR_JOB_TYPE_TO_STR(val) \
__print_symbolic(val, \
{ DRM_PVR_JOB_TYPE_GEOMETRY, "geometry" }, \
@@ -64,9 +75,7 @@ TRACE_EVENT(pvr_job_create,
__entry->ctx = job->ctx;
__entry->fw_obj = job->ctx->fw_obj;
pvr_fw_object_get_fw_addr(job->ctx->fw_obj, &__entry->fw_addr);
- __entry->hwrt_addr = job->hwrt ?
- job->hwrt->fw_obj->fw_addr_offset :
- 0;
+ __entry->hwrt_addr = PVR_JOB_GET_HWRT_FW_ADDR(job);
__entry->job = job;
__entry->job_type = job->type;
__entry->sync_op_count = sync_op_count;),
@@ -82,6 +91,7 @@ TRACE_EVENT(pvr_job_create,
);
#undef PVR_JOB_TYPE_TO_STR
+#undef PVR_JOB_GET_HWRT_FW_ADDR
TRACE_EVENT(pvr_job_submit_fw,
TP_PROTO(struct pvr_job *job),
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 8e552cdc3b53..97e3ff412e6e 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -154,10 +154,10 @@ static void mtk_crtc_reset(struct drm_crtc *crtc)
{
struct mtk_crtc_state *state;
- if (crtc->state)
+ if (crtc->state) {
__drm_atomic_helper_crtc_destroy_state(crtc->state);
-
- kfree(to_mtk_crtc_state(crtc->state));
+ kfree(to_mtk_crtc_state(crtc->state));
+ }
crtc->state = NULL;
state = kzalloc_obj(*state);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index c0af3e3b51d5..6a259872b0a9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -625,6 +625,7 @@ static void mtk_disp_ovl_adaptor_master_unbind(struct device *dev)
struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
priv->children_bound = false;
+ component_unbind_all(dev, priv->mmsys_dev);
}
static const struct component_master_ops mtk_disp_ovl_adaptor_master_ops = {
@@ -651,12 +652,15 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
priv->mmsys_dev = pdev->dev.platform_data;
- component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, match);
+ ret = component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, match);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component master\n");
pm_runtime_enable(dev);
ret = component_add(dev, &mtk_disp_ovl_adaptor_comp_ops);
if (ret != 0) {
+ component_master_del(dev, &mtk_disp_ovl_adaptor_master_ops);
pm_runtime_disable(dev);
return dev_err_probe(dev, ret, "Failed to add component\n");
}
@@ -666,6 +670,7 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
{
+ component_del(&pdev->dev, &mtk_disp_ovl_adaptor_comp_ops);
component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops);
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index eb325e68aa59..49dfc0f825cb 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -743,8 +743,6 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
mtk_dsi_set_vm_cmd(dsi);
mtk_dsi_config_vdo_timing(dsi);
mtk_dsi_set_interrupt_enable(dsi);
- mtk_dsi_lane_ready(dsi);
- mtk_dsi_clk_hs_mode(dsi, 1);
return 0;
err_disable_engine_clk:
@@ -858,6 +856,9 @@ static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
ret = mtk_dsi_poweron(dsi);
if (ret < 0)
drm_err(drm, "failed to power on dsi\n");
+
+ mtk_dsi_lane_ready(dsi);
+ mtk_dsi_clk_hs_mode(dsi, 1);
}
static void mtk_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
index a049489daa2d..042b98e5a519 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
@@ -290,6 +290,13 @@ static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev, struc
return 0;
}
+static void mtk_hdmi_put_adapter(void *_adap)
+{
+ struct i2c_adapter *adap = _adap;
+
+ i2c_put_adapter(adap);
+}
+
static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device *pdev,
const char * const *clk_names, size_t num_clocks)
{
@@ -328,12 +335,12 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device
if (!i2c_np)
return dev_err_probe(dev, -EINVAL, "No ddc-i2c-bus in connector\n");
- hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
+ hdmi->ddc_adpt = of_get_i2c_adapter_by_node(i2c_np);
of_node_put(i2c_np);
if (!hdmi->ddc_adpt)
return dev_err_probe(dev, -EPROBE_DEFER, "Failed to get ddc i2c adapter by node\n");
- ret = devm_add_action_or_reset(dev, mtk_hdmi_put_device, &hdmi->ddc_adpt->dev);
+ ret = devm_add_action_or_reset(dev, mtk_hdmi_put_adapter, hdmi->ddc_adpt);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
index 7bbf463056c9..ffe456238a2b 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
@@ -1499,13 +1499,6 @@ static int mtk_hdmi_v2_probe(struct platform_device *pdev)
return 0;
}
-static void mtk_hdmi_v2_remove(struct platform_device *pdev)
-{
- struct mtk_hdmi *hdmi = platform_get_drvdata(pdev);
-
- i2c_put_adapter(hdmi->ddc_adpt);
-}
-
static const struct of_device_id mtk_drm_hdmi_v2_of_ids[] = {
{ .compatible = "mediatek,mt8188-hdmi-tx", .data = &mtk_hdmi_conf_mt8188 },
{ .compatible = "mediatek,mt8195-hdmi-tx", .data = &mtk_hdmi_conf_mt8195 },
@@ -1515,7 +1508,6 @@ MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_v2_of_ids);
static struct platform_driver mtk_hdmi_v2_driver = {
.probe = mtk_hdmi_v2_probe,
- .remove = mtk_hdmi_v2_remove,
.driver = {
.name = "mediatek-drm-hdmi-v2",
.of_match_table = mtk_drm_hdmi_v2_of_ids,
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 90f59d782a80..e45933e333b5 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -545,6 +545,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
struct panthor_fw_binary_section_entry_hdr hdr;
struct panthor_fw_section *section;
u32 section_size;
+ u32 data_size;
u32 name_len;
int ret;
@@ -595,6 +596,13 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
return -EINVAL;
}
+ section_size = hdr.va.end - hdr.va.start;
+ data_size = hdr.data.end - hdr.data.start;
+ if (data_size > section_size) {
+ drm_err(&ptdev->base, "Firmware corrupted, section data exceeds section size\n");
+ return -EINVAL;
+ }
+
name_len = iter->size - iter->offset;
section = drmm_kzalloc(&ptdev->base, sizeof(*section), GFP_KERNEL);
@@ -603,7 +611,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
list_add_tail(&section->node, &ptdev->fw->sections);
section->flags = hdr.flags;
- section->data.size = hdr.data.end - hdr.data.start;
+ section->data.size = data_size;
if (section->data.size > 0) {
void *data = drmm_kmalloc(&ptdev->base, section->data.size, GFP_KERNEL);
@@ -626,7 +634,6 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
section->name = name;
}
- section_size = hdr.va.end - hdr.va.start;
if (section_size) {
u32 cache_mode = hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK;
struct panthor_gem_object *bo;
@@ -857,18 +864,24 @@ out:
* iface_fw_to_cpu_addr() - Turn an MCU address into a CPU address
* @ptdev: Device.
* @mcu_va: MCU address.
+ * @size: Size of the object pointed to by @mcu_va.
*
- * Return: NULL if the address is not part of the shared section, non-NULL otherwise.
+ * Return: NULL if the object is not part of the shared section, non-NULL otherwise.
*/
-static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va)
+static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va, size_t size)
{
u64 shared_mem_start = panthor_kernel_bo_gpuva(ptdev->fw->shared_section->mem);
- u64 shared_mem_end = shared_mem_start +
- panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
- if (mcu_va < shared_mem_start || mcu_va >= shared_mem_end)
+ size_t shared_mem_size = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
+ u64 offset;
+
+ if (mcu_va < shared_mem_start)
+ return NULL;
+
+ offset = mcu_va - shared_mem_start;
+ if (offset > shared_mem_size || size > shared_mem_size - offset)
return NULL;
- return ptdev->fw->shared_section->mem->kmap + (mcu_va - shared_mem_start);
+ return ptdev->fw->shared_section->mem->kmap + offset;
}
static int panthor_init_cs_iface(struct panthor_device *ptdev,
@@ -890,8 +903,10 @@ static int panthor_init_cs_iface(struct panthor_device *ptdev,
spin_lock_init(&cs_iface->lock);
cs_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset;
- cs_iface->input = iface_fw_to_cpu_addr(ptdev, cs_iface->control->input_va);
- cs_iface->output = iface_fw_to_cpu_addr(ptdev, cs_iface->control->output_va);
+ cs_iface->input = iface_fw_to_cpu_addr(ptdev, cs_iface->control->input_va,
+ sizeof(*cs_iface->input));
+ cs_iface->output = iface_fw_to_cpu_addr(ptdev, cs_iface->control->output_va,
+ sizeof(*cs_iface->output));
if (!cs_iface->input || !cs_iface->output) {
drm_err(&ptdev->base, "Invalid stream control interface input/output VA");
@@ -941,8 +956,10 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev,
spin_lock_init(&csg_iface->lock);
csg_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset;
- csg_iface->input = iface_fw_to_cpu_addr(ptdev, csg_iface->control->input_va);
- csg_iface->output = iface_fw_to_cpu_addr(ptdev, csg_iface->control->output_va);
+ csg_iface->input = iface_fw_to_cpu_addr(ptdev, csg_iface->control->input_va,
+ sizeof(*csg_iface->input));
+ csg_iface->output = iface_fw_to_cpu_addr(ptdev, csg_iface->control->output_va,
+ sizeof(*csg_iface->output));
if (csg_iface->control->stream_num < MIN_CS_PER_CSG ||
csg_iface->control->stream_num > MAX_CS_PER_CSG)
@@ -999,8 +1016,10 @@ static int panthor_fw_init_ifaces(struct panthor_device *ptdev)
return -EINVAL;
}
- glb_iface->input = iface_fw_to_cpu_addr(ptdev, glb_iface->control->input_va);
- glb_iface->output = iface_fw_to_cpu_addr(ptdev, glb_iface->control->output_va);
+ glb_iface->input = iface_fw_to_cpu_addr(ptdev, glb_iface->control->input_va,
+ sizeof(*glb_iface->input));
+ glb_iface->output = iface_fw_to_cpu_addr(ptdev, glb_iface->control->output_va,
+ sizeof(*glb_iface->output));
if (!glb_iface->input || !glb_iface->output) {
drm_err(&ptdev->base, "Invalid global control interface input/output VA");
return -EINVAL;
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 8e5141bb5075..7877d493d80e 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -104,7 +104,7 @@ vc4_overflow_mem_work(struct work_struct *work)
vc4->bin_alloc_overflow = BIT(bin_bo_slot);
V3D_WRITE(V3D_BPOA, bo->base.dma_addr + bin_bo_slot * vc4->bin_alloc_size);
- V3D_WRITE(V3D_BPOS, bo->base.base.size);
+ V3D_WRITE(V3D_BPOS, vc4->bin_alloc_size);
V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM);
V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index 7f2fadfde7a8..d2a65c968b1f 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -385,6 +385,23 @@ validate_tile_binning_config(VALIDATE_ARGS)
return -EINVAL;
}
+ /* The tile state data array is 48 bytes per tile, and we put it at
+ * the start of a BO containing both it and the tile alloc.
+ */
+ tile_state_size = 48 * tile_count;
+
+ /* Since the tile alloc array will follow us, align. */
+ tile_state_size = roundup(tile_state_size, 4096);
+
+ /* Reject configurations whose tile state would leave no room for
+ * the tile alloc pool that follows it in the slot.
+ */
+ if (tile_state_size >= vc4->bin_alloc_size) {
+ DRM_DEBUG("Tile binning config of %dx%d too large\n",
+ exec->bin_tiles_x, exec->bin_tiles_y);
+ return -EINVAL;
+ }
+
bin_slot = vc4_v3d_get_bin_slot(vc4);
if (bin_slot < 0) {
if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
@@ -400,13 +417,13 @@ validate_tile_binning_config(VALIDATE_ARGS)
exec->bin_slots |= BIT(bin_slot);
bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size;
- /* The tile state data array is 48 bytes per tile, and we put it at
- * the start of a BO containing both it and the tile alloc.
- */
- tile_state_size = 48 * tile_count;
+ exec->tile_alloc_offset = bin_addr + tile_state_size;
- /* Since the tile alloc array will follow us, align. */
- exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096);
+ /* The TSDA area must be zeroed out before use, otherwise the PTB might
+ * consume a stale tile state.
+ */
+ memset(vc4->bin_bo->base.vaddr + bin_slot * vc4->bin_alloc_size, 0,
+ tile_state_size);
*(uint8_t *)(validated + 14) =
((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c
index 2421b0dd057c..f9042bafdc93 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.c
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.c
@@ -547,14 +547,17 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
if (IS_ERR(dma_buf))
return PTR_ERR(dma_buf);
- if (dma_buf->ops != &tdev->ops)
- return -ENOSYS;
+ if (dma_buf->ops != &tdev->ops) {
+ ret = -ENOSYS;
+ goto out;
+ }
prime = (struct ttm_prime_object *) dma_buf->priv;
base = &prime->base;
*handle = base->handle;
ret = ttm_ref_object_add(tfile, base, NULL, false);
+out:
dma_buf_put(dma_buf);
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
index 135b75a3e013..56f965ec99dc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
@@ -30,6 +30,7 @@
#include "vmwgfx_bo.h"
#include <linux/highmem.h>
+#include <linux/overflow.h>
/*
* Template that implements find_first_diff() for a generic
@@ -463,19 +464,42 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
container_of(dst->tbo.bdev, struct vmw_private, bdev);
size_t dst_size = dst->tbo.resource->size;
size_t src_size = src->tbo.resource->size;
+ size_t dst_end, src_end;
struct iosys_map dst_map = {0};
struct iosys_map src_map = {0};
+ bool dst_mapped = false;
+ bool src_mapped = false;
int ret, i;
int x_in_bytes;
u8 *vsrc;
u8 *vdst;
+ if (!height || !width_in_bytes)
+ return 0;
+
+ if (!dst_stride || !src_stride)
+ return -EINVAL;
+ if (dst_stride < width_in_bytes || src_stride < width_in_bytes)
+ return -EINVAL;
+ if (check_mul_overflow((size_t)dst_stride, (size_t)height - 1, &dst_end) ||
+ check_add_overflow(dst_end, (size_t)width_in_bytes, &dst_end) ||
+ check_add_overflow((size_t)dst_offset, dst_end, &dst_end) ||
+ dst_end > dst_size ||
+ check_mul_overflow((size_t)src_stride, (size_t)height - 1, &src_end) ||
+ check_add_overflow(src_end, (size_t)width_in_bytes, &src_end) ||
+ check_add_overflow((size_t)src_offset, src_end, &src_end) ||
+ src_end > src_size) {
+ drm_dbg_driver(&vmw->drm, "Out-of-bounds external BO copy\n");
+ return -EINVAL;
+ }
+
vsrc = map_external(src, &src_map);
if (!vsrc) {
drm_dbg_driver(&vmw->drm, "Wasn't able to map src\n");
ret = -ENOMEM;
goto out;
}
+ src_mapped = true;
vdst = map_external(dst, &dst_map);
if (!vdst) {
@@ -483,16 +507,13 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
ret = -ENOMEM;
goto out;
}
+ dst_mapped = true;
vsrc += src_offset;
vdst += dst_offset;
- if (src_stride == dst_stride) {
- dst_size -= dst_offset;
- src_size -= src_offset;
- memcpy(vdst, vsrc,
- min(dst_stride * height, min(dst_size, src_size)));
+ if (src_stride == dst_stride && width_in_bytes == dst_stride) {
+ memcpy(vdst, vsrc, dst_stride * (size_t)height);
} else {
- WARN_ON(dst_stride < width_in_bytes);
for (i = 0; i < height; ++i) {
memcpy(vdst, vsrc, width_in_bytes);
vsrc += src_stride;
@@ -508,8 +529,10 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
ret = 0;
out:
- unmap_external(src, &src_map);
- unmap_external(dst, &dst_map);
+ if (src_mapped)
+ unmap_external(src, &src_map);
+ if (dst_mapped)
+ unmap_external(dst, &dst_map);
return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
index b010fc7ca68e..d1e7df500190 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
@@ -432,6 +432,7 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
u32 size = vmw_cursor_mob_size(vps->cursor.update_type,
vps->base.crtc_w, vps->base.crtc_h);
struct vmw_bo *vbo = vps->cursor.mob;
+ void *map;
if (!vbo)
return -EINVAL;
@@ -446,11 +447,15 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
if (unlikely(ret != 0))
return -ENOMEM;
- vmw_bo_map_and_cache(vbo);
+ map = vmw_bo_map_and_cache(vbo);
+ if (!map) {
+ vmw_bo_unmap(vbo);
+ ret = -ENOMEM;
+ }
ttm_bo_unreserve(&vbo->tbo);
- return 0;
+ return ret;
}
/**
@@ -663,9 +668,15 @@ int vmw_cursor_plane_prepare_fb(struct drm_plane *plane,
!vmw_cursor_buffer_changed(vps, old_vps)) {
vps->cursor.update_type =
VMW_CURSOR_UPDATE_NONE;
- } else {
- vmw_cursor_mob_get(vcp, vps);
- vmw_cursor_mob_map(vps);
+ } else if (vps->cursor.update_type ==
+ VMW_CURSOR_UPDATE_MOB &&
+ (vmw_cursor_mob_get(vcp, vps) ||
+ vmw_cursor_mob_map(vps))) {
+ /*
+ * Reset the cursor to avoid crashes later.
+ */
+ vps->cursor.update_type =
+ VMW_CURSOR_UPDATE_NONE;
}
}
}
@@ -732,6 +743,34 @@ int vmw_cursor_plane_atomic_check(struct drm_plane *plane,
"surface not suitable for cursor\n");
return -EINVAL;
}
+ } else if (update_type == VMW_CURSOR_UPDATE_GB_ONLY ||
+ update_type == VMW_CURSOR_UPDATE_MOB) {
+ u32 cursor_max_dim =
+ vmw_read(vmw, SVGA_REG_CURSOR_MAX_DIMENSION);
+
+ if (new_state->crtc_w > cursor_max_dim ||
+ new_state->crtc_h > cursor_max_dim) {
+ drm_warn(&vmw->drm,
+ "Cursor dimensions (%d, %d) exceed device max %u\n",
+ new_state->crtc_w, new_state->crtc_h,
+ cursor_max_dim);
+ return -EINVAL;
+ }
+
+ if (update_type == VMW_CURSOR_UPDATE_MOB) {
+ u32 mob_max_size =
+ vmw_read(vmw, SVGA_REG_MOB_MAX_SIZE);
+ u64 mob_size = (u64)new_state->crtc_w *
+ new_state->crtc_h * sizeof(u32) +
+ sizeof(SVGAGBCursorHeader);
+
+ if (mob_size > mob_max_size) {
+ drm_warn(&vmw->drm,
+ "Cursor MOB size %llu exceeds device max %u\n",
+ mob_size, mob_max_size);
+ return -EINVAL;
+ }
+ }
}
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index e1f18020170a..a9136a6523cb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1272,9 +1272,13 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
SVGA3dCmdHeader *header)
{
VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBindQuery);
+ struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
struct vmw_bo *vmw_bo;
int ret;
+ if (!ctx_node)
+ return -EINVAL;
+
cmd = container_of(header, typeof(*cmd), header);
/*
@@ -1288,7 +1292,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
return ret;
sw_context->dx_query_mob = vmw_bo;
- sw_context->dx_query_ctx = sw_context->dx_ctx_node->ctx;
+ sw_context->dx_query_ctx = ctx_node->ctx;
return 0;
}
@@ -1506,6 +1510,12 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
bool dirty;
cmd = container_of(header, typeof(*cmd), header);
+
+ if (unlikely(header->size < sizeof(cmd->body) + sizeof(*suffix))) {
+ VMW_DEBUG_USER("Illegal SVGA_3D_CMD_SURFACE_DMA size.\n");
+ return -EINVAL;
+ }
+
suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->body +
header->size - sizeof(*suffix));
@@ -1567,11 +1577,17 @@ static int vmw_cmd_draw(struct vmw_private *dev_priv,
uint32_t maxnum;
int ret;
+ cmd = container_of(header, typeof(*cmd), header);
+
+ if (unlikely(header->size < sizeof(cmd->body))) {
+ VMW_DEBUG_USER("Illegal DRAW_PRIMITIVES header size.\n");
+ return -EINVAL;
+ }
+
ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
if (unlikely(ret != 0))
return ret;
- cmd = container_of(header, typeof(*cmd), header);
maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
if (unlikely(cmd->body.numVertexDecls > maxnum)) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 4ef84ff9b638..384c6736cf6b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -367,13 +367,24 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
ret = vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT);
+ spin_lock(&fman->lock);
if (unlikely(ret != 0)) {
+ bool cookie = dma_fence_begin_signalling();
+
list_del_init(&fence->head);
- dma_fence_signal(&fence->base);
+ if (fence->waiter_added) {
+ vmw_seqno_waiter_remove(fman->dev_priv);
+ fence->waiter_added = false;
+ }
+ dma_fence_signal_locked(&fence->base);
+ dma_fence_end_signalling(cookie);
}
BUG_ON(!list_empty(&fence->head));
+ spin_unlock(&fman->lock);
+
dma_fence_put(&fence->base);
+
spin_lock(&fman->lock);
}
spin_unlock(&fman->lock);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
index 45561bc1c9ef..8ab88f388652 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
@@ -311,7 +311,7 @@ void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res)
return;
cur = max(res_start, dirty->start);
- res_end = max(res_end, dirty->end);
+ res_end = min(res_end, dirty->end);
while (cur < res_end) {
unsigned long num;
@@ -347,7 +347,7 @@ void vmw_bo_dirty_clear(struct vmw_bo *vbo)
return;
cur = max(res_start, dirty->start);
- res_end = max(res_end, dirty->end);
+ res_end = min(res_end, dirty->end);
while (cur < res_end) {
unsigned long num;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 388011696941..e3a187a2c7a1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -136,7 +136,7 @@ static void vmw_resource_release(struct kref *kref)
val_buf.num_shared = 0;
res->func->unbind(res, false, &val_buf);
}
- res->guest_memory_size = false;
+ res->guest_memory_dirty = false;
vmw_resource_mob_detach(res);
if (res->dirty)
res->func->dirty_free(res);
@@ -773,7 +773,7 @@ void vmw_resource_unbind_list(struct vmw_bo *vbo)
if (!WARN_ON_ONCE(!res->func->unbind))
(void) res->func->unbind(res, res->res_dirty, &val_buf);
- res->guest_memory_size = true;
+ res->guest_memory_dirty = true;
res->res_dirty = false;
vmw_resource_mob_detach(res);
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index eca4e3e97eb4..39811cf19db1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -25,6 +25,8 @@
*
**************************************************************************/
+#include <linux/overflow.h>
+
#include <drm/ttm/ttm_placement.h>
#include "vmwgfx_binding.h"
@@ -685,7 +687,7 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
struct vmw_bo *buffer,
size_t shader_size,
- size_t offset,
+ u64 offset,
SVGA3dShaderType shader_type,
uint8_t num_input_sig,
uint8_t num_output_sig,
@@ -739,7 +741,7 @@ out:
static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
struct vmw_bo *buffer,
size_t shader_size,
- size_t offset,
+ u64 offset,
SVGA3dShaderType shader_type)
{
struct vmw_shader *shader;
@@ -768,7 +770,7 @@ out_err:
static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
enum drm_vmw_shader_type shader_type_drm,
- u32 buffer_handle, size_t size, size_t offset,
+ u32 buffer_handle, size_t size, u64 offset,
uint8_t num_input_sig, uint8_t num_output_sig,
uint32_t *shader_handle)
{
@@ -779,13 +781,16 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
int ret;
if (buffer_handle != SVGA3D_INVALID_ID) {
+ u64 end;
+
ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
if (unlikely(ret != 0)) {
VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
return ret;
}
- if ((u64)buffer->tbo.base.size < (u64)size + (u64)offset) {
+ if (check_add_overflow((u64)size, (u64)offset, &end) ||
+ end > buffer->tbo.base.size) {
VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
ret = -EINVAL;
goto out_bad_arg;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
index 35dc94c3db39..45fde7ec514f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
@@ -309,7 +309,8 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
}
node->res = vmw_resource_reference_unless_doomed(res);
if (!node->res) {
- hash_del_rcu(&node->hash.head);
+ if (ctx->sw_context)
+ hash_del_rcu(&node->hash.head);
return -ESRCH;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
index 7b8163b5e501..3d0d5dfa869f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
@@ -206,14 +206,14 @@ vmw_vkms_init(struct vmw_private *vmw)
vmw->vkms_enabled = false;
ret = vmw_host_get_guestinfo(GUESTINFO_VBLANK, buffer, &buf_len);
- if (ret || buf_len > max_buf_len)
- return;
- buffer[buf_len] = '\0';
+ if (!ret && buf_len <= max_buf_len) {
+ buffer[buf_len] = '\0';
- ret = kstrtobool(buffer, &vmw->vkms_enabled);
- if (!ret && vmw->vkms_enabled) {
- ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
- vmw->vkms_enabled = (ret == 0);
+ ret = kstrtobool(buffer, &vmw->vkms_enabled);
+ if (!ret && vmw->vkms_enabled) {
+ ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
+ vmw->vkms_enabled = (ret == 0);
+ }
}
vmw->crc_workq = alloc_ordered_workqueue("vmwgfx_crc_generator", 0);
@@ -228,7 +228,8 @@ vmw_vkms_init(struct vmw_private *vmw)
void
vmw_vkms_cleanup(struct vmw_private *vmw)
{
- destroy_workqueue(vmw->crc_workq);
+ if (vmw->crc_workq)
+ destroy_workqueue(vmw->crc_workq);
}
bool
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 39c9c8f0ea2d..d0a1e6c2b55f 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -443,10 +443,6 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,
if (!xe_pt_covers(addr, next, level, &xe_walk->base))
return false;
- /* Does the DMA segment cover the whole pte? */
- if (next - xe_walk->va_curs_start > xe_walk->curs->size)
- return false;
-
/* null VMA's and purged BO's do not have dma addresses */
if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo)))
return true;
@@ -455,6 +451,10 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,
if (xe_walk->clear_pt)
return true;
+ /* Does the DMA segment cover the whole pte? */
+ if (next - xe_walk->va_curs_start > xe_walk->curs->size)
+ return false;
+
/* Is the DMA address huge PTE size aligned? */
size = next - addr;
dma = addr - xe_walk->va_curs_start + xe_res_dma(xe_walk->curs);
@@ -775,8 +775,11 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
}
xe_walk.needs_64K = (vm->flags & XE_VM_FLAG_64K);
- if (clear_pt)
+ if (clear_pt) {
+ xe_assert(xe, !range);
+ curs.size = xe_vma_size(vma);
goto walk_pt;
+ }
if (vma->gpuva.flags & XE_VMA_ATOMIC_PTE_BIT) {
xe_walk.default_vram_pte = xe_atomic_for_vram(vm, vma) ? XE_USM_PPGTT_PTE_AE : 0;
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index b5b322ce16df..0fd50d4cb573 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -72,7 +72,8 @@ module_param(max_version, uint, S_IRUGO);
MODULE_PARM_DESC(max_version,
"Maximal VMBus protocol version which can be negotiated");
-int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
+static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
+ u32 version, u32 connection_id)
{
int ret = 0;
struct vmbus_channel_initiate_contact *msg;
@@ -87,20 +88,20 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
msg->vmbus_version_requested = version;
/*
- * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
- * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
- * and for subsequent messages, we must use the Message Connection ID
- * field in the host-returned Version Response Message. And, with
- * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
- * tell the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
- * compatibility.
+ * For VMBus protocol 5.0 (VERSION_WIN10_V5) and higher, use the
+ * caller-supplied connection_id for the Initiate Contact message so
+ * the caller can implement the required retry scheme. For subsequent
+ * messages, use the Message Connection ID field in the host-returned
+ * Version Response message. With VERSION_WIN10_V5 and higher, we don't
+ * use msg->interrupt_page, but tell the host explicitly that we still
+ * use VMBUS_MESSAGE_SINT(2) for compatibility.
*
* On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
*/
if (version >= VERSION_WIN10_V5) {
msg->msg_sint = VMBUS_MESSAGE_SINT;
msg->msg_vtl = ms_hyperv.vtl;
- vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
+ vmbus_connection.msg_conn_id = connection_id;
} else {
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -165,6 +166,22 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
return ret;
}
+int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
+{
+ int ret;
+
+ /* Try the redirect ID first for VTL2 with VMBus protocol 5.0+. */
+ if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl == 2) {
+ ret = vmbus_try_connection_id(msginfo, version,
+ VMBUS_MESSAGE_CONNECTION_ID_REDIRECT);
+ if (ret != -ENXIO)
+ return ret;
+ }
+
+ return vmbus_try_connection_id(msginfo, version,
+ VMBUS_MESSAGE_CONNECTION_ID_4);
+}
+
/*
* vmbus_connect - Sends a connect request on the partition service connection
*/
@@ -457,18 +474,10 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
switch (ret) {
case HV_STATUS_INVALID_CONNECTION_ID:
- /*
- * See vmbus_negotiate_version(): VMBus protocol 5.0
- * and higher require that we must use
- * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
- * Contact message, but on old hosts that only
- * support VMBus protocol 4.0 or lower, here we get
- * HV_STATUS_INVALID_CONNECTION_ID and we should
- * return an error immediately without retrying.
- */
+ /* Allow INITIATE_CONTACT to try another connection ID. */
hdr = buffer;
if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
- return -EINVAL;
+ return -ENXIO;
/*
* We could get this if we send messages too
* frequently.
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index eb8bdd8bb1f5..33923621a5a3 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -110,6 +110,8 @@ struct hv_input_post_message {
enum {
VMBUS_MESSAGE_CONNECTION_ID = 1,
VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
+ /* VTL2 redirect connection ID for INITIATE_CONTACT. */
+ VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
VMBUS_MESSAGE_PORT_ID = 1,
VMBUS_EVENT_CONNECTION_ID = 2,
VMBUS_EVENT_PORT_ID = 2,
diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c
index 90959f639dc3..06aef99c8298 100644
--- a/drivers/hv/mshv_eventfd.c
+++ b/drivers/hv/mshv_eventfd.c
@@ -169,7 +169,14 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)
return -EOPNOTSUPP;
#endif
- vp = partition->pt_vp_array[irq->lapic_apic_id];
+ /*
+ * Pairs with smp_store_release() in mshv_partition_ioctl_create_vp().
+ * MSHV_IRQFD does not require the target lapic_apic_id to refer to an
+ * existing VP, so this read can race a concurrent VP creation; the
+ * acquire ensures that a non-NULL pointer implies the VP's
+ * initialising stores are visible.
+ */
+ vp = smp_load_acquire(&partition->pt_vp_array[irq->lapic_apic_id]);
if (!vp->vp_register_page)
return -EOPNOTSUPP;
@@ -284,7 +291,7 @@ static void mshv_irqfd_deactivate(struct mshv_irqfd *irqfd)
if (!mshv_irqfd_is_active(irqfd))
return;
- hlist_del(&irqfd->irqfd_hnode);
+ hlist_del_init(&irqfd->irqfd_hnode);
queue_work(irqfd_cleanup_wq, &irqfd->irqfd_shutdown);
}
@@ -473,6 +480,19 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
init_poll_funcptr(&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);
spin_lock_irq(&pt->pt_irqfds_lock);
+ ret = 0;
+ hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) {
+ if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
+ continue;
+ /* This fd is used for another irq already. */
+ ret = -EBUSY;
+ spin_unlock_irq(&pt->pt_irqfds_lock);
+ goto fail;
+ }
+
+ idx = srcu_read_lock(&pt->pt_irq_srcu);
+ mshv_irqfd_update(pt, irqfd);
+
#if IS_ENABLED(CONFIG_X86)
if (args->flags & BIT(MSHV_IRQFD_BIT_RESAMPLE) &&
!irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
@@ -481,22 +501,12 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
* Otherwise return with failure
*/
spin_unlock_irq(&pt->pt_irqfds_lock);
+ srcu_read_unlock(&pt->pt_irq_srcu, idx);
ret = -EINVAL;
goto fail;
}
#endif
- ret = 0;
- hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) {
- if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
- continue;
- /* This fd is used for another irq already. */
- ret = -EBUSY;
- spin_unlock_irq(&pt->pt_irqfds_lock);
- goto fail;
- }
- idx = srcu_read_lock(&pt->pt_irq_srcu);
- mshv_irqfd_update(pt, irqfd);
hlist_add_head(&irqfd->irqfd_hnode, &pt->pt_irqfds_list);
spin_unlock_irq(&pt->pt_irqfds_lock);
@@ -541,13 +551,14 @@ static int mshv_irqfd_deassign(struct mshv_partition *pt,
if (IS_ERR(eventfd))
return PTR_ERR(eventfd);
+ spin_lock_irq(&pt->pt_irqfds_lock);
hlist_for_each_entry_safe(irqfd, n, &pt->pt_irqfds_list,
irqfd_hnode) {
if (irqfd->irqfd_eventfd_ctx == eventfd &&
irqfd->irqfd_irqnum == args->gsi)
-
mshv_irqfd_deactivate(irqfd);
}
+ spin_unlock_irq(&pt->pt_irqfds_lock);
eventfd_ctx_put(eventfd);
diff --git a/drivers/hv/mshv_irq.c b/drivers/hv/mshv_irq.c
index b3142c84dcbc..65a4ffc82d56 100644
--- a/drivers/hv/mshv_irq.c
+++ b/drivers/hv/mshv_irq.c
@@ -51,7 +51,7 @@ int mshv_update_routing_table(struct mshv_partition *partition,
/*
* Allow only one to one mapping between GSI and MSI routing.
*/
- if (girq->guest_irq_num != 0) {
+ if (girq->girq_entry_valid) {
r = -EINVAL;
goto out;
}
diff --git a/drivers/hv/mshv_portid_table.c b/drivers/hv/mshv_portid_table.c
index c349af1f0aaa..0d632507ed21 100644
--- a/drivers/hv/mshv_portid_table.c
+++ b/drivers/hv/mshv_portid_table.c
@@ -40,12 +40,14 @@ mshv_port_table_fini(void)
int
mshv_portid_alloc(struct port_table_info *info)
{
- int ret = 0;
+ int ret;
+ idr_preload(GFP_KERNEL);
idr_lock(&port_table_idr);
ret = idr_alloc(&port_table_idr, info, PORTID_MIN,
- PORTID_MAX, GFP_KERNEL);
+ PORTID_MAX, GFP_NOWAIT);
idr_unlock(&port_table_idr);
+ idr_preload_end();
return ret;
}
@@ -60,8 +62,7 @@ mshv_portid_free(int port_id)
WARN_ON(!info);
idr_unlock(&port_table_idr);
- synchronize_rcu();
- kfree(info);
+ kfree_rcu(info, portbl_rcu);
}
int
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 146726cc4e9b..cc2cfce2aefd 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -1072,6 +1072,8 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
struct mshv_vp *vp;
struct page *intercept_msg_page, *register_page, *ghcb_page;
struct hv_stats_page *stats_pages[2];
+ struct file *file;
+ int fd;
long ret;
if (copy_from_user(&args, arg, sizeof(args)))
@@ -1117,8 +1119,10 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
goto unmap_ghcb_page;
vp = kzalloc_obj(*vp);
- if (!vp)
+ if (!vp) {
+ ret = -ENOMEM;
goto unmap_stats_pages;
+ }
vp->vp_partition = mshv_partition_get(partition);
if (!vp->vp_partition) {
@@ -1144,21 +1148,40 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
if (ret)
goto put_partition;
- /*
- * Keep anon_inode_getfd last: it installs fd in the file struct and
- * thus makes the state accessible in user space.
- */
- ret = anon_inode_getfd("mshv_vp", &mshv_vp_fops, vp,
- O_RDWR | O_CLOEXEC);
- if (ret < 0)
+ fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ ret = fd;
goto remove_debugfs_vp;
+ }
+
+ file = anon_inode_getfile("mshv_vp", &mshv_vp_fops, vp,
+ O_RDWR | O_CLOEXEC);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto put_unused_vp_fd;
+ }
/* already exclusive with the partition mutex for all ioctls */
partition->pt_vp_count++;
- partition->pt_vp_array[args.vp_index] = vp;
+ /*
+ * Pairs with smp_load_acquire() in mshv_try_assert_irq_fast(), which
+ * can run concurrently from an irqfd waker without holding pt_mutex.
+ * The release ensures the VP's initialising stores are visible to any
+ * reader that observes a non-NULL pointer in pt_vp_array.
+ */
+ smp_store_release(&partition->pt_vp_array[args.vp_index], vp);
+
+ /*
+ * fd_install() is the userspace-visibility commit point. Must be the
+ * last operation that can fail or be observed.
+ */
+ fd_install(fd, file);
+ ret = fd;
goto out;
+put_unused_vp_fd:
+ put_unused_fd(fd);
remove_debugfs_vp:
mshv_debugfs_vp_remove(vp);
put_partition:
diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c
index 0d3d4161974f..6e3c11c68171 100644
--- a/drivers/hv/mshv_vtl_main.c
+++ b/drivers/hv/mshv_vtl_main.c
@@ -129,6 +129,7 @@ mshv_ioctl_create_vtl(void __user *user_arg, struct device *module_dev)
file = anon_inode_getfile("mshv_vtl", &mshv_vtl_fops,
vtl, O_RDWR);
if (IS_ERR(file)) {
+ put_unused_fd(fd);
kfree(vtl);
return PTR_ERR(file);
}
@@ -801,7 +802,7 @@ static vm_fault_t mshv_vtl_fault(struct vm_fault *vmf)
int cpu = vmf->pgoff & MSHV_PG_OFF_CPU_MASK;
int real_off = vmf->pgoff >> MSHV_REAL_OFF_SHIFT;
- if (!cpu_online(cpu))
+ if (cpu >= nr_cpu_ids || !cpu_online(cpu))
return VM_FAULT_SIGBUS;
/*
* CPU Hotplug is not supported in VTL2 in OpenHCL, where this kernel driver exists.
@@ -1148,12 +1149,22 @@ static int mshv_vtl_hvcall_call(struct mshv_vtl_hvcall_fd *fd,
*/
in = (void *)__get_free_page(GFP_KERNEL);
out = (void *)__get_free_page(GFP_KERNEL);
+ if (!in || !out) {
+ ret = -ENOMEM;
+ goto free_pages;
+ }
if (copy_from_user(in, (void __user *)hvcall.input_ptr, hvcall.input_size)) {
ret = -EFAULT;
goto free_pages;
}
+ /*
+ * The caller supplies output_size, so clear the range copied back to
+ * userspace in case the hypercall writes fewer bytes than requested.
+ */
+ memset(out, 0, hvcall.output_size);
+
hvcall.status = hv_do_hypercall(hvcall.control, in, out);
if (copy_to_user((void __user *)hvcall.output_ptr, out, hvcall.output_size)) {
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 23206640c613..6824bd7cb3c4 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1369,8 +1369,6 @@ static void run_vmbus_irqd(unsigned int cpu)
__vmbus_isr();
}
-static bool vmbus_irq_initialized;
-
static struct smp_hotplug_thread vmbus_irq_threads = {
.store = &vmbus_irqd,
.setup = vmbus_irqd_setup,
@@ -1384,8 +1382,19 @@ void vmbus_isr(void)
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
vmbus_irqd_wake();
} else {
- lockdep_hardirq_threaded();
+ static DEFINE_WAIT_OVERRIDE_MAP(vmbus_map, LD_WAIT_CONFIG);
+
+ /*
+ * vmbus_isr is never force-threaded and always invoked at hard
+ * IRQ level. __vmbus_isr() below can acquire a spinlock_t
+ * which becomes a sleeping lock and must not be acquired in
+ * this context. Therefore on PREEMPT_RT this will be threaded
+ * via vmbus_irqd_wake(). On non-PREEMPT the annotation lets
+ * lockdep know that acquiring a spinlock_t is not an issue.
+ */
+ lock_map_acquire_try(&vmbus_map);
__vmbus_isr();
+ lock_map_release(&vmbus_map);
}
}
EXPORT_SYMBOL_FOR_MODULES(vmbus_isr, "mshv_vtl");
@@ -1486,11 +1495,10 @@ static int vmbus_bus_init(void)
* the VMbus interrupt handler.
*/
- if (IS_ENABLED(CONFIG_PREEMPT_RT) && !vmbus_irq_initialized) {
+ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
ret = smpboot_register_percpu_thread(&vmbus_irq_threads);
if (ret)
goto err_kthread;
- vmbus_irq_initialized = true;
}
if (vmbus_irq == -1) {
@@ -1534,10 +1542,8 @@ err_connect:
else
free_percpu_irq(vmbus_irq, &vmbus_evt);
err_setup:
- if (IS_ENABLED(CONFIG_PREEMPT_RT) && vmbus_irq_initialized) {
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
smpboot_unregister_percpu_thread(&vmbus_irq_threads);
- vmbus_irq_initialized = false;
- }
err_kthread:
bus_unregister(&hv_bus);
return ret;
@@ -2169,6 +2175,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
child_device_obj->device.dma_mask = &child_device_obj->dma_mask;
dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64));
+ dma_set_coherent_mask(&child_device_obj->device, DMA_BIT_MASK(64));
/*
* Register with the LDM. This will kick off the driver/device
@@ -3034,10 +3041,9 @@ static void __exit vmbus_exit(void)
hv_remove_vmbus_handler();
else
free_percpu_irq(vmbus_irq, &vmbus_evt);
- if (IS_ENABLED(CONFIG_PREEMPT_RT) && vmbus_irq_initialized) {
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
smpboot_unregister_percpu_thread(&vmbus_irq_threads);
- vmbus_irq_initialized = false;
- }
+
for_each_online_cpu(cpu) {
struct hv_per_cpu_context *hv_cpu
= per_cpu_ptr(hv_context.cpu_context, cpu);
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 664349756dc2..c45b984c02e6 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -70,8 +70,8 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
#define ADT7470_PWM1_AUTO_MASK 0x80
#define ADT7470_PWM_AUTO_MASK 0xC0
#define ADT7470_REG_PWM34_CFG 0x69
-#define ADT7470_PWM3_AUTO_MASK 0x40
-#define ADT7470_PWM4_AUTO_MASK 0x80
+#define ADT7470_PWM4_AUTO_MASK 0x40
+#define ADT7470_PWM3_AUTO_MASK 0x80
#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A
#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D
#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
@@ -110,6 +110,21 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
#define ALARM2(x) ((x) << 8)
+/* TEMP1..TEMP7 (ch 0..6) are, respectively BIT(0)..BIT(6) of reg 0x41 and
+ * 0x72, or BIT(0)..BIT(6) of data->alarm.
+ * TEMP8..TEMP9 (ch 7..9) are, respectively BIT(0)..BIT(2) of reg 0x42 and
+ * 0x73, or BIT(8)..BIT(10) of data->alarm.
+ */
+#define TEMP_ALARM_BIT(ch) ({ \
+ typeof(ch) _ch = (ch); \
+ (1 << (_ch < 7 ? _ch : _ch + 1)); \
+})
+
+/* FAN1..FAN4 (ch 0..3) are respectively BIT(4)..BIT(7) in
+ * reg 0x42 and 0x73 or BIT(12)..BIT(15) in data->alarm.
+ */
+#define FAN_ALARM_BIT(ch) (1 << (12 + (ch)))
+
#define ADT7470_VENDOR 0x41
#define ADT7470_DEVICE 0x70
/* datasheet only mentions a revision 2 */
@@ -167,6 +182,7 @@ struct adt7470_data {
u8 pwm_min[ADT7470_PWM_COUNT];
s8 pwm_tmin[ADT7470_PWM_COUNT];
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
+ u32 pwm_freq;
struct task_struct *auto_update;
unsigned int auto_update_interval;
@@ -205,11 +221,12 @@ static inline int adt7470_write_word_data(struct adt7470_data *data, unsigned in
/* Probe for temperature sensors. Assumes lock is held */
static int adt7470_read_temperatures(struct adt7470_data *data)
{
- unsigned long res;
+ struct device *dev = regmap_get_device(data->regmap);
+ u8 pwm[ADT7470_FAN_COUNT];
unsigned int pwm_cfg[2];
- int err;
+ unsigned long res;
+ int err, err2;
int i;
- u8 pwm[ADT7470_FAN_COUNT];
/* save pwm[1-4] config register */
err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(0), &pwm_cfg[0]);
@@ -233,19 +250,19 @@ static int adt7470_read_temperatures(struct adt7470_data *data)
err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(2),
ADT7470_PWM_AUTO_MASK, 0);
if (err < 0)
- return err;
+ goto out_restore;
/* write pwm control to whatever it was */
err = regmap_bulk_write(data->regmap, ADT7470_REG_PWM(0), &pwm[0],
ADT7470_PWM_COUNT);
if (err < 0)
- return err;
+ goto out_restore;
/* start reading temperature sensors */
err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
ADT7470_T05_STB_MASK, ADT7470_T05_STB_MASK);
if (err < 0)
- return err;
+ goto out_restore;
/* Delay is 200ms * number of temp sensors. */
res = msleep_interruptible((data->num_temp_sensors >= 0 ?
@@ -256,13 +273,30 @@ static int adt7470_read_temperatures(struct adt7470_data *data)
err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
ADT7470_T05_STB_MASK, 0);
if (err < 0)
- return err;
+ goto out_restore;
+out_restore:
/* restore pwm[1-4] config registers */
- err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
- if (err < 0)
- return err;
- err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+ err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
+ if (err2 < 0) {
+ dev_warn_ratelimited(dev,
+ "failed to restore PWM{1,2} config (%d)\n",
+ err2);
+
+ if (!err)
+ err = err2;
+ }
+
+ err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+ if (err2 < 0) {
+ dev_warn_ratelimited(dev,
+ "failed to restore PWM{3,4} config (%d)\n",
+ err2);
+
+ if (!err)
+ err = err2;
+ }
+
if (err < 0)
return err;
@@ -491,7 +525,7 @@ static ssize_t auto_update_interval_store(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = clamp_val(temp, 0, 60000);
+ temp = clamp_val(temp, 500, 60000);
mutex_lock(&data->lock);
data->auto_update_interval = temp;
@@ -551,7 +585,7 @@ static int adt7470_temp_read(struct device *dev, u32 attr, int channel, long *va
*val = 1000 * data->temp_max[channel];
break;
case hwmon_temp_alarm:
- *val = !!(data->alarm & channel);
+ *val = !!(data->alarm & TEMP_ALARM_BIT(channel));
break;
default:
return -EOPNOTSUPP;
@@ -571,14 +605,16 @@ static int adt7470_temp_write(struct device *dev, u32 attr, int channel, long va
switch (attr) {
case hwmon_temp_min:
mutex_lock(&data->lock);
- data->temp_min[channel] = val;
err = regmap_write(data->regmap, ADT7470_TEMP_MIN_REG(channel), val);
+ if (!err)
+ data->temp_min[channel] = val;
mutex_unlock(&data->lock);
break;
case hwmon_temp_max:
mutex_lock(&data->lock);
- data->temp_max[channel] = val;
err = regmap_write(data->regmap, ADT7470_TEMP_MAX_REG(channel), val);
+ if (!err)
+ data->temp_max[channel] = val;
mutex_unlock(&data->lock);
break;
default:
@@ -624,36 +660,33 @@ static ssize_t alarm_mask_store(struct device *dev,
static int adt7470_fan_read(struct device *dev, u32 attr, int channel, long *val)
{
struct adt7470_data *data = adt7470_update_device(dev);
+ u16 fan_data;
if (IS_ERR(data))
return PTR_ERR(data);
switch (attr) {
case hwmon_fan_input:
- if (FAN_DATA_VALID(data->fan[channel]))
- *val = FAN_PERIOD_TO_RPM(data->fan[channel]);
- else
- *val = 0;
+ fan_data = READ_ONCE(data->fan[channel]);
break;
case hwmon_fan_min:
- if (FAN_DATA_VALID(data->fan_min[channel]))
- *val = FAN_PERIOD_TO_RPM(data->fan_min[channel]);
- else
- *val = 0;
+ fan_data = READ_ONCE(data->fan_min[channel]);
break;
case hwmon_fan_max:
- if (FAN_DATA_VALID(data->fan_max[channel]))
- *val = FAN_PERIOD_TO_RPM(data->fan_max[channel]);
- else
- *val = 0;
+ fan_data = READ_ONCE(data->fan_max[channel]);
break;
case hwmon_fan_alarm:
- *val = !!(data->alarm & (1 << (12 + channel)));
- break;
+ *val = !!(data->alarm & FAN_ALARM_BIT(channel));
+ return 0;
default:
return -EOPNOTSUPP;
}
+ if (FAN_DATA_VALID(fan_data))
+ *val = FAN_PERIOD_TO_RPM(fan_data);
+ else
+ *val = 0;
+
return 0;
}
@@ -721,7 +754,7 @@ static ssize_t force_pwm_max_store(struct device *dev,
}
/* These are the valid PWM frequencies to the nearest Hz */
-static const int adt7470_freq_map[] = {
+static const u32 adt7470_freq_map[] = {
11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
};
@@ -761,7 +794,7 @@ static int adt7470_pwm_read(struct device *dev, u32 attr, int channel, long *val
*val = 1 + data->pwm_automatic[channel];
break;
case hwmon_pwm_freq:
- *val = pwm1_freq_get(dev);
+ *val = data->pwm_freq;
break;
default:
return -EOPNOTSUPP;
@@ -774,12 +807,14 @@ static int pwm1_freq_set(struct device *dev, long freq)
{
struct adt7470_data *data = dev_get_drvdata(dev);
unsigned int low_freq = ADT7470_CFG_LF;
+ u32 closest_freq;
int index;
int err;
/* Round the user value given to the closest available frequency */
index = find_closest(freq, adt7470_freq_map,
ARRAY_SIZE(adt7470_freq_map));
+ closest_freq = adt7470_freq_map[index];
if (index >= 8) {
index -= 8;
@@ -797,6 +832,10 @@ static int pwm1_freq_set(struct device *dev, long freq)
err = regmap_update_bits(data->regmap, ADT7470_REG_CFG_2,
ADT7470_FREQ_MASK,
index << ADT7470_FREQ_SHIFT);
+ if (err < 0)
+ goto out;
+
+ data->pwm_freq = closest_freq;
out:
mutex_unlock(&data->lock);
@@ -813,9 +852,10 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val
case hwmon_pwm_input:
val = clamp_val(val, 0, 255);
mutex_lock(&data->lock);
- data->pwm[channel] = val;
err = regmap_write(data->regmap, ADT7470_REG_PWM(channel),
- data->pwm[channel]);
+ val);
+ if (!err)
+ data->pwm[channel] = val;
mutex_unlock(&data->lock);
break;
case hwmon_pwm_enable:
@@ -829,10 +869,11 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val
val--;
mutex_lock(&data->lock);
- data->pwm_automatic[channel] = val;
err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(channel),
pwm_auto_reg_mask,
val ? pwm_auto_reg_mask : 0);
+ if (!err)
+ data->pwm_automatic[channel] = val;
mutex_unlock(&data->lock);
break;
case hwmon_pwm_freq:
@@ -1008,8 +1049,10 @@ static ssize_t pwm_auto_temp_store(struct device *dev,
if (temp < 0)
return temp;
+ if (temp > 0xF)
+ return -EINVAL;
+
mutex_lock(&data->lock);
- data->pwm_automatic[attr->index] = temp;
if (!(attr->index % 2)) {
mask = 0xF0;
@@ -1020,6 +1063,9 @@ static ssize_t pwm_auto_temp_store(struct device *dev,
}
err = regmap_update_bits(data->regmap, pwm_auto_reg, mask, val);
+ if (!err)
+ data->pwm_auto_temp[attr->index] = temp;
+
mutex_unlock(&data->lock);
return err < 0 ? err : count;
@@ -1248,6 +1294,7 @@ static int adt7470_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct adt7470_data *data;
struct device *hwmon_dev;
+ int freq_val;
int err;
data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL);
@@ -1272,6 +1319,14 @@ static int adt7470_probe(struct i2c_client *client)
if (err < 0)
return err;
+ freq_val = pwm1_freq_get(dev);
+ if (freq_val <= 0) {
+ err = freq_val < 0 ? freq_val : -EINVAL;
+ return err;
+ }
+
+ data->pwm_freq = (u32)freq_val;
+
/* Register sysfs hooks */
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
&adt7470_chip_info,
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index c4742e84b999..449a72c6b40b 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -16,6 +16,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/limits.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -266,30 +267,34 @@ static u16 ina226_interval_to_reg(long interval)
return FIELD_PREP(INA226_AVG_RD_MASK, avg_bits);
}
-static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
- unsigned int regval)
+static long ina2xx_get_value(struct ina2xx_data *data, u8 reg,
+ unsigned int regval)
{
- int val;
+ s64 val64;
+ long val;
switch (reg) {
case INA2XX_SHUNT_VOLTAGE:
/* signed register */
- val = (s16)regval >> data->config->shunt_voltage_shift;
- val = DIV_ROUND_CLOSEST(val, data->config->shunt_div);
+ val = DIV_ROUND_CLOSEST((s16)regval >> data->config->shunt_voltage_shift,
+ data->config->shunt_div);
break;
case INA2XX_BUS_VOLTAGE:
- val = (regval >> data->config->bus_voltage_shift) *
- data->config->bus_voltage_lsb;
- val = DIV_ROUND_CLOSEST(val, 1000);
+ val = DIV_ROUND_CLOSEST((regval >> data->config->bus_voltage_shift) *
+ data->config->bus_voltage_lsb, 1000);
break;
case INA2XX_POWER:
- val = regval * data->power_lsb_uW;
+ val = min_t(u64, (u64)regval * data->power_lsb_uW, LONG_MAX);
break;
case INA2XX_CURRENT:
/* signed register, result in mA */
- val = ((s16)regval >> data->config->current_shift) *
+ val64 = (s64)((s16)regval >> data->config->current_shift) *
data->current_lsb_uA;
- val = DIV_ROUND_CLOSEST(val, 1000);
+ if (val64 < 0)
+ val64 = -DIV_ROUND_CLOSEST_ULL(-val64, 1000);
+ else
+ val64 = DIV_ROUND_CLOSEST_ULL(val64, 1000);
+ val = clamp_val(val64, LONG_MIN, LONG_MAX);
break;
case INA2XX_CALIBRATION:
val = regval;
@@ -378,27 +383,29 @@ static int ina2xx_read_init(struct device *dev, int reg, long *val)
*/
static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
{
+ long limit;
+
switch (reg) {
case INA2XX_SHUNT_VOLTAGE:
- val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div);
- val *= data->config->shunt_div;
- val <<= data->config->shunt_voltage_shift;
- return clamp_val(val, 0, SHRT_MAX);
+ val = min_t(long, val, DIV_ROUND_CLOSEST(SHRT_MAX, data->config->shunt_div));
+ return min_t(long, (val * data->config->shunt_div) << data->config->shunt_voltage_shift,
+ SHRT_MAX);
case INA2XX_BUS_VOLTAGE:
- val = clamp_val(val, 0, 200000);
- val = (val * 1000) << data->config->bus_voltage_shift;
- val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb);
- return clamp_val(val, 0, USHRT_MAX);
+ val = min_t(long, val, 130000);
+ return min_t(long,
+ DIV_ROUND_CLOSEST((val * 1000) << data->config->bus_voltage_shift,
+ data->config->bus_voltage_lsb),
+ USHRT_MAX);
case INA2XX_POWER:
- val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
- val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW);
- return clamp_val(val, 0, USHRT_MAX);
+ val = min_t(long, val, LONG_MAX - data->power_lsb_uW);
+ return min_t(long, DIV_ROUND_CLOSEST(val, data->power_lsb_uW), USHRT_MAX);
case INA2XX_CURRENT:
- val = clamp_val(val, INT_MIN / 1000, INT_MAX / 1000);
+ limit = (LONG_MAX - (data->current_lsb_uA / 2)) / 1000;
+ val = min_t(long, val, limit);
/* signed register, result in mA */
val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_uA);
- val <<= data->config->current_shift;
- return clamp_val(val, SHRT_MIN, SHRT_MAX);
+ limit = SHRT_MAX >> data->config->current_shift;
+ return (u16)(min_t(long, val, limit) << data->config->current_shift);
default:
/* programmer goofed */
WARN_ON_ONCE(1);
@@ -537,6 +544,7 @@ static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *va
u8 template[6];
int ret;
long accumulator_24, sample_count;
+ u64 val64;
/* 48-bit register read */
ret = i2c_smbus_read_i2c_block_data(data->client, reg, 6, template);
@@ -555,7 +563,8 @@ static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *va
return 0;
}
- *val = DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW;
+ val64 = (u64)DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW;
+ *val = min_t(u64, val64, LONG_MAX);
return 0;
}
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index e2a429e579ac..da09770c05e7 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -247,8 +247,7 @@ static struct lm63_data *lm63_update_device(struct device *dev)
LM63_REG_TACH_LIMIT_MSB) << 8);
}
- data->pwm1_freq = i2c_smbus_read_byte_data(client,
- LM63_REG_PWM_FREQ);
+ data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ) & 0x1f;
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
data->pwm1[0] = i2c_smbus_read_byte_data(client,
@@ -1187,7 +1186,7 @@ static void lm63_init_client(struct lm63_data *data)
data->config |= 0x04;
/* We may need pwm1_freq before ever updating the client data */
- data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+ data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ) & 0x1f;
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 4b9c0ccdf260..c6186505661f 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1194,7 +1194,7 @@ static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
check_enable = (client->irq || !(data->config_orig & 0x80)) &&
(data->config & 0x80);
- if (force || check_enable)
+ if (data->hwmon_dev && (force || check_enable))
schedule_work(&data->report_work);
/*
@@ -1202,7 +1202,7 @@ static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
* alarms are all clear, and alerts are currently disabled.
* Otherwise (re)schedule worker if needed.
*/
- if (check_enable) {
+ if (check_enable && data->hwmon_dev) {
if (!(data->current_alarms & data->alert_alarms)) {
dev_dbg(&client->dev, "Re-enabling ALERT#\n");
lm90_update_confreg(data, data->config & ~0x80);
diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
index 39b9d3abca99..cc698803f8bf 100644
--- a/drivers/hwmon/ltc4282.c
+++ b/drivers/hwmon/ltc4282.c
@@ -374,8 +374,8 @@ static int ltc4282_read_in(struct ltc4282_state *st, u32 attr, long *val,
channel, val);
case hwmon_in_min_alarm:
if (channel == LTC4282_CHAN_VGPIO)
- ltc4282_read_alarm(st, LTC4282_ADC_ALERT_LOG,
- LTC4282_GPIO_ALARM_L_MASK, val);
+ return ltc4282_read_alarm(st, LTC4282_ADC_ALERT_LOG,
+ LTC4282_GPIO_ALARM_L_MASK, val);
return ltc4282_vdd_source_read_alm(st,
LTC4282_VSOURCE_ALARM_L_MASK,
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index d668dc390def..94482c8092cd 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -791,12 +791,12 @@ static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
-static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
-static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
-static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
-static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
-static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
-static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c, 0, 0 };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d, 0, 0 };
static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
@@ -846,8 +846,6 @@ static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
-static const u16 NCT6116_REG_TEMP_SOURCE[] = {
- 0xb0, 0xb1, 0xb2 };
static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
@@ -3652,7 +3650,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
= NCT6106_CRITICAL_PWM_ENABLE_MASK;
data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
- data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
+ data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
@@ -3666,13 +3664,13 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp = NCT6106_REG_TEMP;
reg_temp_mon = NCT6106_REG_TEMP_MON;
- num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+ num_reg_temp = 3;
num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
num_reg_tsi_temp = ARRAY_SIZE(NCT6116_REG_TSI_TEMP);
reg_temp_over = NCT6106_REG_TEMP_OVER;
reg_temp_hyst = NCT6106_REG_TEMP_HYST;
reg_temp_config = NCT6106_REG_TEMP_CONFIG;
- num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
+ num_reg_temp_config = 3;
reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6106_REG_TEMP_CRIT;
reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c
index aea0b8659f5f..6ff2a6bc06c1 100644
--- a/drivers/hwmon/npcm750-pwm-fan.c
+++ b/drivers/hwmon/npcm750-pwm-fan.c
@@ -358,6 +358,11 @@ static void npcm7xx_fan_polling(struct timer_list *t)
add_timer(&data->fan_timer);
}
+static void npcm7xx_fan_cleanup(void *timer)
+{
+ timer_shutdown_sync(timer);
+}
+
static inline void npcm7xx_fan_compute(struct npcm7xx_pwm_fan_data *data,
u8 fan, u8 cmp, u8 fan_id, u8 flag_int,
u8 flag_mode, u8 flag_clear)
@@ -1020,6 +1025,12 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
msecs_to_jiffies(NPCM7XX_FAN_POLL_TIMER_200MS);
timer_setup(&data->fan_timer,
npcm7xx_fan_polling, 0);
+ ret = devm_add_action_or_reset(dev,
+ npcm7xx_fan_cleanup,
+ &data->fan_timer);
+ if (ret)
+ return ret;
+
add_timer(&data->fan_timer);
break;
}
diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
index e2316c46629d..ff0c0bee0e83 100644
--- a/drivers/hwmon/nzxt-smart2.c
+++ b/drivers/hwmon/nzxt-smart2.c
@@ -203,7 +203,7 @@ struct drvdata {
*/
struct mutex mutex;
long update_interval;
- u8 output_buffer[OUTPUT_REPORT_SIZE];
+ u8 output_buffer[OUTPUT_REPORT_SIZE] __aligned(ARCH_DMA_MINALIGN);
};
static long scale_pwm_value(long val, long orig_max, long new_max)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 3143b9e0316c..5567d37f13fe 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -513,7 +513,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
if (tmp != rv)
rv = _pmbus_write_byte_data(client, page, reg, tmp);
- return rv;
+ return rv < 0 ? rv : 0;
}
EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, "PMBUS");
@@ -2985,8 +2985,9 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
if (reg == sreg && page == spage && (smask & flags)) {
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
- sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
- kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
+ sysfs_notify(&data->hwmon_dev->kobj, NULL,
+ da->attr.name);
+ kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
flags &= ~smask;
}
diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c
index c2f6b73aa7f3..4d90f89a9929 100644
--- a/drivers/hwmon/sht3x.c
+++ b/drivers/hwmon/sht3x.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
+#include <linux/unaligned.h>
/* commands (high repeatability mode) */
static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 };
@@ -276,9 +277,9 @@ static struct sht3x_data *sht3x_update_client(struct device *dev)
if (ret)
goto out;
- val = be16_to_cpup((__be16 *)buf);
+ val = get_unaligned_be16(buf);
data->temperature = sht3x_extract_temperature(val);
- val = be16_to_cpup((__be16 *)(buf + 3));
+ val = get_unaligned_be16(buf + 3);
data->humidity = sht3x_extract_humidity(val);
data->last_update = jiffies;
}
@@ -336,7 +337,7 @@ static int limits_update(struct sht3x_data *data)
if (ret)
return ret;
- raw = be16_to_cpup((__be16 *)buffer);
+ raw = get_unaligned_be16(buffer);
temperature = sht3x_extract_temperature((raw & 0x01ff) << 7);
humidity = sht3x_extract_humidity(raw & 0xfe00);
data->temperature_limits[index] = temperature;
@@ -389,7 +390,7 @@ static size_t limit_write(struct device *dev,
raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7);
raw |= ((humidity * 42950) >> 16) & 0xfe00;
- *((__be16 *)position) = cpu_to_be16(raw);
+ put_unaligned_be16(raw, position);
position += SHT3X_WORD_LEN;
*position = crc8(sht3x_crc8_table,
position - SHT3X_WORD_LEN,
diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c
index 188e24cc4d35..9fdd6a5fb8b6 100644
--- a/drivers/i2c/busses/i2c-amd-mp2-plat.c
+++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c
@@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platform_device *pdev)
amd_mp2_pm_runtime_put(mp2_dev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
+ amd_mp2_unregister_cb(&i2c_dev->common);
+ }
return ret;
}
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index b5629cffe99b..86ca4c2221c4 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -803,6 +803,17 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
}
if (!time_left && !iproc_i2c->xfer_is_done) {
+ /*
+ * The controller may fail to clear START_BUSY after a timeout,
+ * reset the controller to recover in that case.
+ */
+ if (!!(iproc_i2c_rd_reg(iproc_i2c, M_CMD_OFFSET) &
+ BIT(M_CMD_START_BUSY_SHIFT))) {
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+ bcm_iproc_i2c_init(iproc_i2c);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+ }
+
/* flush both TX/RX FIFOs */
val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 6d6e81242f74..c8a203fff4d1 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -8,12 +8,14 @@
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*/
+#include <linux/acpi.h>
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -130,6 +132,80 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return 0;
}
+#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
+/*
+ * Check whether an ACPI GpioInt resource's referenced GPIO controller
+ * has finished probing. Resources with no named controller (resource
+ * source string) are skipped, since they can't be resolved to a
+ * struct device.
+ */
+static int check_gpioint_resource(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_gpio *agpio;
+ struct acpi_device *gpio_adev;
+ struct device *gpio_dev;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!acpi_gpio_get_irq_resource(ares, &agpio))
+ return 1; /* not a GpioInt resource, skip */
+
+ if (!agpio->resource_source.string_length)
+ return 1; /* no named controller, skip */
+
+ status = acpi_get_handle(NULL, agpio->resource_source.string_ptr, &handle);
+ if (ACPI_FAILURE(status))
+ return 1;
+
+ gpio_adev = acpi_fetch_acpi_dev(handle);
+ if (!gpio_adev)
+ return 1;
+
+ struct gpio_device *gdev __free(gpio_device_put) =
+ gpio_device_find_by_fwnode(acpi_fwnode_handle(gpio_adev));
+ if (!gdev)
+ return -EPROBE_DEFER; /* controller not registered yet: abort walk */
+
+ gpio_dev = gpio_device_to_device(gdev)->parent;
+
+ guard(device)(gpio_dev);
+ if (!device_is_bound(gpio_dev))
+ return -EPROBE_DEFER; /* controller not bound yet: abort walk */
+
+ return 1; /* bound, skip adding to resource list, continue walk */
+}
+
+static int check_child_gpioint(struct acpi_device *adev, void *data)
+{
+ LIST_HEAD(res_list);
+ int ret;
+
+ ret = acpi_dev_get_resources(adev, &res_list, check_gpioint_resource, NULL);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&res_list);
+
+ return 0;
+}
+
+static int i2c_dw_check_gpio_dependencies(struct device *dev)
+{
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return 0;
+
+ return acpi_dev_for_each_child(adev, check_child_gpioint, NULL);
+}
+#else
+static int i2c_dw_check_gpio_dependencies(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_ACPI && CONFIG_GPIOLIB */
+
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
u32 flags = (uintptr_t)device_get_match_data(&pdev->dev);
@@ -138,6 +214,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
struct dw_i2c_dev *dev;
int irq, ret;
+ ret = i2c_dw_check_gpio_dependencies(device);
+ if (ret)
+ return ret;
+
irq = platform_get_irq_optional(pdev, 0);
if (irq == -ENXIO)
flags |= ACCESS_POLLING;
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d5e6e2eca3b3..9477d814fde9 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
if (i2c_imx->slave)
return -EBUSY;
- i2c_imx->slave = client;
- i2c_imx->last_slave_event = I2C_SLAVE_STOP;
-
/* Resume */
ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (ret < 0) {
@@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
return ret;
}
+ scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
+ i2c_imx->slave = client;
+ i2c_imx->last_slave_event = I2C_SLAVE_STOP;
+ }
+
i2c_imx_slave_init(i2c_imx);
return 0;
@@ -958,6 +960,7 @@ static int i2c_imx_unreg_slave(struct i2c_client *client)
i2c_imx_reset_regs(i2c_imx);
+ hrtimer_cancel(&i2c_imx->slave_timer);
i2c_imx->slave = NULL;
/* Suspend */
@@ -1952,6 +1955,47 @@ static int i2c_imx_runtime_resume(struct device *dev)
return 0;
}
+static int __maybe_unused i2c_imx_suspend_noirq(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ i2c_mark_adapter_suspended(&i2c_imx->adapter);
+
+ /*
+ * Cancel the slave timer before powering down to prevent
+ * i2c_imx_slave_timeout() from accessing hardware registers
+ * while the clock is disabled.
+ */
+ hrtimer_cancel(&i2c_imx->slave_timer);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ i2c_mark_adapter_resumed(&i2c_imx->adapter);
+ if (i2c_imx->slave) {
+ hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY);
+ hrtimer_restart(&i2c_imx->slave_timer);
+ }
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused i2c_imx_resume_noirq(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ i2c_mark_adapter_resumed(&i2c_imx->adapter);
+
+ return 0;
+}
+
static int i2c_imx_suspend(struct device *dev)
{
/*
@@ -1985,8 +2029,8 @@ static int i2c_imx_resume(struct device *dev)
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
- NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend_noirq,
+ i2c_imx_resume_noirq)
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
};
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
index 664a5471d933..695be3b21460 100644
--- a/drivers/i2c/busses/i2c-jz4780.c
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -141,6 +141,7 @@ struct jz4780_i2c {
void __iomem *iomem;
int irq;
struct clk *clk;
+ unsigned long clk_rate_khz;
struct i2c_adapter adap;
const struct ingenic_i2c_config *cdata;
@@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
{
- int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
+ int dev_clk_khz = i2c->clk_rate_khz;
int cnt_high = 0; /* HIGH period count of the SCL clock */
int cnt_low = 0; /* LOW period count of the SCL clock */
int cnt_period = 0; /* period count of the SCL clock */
@@ -796,6 +797,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->clk))
return PTR_ERR(i2c->clk);
+ i2c->clk_rate_khz = clk_get_rate(i2c->clk) / 1000;
+
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&clk_freq);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
index 51a0c3d80fc9..3fe716cc153d 100644
--- a/drivers/i2c/busses/i2c-k1.c
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -723,11 +723,6 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
if (i2c->irq < 0)
return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
- ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
- IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
- if (ret)
- return dev_err_probe(dev, ret, "failed to request irq");
-
clk = devm_clk_get_enabled(dev, "func");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
@@ -755,6 +750,11 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
init_completion(&i2c->complete);
+ ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
+ IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request irq");
+
platform_set_drvdata(pdev, i2c);
ret = i2c_add_numbered_adapter(&i2c->adapt);
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index 4d64895a9e9e..bdeda3979c48 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -492,24 +492,8 @@ static int __maybe_unused cci_resume_runtime(struct device *dev)
return 0;
}
-static int __maybe_unused cci_suspend(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- return cci_suspend_runtime(dev);
-
- return 0;
-}
-
-static int __maybe_unused cci_resume(struct device *dev)
-{
- cci_resume_runtime(dev);
- pm_request_autosuspend(dev);
-
- return 0;
-}
-
static const struct dev_pm_ops qcom_cci_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL)
};
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index 1e9f7d2de344..85ebfdb3d2a7 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -297,6 +297,20 @@ unlock:
return ret;
}
+static int arm_vsmmu_vdevice_init(struct iommufd_vdevice *vdev)
+{
+ struct device *dev = iommufd_vdevice_to_device(vdev);
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+ /*
+ * arm_vsmmu_vsid_to_sid() maps a vSID to master->streams[0] alone, so
+ * more streams would leave the rest stale and none reads out of bounds.
+ */
+ if (master->num_streams != 1)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
/* This is basically iommu_viommu_arm_smmuv3_invalidate in u64 for conversion */
struct arm_vsmmu_invalidation_cmd {
union {
@@ -403,6 +417,7 @@ out:
static const struct iommufd_viommu_ops arm_vsmmu_ops = {
.alloc_domain_nested = arm_vsmmu_alloc_domain_nested,
.cache_invalidate = arm_vsmmu_cache_invalidate,
+ .vdevice_init = arm_vsmmu_vdevice_init,
};
size_t arm_smmu_get_viommu_size(struct device *dev,
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index cca52a34d0ed..c16ff1fc4b95 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -332,17 +332,31 @@ void iopf_group_response(struct iopf_group *group,
.code = status,
};
- /* Only send response if there is a fault report pending */
mutex_lock(&fault_param->lock);
- if (!list_empty(&group->pending_node)) {
- ops->page_response(dev, &group->last_fault, &resp);
- list_del_init(&group->pending_node);
- }
+ ops->page_response(dev, &group->last_fault, &resp);
+ list_del_init(&group->pending_node);
mutex_unlock(&fault_param->lock);
}
EXPORT_SYMBOL_GPL(iopf_group_response);
/**
+ * iopf_group_dequeue - Dequeue a page fault group from the pending list
+ * @group: the group to dequeue
+ *
+ * The fault handler is responsible for responding to the group after
+ * this function returns.
+ */
+void iopf_group_dequeue(struct iopf_group *group)
+{
+ struct iommu_fault_param *fault_param = group->fault_param;
+
+ mutex_lock(&fault_param->lock);
+ list_del_init(&group->pending_node);
+ mutex_unlock(&fault_param->lock);
+}
+EXPORT_SYMBOL_GPL(iopf_group_dequeue);
+
+/**
* iopf_queue_discard_partial - Remove all pending partial fault
* @queue: the queue whose partial faults need to be discarded
*
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 170a7005f0bc..2895e5370910 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -589,7 +589,7 @@ static int iommufd_hwpt_replace_device(struct iommufd_device *idev,
if (rc)
goto out_free_handle;
- iommufd_auto_response_faults(hwpt, old_handle);
+ iommufd_auto_response_faults(old, old_handle);
kfree(old_handle);
return 0;
diff --git a/drivers/iommu/iommufd/eventq.c b/drivers/iommu/iommufd/eventq.c
index 5129e3bf5461..747dd5155121 100644
--- a/drivers/iommu/iommufd/eventq.c
+++ b/drivers/iommu/iommufd/eventq.c
@@ -484,6 +484,8 @@ int iommufd_fault_iopf_handler(struct iopf_group *group)
hwpt = group->attach_handle->domain->iommufd_hwpt;
fault = hwpt->fault;
+ iopf_group_dequeue(group);
+
spin_lock(&fault->common.lock);
list_add_tail(&group->node, &fault->common.deliver);
spin_unlock(&fault->common.lock);
diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c
index 03c8379bbc34..404f31d8f729 100644
--- a/drivers/iommu/iommufd/pages.c
+++ b/drivers/iommu/iommufd/pages.c
@@ -2451,6 +2451,9 @@ int iopt_area_add_access(struct iopt_area *area, unsigned long start_index,
if ((flags & IOMMUFD_ACCESS_RW_WRITE) && !pages->writable)
return -EPERM;
+ if (iopt_is_dmabuf(pages))
+ return -EINVAL;
+
mutex_lock(&pages->mutex);
access = iopt_pages_get_exact_access(pages, start_index, last_index);
if (access) {
diff --git a/drivers/iommu/iommufd/viommu.c b/drivers/iommu/iommufd/viommu.c
index 4081deda9b33..fc13cf4737ea 100644
--- a/drivers/iommu/iommufd/viommu.c
+++ b/drivers/iommu/iommufd/viommu.c
@@ -143,7 +143,7 @@ void iommufd_vdevice_destroy(struct iommufd_object *obj)
int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd)
{
struct iommu_vdevice_alloc *cmd = ucmd->cmd;
- struct iommufd_vdevice *vdev, *curr;
+ struct iommufd_vdevice *vdev;
size_t vdev_size = sizeof(*vdev);
struct iommufd_viommu *viommu;
struct iommufd_device *idev;
@@ -189,7 +189,7 @@ int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd)
if (WARN_ON_ONCE(viommu->ops->vdevice_size < vdev_size ||
!viommu->ops->vdevice_init)) {
rc = -EOPNOTSUPP;
- goto out_put_idev;
+ goto out_unlock_igroup;
}
vdev_size = viommu->ops->vdevice_size;
}
@@ -218,18 +218,28 @@ int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd)
*/
idev->vdev = vdev;
- curr = xa_cmpxchg(&viommu->vdevs, virt_id, NULL, vdev, GFP_KERNEL);
- if (curr) {
- rc = xa_err(curr) ?: -EEXIST;
+ /*
+ * Reserve the slot with a zero entry (reads back as NULL) until the
+ * vdevice_init() op accepts the vDEVICE. Only the xa_* helpers hide a
+ * reserved entry, so never use a raw xas_* iterator on this xarray.
+ */
+ rc = xa_insert(&viommu->vdevs, virt_id, NULL, GFP_KERNEL);
+ if (rc) {
+ if (rc == -EBUSY)
+ rc = -EEXIST;
goto out_abort;
}
if (viommu->ops && viommu->ops->vdevice_init) {
rc = viommu->ops->vdevice_init(vdev);
- if (rc)
+ if (rc) {
+ xa_release(&viommu->vdevs, virt_id);
goto out_abort;
+ }
}
+ xa_store(&viommu->vdevs, virt_id, vdev, GFP_KERNEL);
+
cmd->out_vdevice_id = vdev->obj.id;
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
if (rc)
diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
index 3702cac7fbf0..b3b321d9ce68 100644
--- a/drivers/net/can/c_can/c_can_main.c
+++ b/drivers/net/can/c_can/c_can_main.c
@@ -597,20 +597,20 @@ static int c_can_chip_config(struct net_device *dev)
return err;
/* enable automatic retransmission */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR | CONTROL_INIT);
if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
(priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
/* loopback + silent mode : useful for hot self-test */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* loopback mode : useful for self-test function */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
/* silent mode : bus-monitoring mode */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
}
diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c
index 0ea1ff28dfce..07d4aa43c700 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_base.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_base.c
@@ -340,8 +340,8 @@ static void ctucan_set_mode(struct ctucan_priv *priv, const struct can_ctrlmode
(mode_reg & ~REG_MODE_FDE);
mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ?
- (mode_reg | REG_MODE_ACF) :
- (mode_reg & ~REG_MODE_ACF);
+ (mode_reg | REG_MODE_STM) :
+ (mode_reg & ~REG_MODE_STM);
mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ?
(mode_reg | REG_MODE_NISOFD) :
@@ -869,7 +869,7 @@ static void ctucan_err_interrupt(struct net_device *ndev, u32 isr)
break;
case CAN_STATE_ERROR_ACTIVE:
if (skb) {
- cf->can_id |= CAN_ERR_CNT;
+ cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
cf->data[6] = bec.txerr;
cf->data[7] = bec.rxerr;
@@ -1136,8 +1136,12 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
/* Error interrupts */
if (FIELD_GET(REG_INT_STAT_EWLI, isr) ||
FIELD_GET(REG_INT_STAT_FCSI, isr) ||
- FIELD_GET(REG_INT_STAT_ALI, isr)) {
- icr = isr & (REG_INT_STAT_EWLI | REG_INT_STAT_FCSI | REG_INT_STAT_ALI);
+ FIELD_GET(REG_INT_STAT_ALI, isr) ||
+ FIELD_GET(REG_INT_STAT_BEI, isr)) {
+ icr = isr & (REG_INT_STAT_EWLI |
+ REG_INT_STAT_FCSI |
+ REG_INT_STAT_ALI |
+ REG_INT_STAT_BEI);
ctucan_netdev_dbg(ndev, "some ERR interrupt: clearing 0x%08x\n", icr);
ctucan_write32(priv, CTUCANFD_INT_STAT, icr);
diff --git a/drivers/net/can/ctucanfd/ctucanfd_pci.c b/drivers/net/can/ctucanfd/ctucanfd_pci.c
index 625788fa8976..4b6db28f7b67 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_pci.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_pci.c
@@ -194,7 +194,7 @@ err_free_board:
pci_set_drvdata(pdev, NULL);
kfree(bdata);
err_pci_iounmap_bar0:
- pci_iounmap(pdev, cra_addr);
+ pci_iounmap(pdev, bar0_base);
err_pci_iounmap_bar1:
pci_iounmap(pdev, addr);
err_release_regions:
@@ -266,6 +266,7 @@ static const struct pci_device_id ctucan_pci_tbl[] = {
CTUCAN_WITH_CTUCAN_ID)},
{},
};
+MODULE_DEVICE_TABLE(pci, ctucan_pci_tbl);
static struct pci_driver ctucan_pci_driver = {
.name = KBUILD_MODNAME,
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index eaf8cac78038..fcc37b73ed43 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2003,20 +2003,12 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
u32 ch, sts;
int err;
- err = reset_control_reset(gpriv->rstc1);
- if (err)
- return err;
-
- err = reset_control_reset(gpriv->rstc2);
- if (err)
- goto fail_reset1;
-
/* Enable peripheral clock for register access */
err = clk_prepare_enable(gpriv->clkp);
if (err) {
dev_err(dev, "failed to enable peripheral clock: %pe\n",
ERR_PTR(err));
- goto fail_reset2;
+ return err;
}
/* Enable RAM clock */
@@ -2027,10 +2019,18 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
goto fail_clk;
}
+ err = reset_control_reset(gpriv->rstc1);
+ if (err)
+ goto fail_ram_clk;
+
+ err = reset_control_reset(gpriv->rstc2);
+ if (err)
+ goto fail_reset1;
+
err = rcar_canfd_reset_controller(gpriv);
if (err) {
dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
- goto fail_ram_clk;
+ goto fail_reset2;
}
/* Controller in Global reset & Channel reset mode */
@@ -2068,14 +2068,14 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
fail_mode:
rcar_canfd_disable_global_interrupts(gpriv);
-fail_ram_clk:
- clk_disable_unprepare(gpriv->clk_ram);
-fail_clk:
- clk_disable_unprepare(gpriv->clkp);
fail_reset2:
reset_control_assert(gpriv->rstc2);
fail_reset1:
reset_control_assert(gpriv->rstc1);
+fail_ram_clk:
+ clk_disable_unprepare(gpriv->clk_ram);
+fail_clk:
+ clk_disable_unprepare(gpriv->clkp);
return err;
}
@@ -2090,10 +2090,10 @@ static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
}
- clk_disable_unprepare(gpriv->clk_ram);
- clk_disable_unprepare(gpriv->clkp);
reset_control_assert(gpriv->rstc2);
reset_control_assert(gpriv->rstc1);
+ clk_disable_unprepare(gpriv->clk_ram);
+ clk_disable_unprepare(gpriv->clkp);
}
static int rcar_canfd_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
index 721df91cdbfb..282570daf3ef 100644
--- a/drivers/net/can/softing/softing_fw.c
+++ b/drivers/net/can/softing/softing_fw.c
@@ -91,12 +91,12 @@ int softing_bootloader_command(struct softing *card, int16_t cmd,
return ret;
}
-static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
- uint16_t *plen, const uint8_t **pdat)
+static int fw_parse(const u8 **pmem, const u8 *limit, u16 *ptype,
+ u32 *paddr, u16 *plen, const u8 **pdat)
{
uint16_t checksum[2];
- const uint8_t *mem;
- const uint8_t *end;
+ const u8 *mem;
+ const u8 *record_end;
/*
* firmware records are a binary, unaligned stream composed of:
@@ -114,14 +114,21 @@ static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
* endianness & alignment.
*/
mem = *pmem;
+ /* A record needs an 8-byte prefix and a 2-byte checksum. */
+ if (mem > limit || limit - mem < 10)
+ return -EINVAL;
+
*ptype = le16_to_cpup((void *)&mem[0]);
*paddr = le32_to_cpup((void *)&mem[2]);
*plen = le16_to_cpup((void *)&mem[6]);
+ if (*plen > limit - mem - 10)
+ return -EINVAL;
+
*pdat = &mem[8];
/* verify checksum */
- end = &mem[8 + *plen];
- checksum[0] = le16_to_cpup((void *)end);
- for (checksum[1] = 0; mem < end; ++mem)
+ record_end = &mem[8 + *plen];
+ checksum[0] = le16_to_cpup((void *)record_end);
+ for (checksum[1] = 0; mem < record_end; ++mem)
checksum[1] += *mem;
if (checksum[0] != checksum[1])
return -EINVAL;
@@ -139,6 +146,7 @@ int softing_load_fw(const char *file, struct softing *card,
uint16_t type, len;
uint32_t addr;
uint8_t *buf = NULL, *new_buf;
+ s64 dpram_offset;
int buflen = 0;
int8_t type_end = 0;
@@ -153,7 +161,7 @@ int softing_load_fw(const char *file, struct softing *card,
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type != 0xffff)
@@ -164,7 +172,7 @@ int softing_load_fw(const char *file, struct softing *card,
}
/* ok, we had a header */
while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type == 3) {
@@ -179,9 +187,13 @@ int softing_load_fw(const char *file, struct softing *card,
goto failed;
}
- if ((addr + len + offset) > size)
+ dpram_offset = (s64)addr + offset;
+ if (dpram_offset < 0 || dpram_offset > size ||
+ len > size - dpram_offset) {
+ ret = -EINVAL;
goto failed;
- memcpy_toio(&dpram[addr + offset], dat, len);
+ }
+ memcpy_toio(&dpram[dpram_offset], dat, len);
/* be sure to flush caches from IO space */
mb();
if (len > buflen) {
@@ -195,7 +207,7 @@ int softing_load_fw(const char *file, struct softing *card,
buf = new_buf;
}
/* verify record data */
- memcpy_fromio(buf, &dpram[addr + offset], len);
+ memcpy_fromio(buf, &dpram[dpram_offset], len);
if (memcmp(buf, dat, len)) {
/* is not ok */
dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
@@ -237,7 +249,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret)
goto failed;
ret = -EINVAL;
@@ -253,7 +265,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
}
/* ok, we had a header */
while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret)
goto failed;
@@ -279,6 +291,12 @@ int softing_load_app_fw(const char *file, struct softing *card)
/* work in 16bit (target) */
sum &= 0xffff;
+ if (card->pdat->app.offs > card->dpram_size ||
+ len > card->dpram_size - card->pdat->app.offs) {
+ ret = -EINVAL;
+ goto failed;
+ }
+
memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
iowrite32(card->pdat->app.offs + card->pdat->app.addr,
&card->dpram[DPRAM_COMMAND + 2]);
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 9b25dda7c183..24cf8f651f8f 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -409,6 +409,40 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
netif_rx(skb);
}
+static bool ems_usb_rx_msg_len_valid(struct ems_cpc_msg *msg)
+{
+ size_t len = msg->length;
+ size_t can_len;
+
+ switch (msg->type) {
+ case CPC_MSG_TYPE_CAN_STATE:
+ return len >= sizeof(msg->msg.can_state);
+
+ case CPC_MSG_TYPE_CAN_FRAME:
+ case CPC_MSG_TYPE_EXT_CAN_FRAME:
+ case CPC_MSG_TYPE_RTR_FRAME:
+ case CPC_MSG_TYPE_EXT_RTR_FRAME:
+ if (len < CPC_CAN_MSG_MIN_SIZE)
+ return false;
+
+ if (msg->type == CPC_MSG_TYPE_RTR_FRAME ||
+ msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME)
+ return true;
+
+ can_len = can_cc_dlc2len(msg->msg.can_msg.length & 0xf);
+ return len >= CPC_CAN_MSG_MIN_SIZE + can_len;
+
+ case CPC_MSG_TYPE_CAN_FRAME_ERROR:
+ return len >= sizeof(msg->msg.error);
+
+ case CPC_MSG_TYPE_OVERRUN:
+ return len >= sizeof(msg->msg.overrun);
+
+ default:
+ return true;
+ }
+}
+
/*
* callback for bulk IN urb
*/
@@ -451,6 +485,15 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
}
msg = (struct ems_cpc_msg *)&ibuf[start];
+ if (msg->length >
+ urb->actual_length - start - CPC_MSG_HEADER_LEN) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+ if (!ems_usb_rx_msg_len_valid(msg)) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
switch (msg->type) {
case CPC_MSG_TYPE_CAN_STATE:
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index b259f6109808..e1724ae79c5a 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -1476,7 +1476,6 @@ static void es58x_read_bulk_callback(struct urb *urb)
dev_err_ratelimited(dev,
"Failed resubmitting read bulk urb: %pe\n",
ERR_PTR(ret));
- return;
free_urb:
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index ec9a7cbbbc69..82508a865095 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -674,7 +674,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->flags & GS_CAN_FLAG_FD) {
skb = alloc_canfd_skb(netdev, &cfd);
if (!skb)
- return;
+ goto resubmit_urb;
cfd->can_id = le32_to_cpu(hf->can_id);
cfd->len = data_length;
@@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
} else {
skb = alloc_can_skb(netdev, &cf);
if (!skb)
- return;
+ goto resubmit_urb;
cf->can_id = le32_to_cpu(hf->can_id);
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
index e09d663e362f..efbb7bed34c9 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
@@ -1626,6 +1626,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
reinit_completion(&priv->get_busparams_comp);
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
+ kfree(cmd);
if (err)
return err;
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index df737cfc5ea0..a876c7819b81 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -691,13 +691,22 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
continue;
}
- if (pos + tmp->len > actual_len) {
+ if (tmp->len < CMD_HEADER_LEN ||
+ tmp->len > actual_len - pos) {
dev_err_ratelimited(&dev->intf->dev,
"Format error\n");
break;
}
if (tmp->id == id) {
+ if (tmp->len > sizeof(*cmd)) {
+ dev_err_ratelimited(&dev->intf->dev,
+ "Received command %u too large (%u)\n",
+ tmp->id, tmp->len);
+ err = -EIO;
+ goto end;
+ }
+
memcpy(cmd, tmp, tmp->len);
goto end;
}
@@ -1737,7 +1746,7 @@ static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
continue;
}
- if (pos + cmd->len > len) {
+ if (cmd->len < CMD_HEADER_LEN || cmd->len > len - pos) {
dev_err_ratelimited(&dev->intf->dev, "Format error\n");
break;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index c7933d1acc99..55aad01cd8ca 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -470,7 +470,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
netif_device_detach(dev->netdev);
usb_unanchor_urb(urb);
- kfree(buf);
usb_free_urb(urb);
break;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index ef9fd693e9bd..0d46f4ce5dca 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -566,6 +566,13 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
dev->can.ctrlmode);
}
+ if (!(rx_msg_flags & PUCAN_MSG_RTR) &&
+ le16_to_cpu(rx_msg->size) - offsetof(struct pucan_rx_msg, d) <
+ cfd->len) {
+ kfree_skb(skb);
+ return -EBADMSG;
+ }
+
cfd->can_id = le32_to_cpu(rm->can_id);
if (rx_msg_flags & PUCAN_MSG_EXT_ID)
@@ -714,6 +721,24 @@ static void pcan_usb_fd_decode_ts(struct pcan_usb_fd_if *usb_if,
peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low));
}
+static size_t pcan_usb_fd_rx_msg_min_size(u16 rx_msg_type)
+{
+ switch (rx_msg_type) {
+ case PUCAN_MSG_CAN_RX:
+ return offsetof(struct pucan_rx_msg, d);
+ case PCAN_UFD_MSG_CALIBRATION:
+ return sizeof(struct pcan_ufd_ts_msg);
+ case PUCAN_MSG_ERROR:
+ return sizeof(struct pucan_error_msg);
+ case PUCAN_MSG_STATUS:
+ return sizeof(struct pucan_status_msg);
+ case PCAN_UFD_MSG_OVERRUN:
+ return sizeof(struct pcan_ufd_ovr_msg);
+ default:
+ return sizeof(struct pucan_msg);
+ }
+}
+
/* callback for bulk IN urb */
static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
{
@@ -728,6 +753,12 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
msg_end = urb->transfer_buffer + urb->actual_length;
for (; msg_ptr < msg_end;) {
u16 rx_msg_type, rx_msg_size;
+ size_t rx_msg_min_size;
+
+ if (msg_end - msg_ptr < sizeof(*rx_msg)) {
+ err = -EBADMSG;
+ break;
+ }
rx_msg = (struct pucan_msg *)msg_ptr;
if (!rx_msg->size) {
@@ -739,13 +770,20 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
rx_msg_type = le16_to_cpu(rx_msg->type);
/* check if the record goes out of current packet */
- if (msg_ptr + rx_msg_size > msg_end) {
+ if (rx_msg_size > msg_end - msg_ptr) {
netdev_err(netdev,
"got frag rec: should inc usb rx buf sze\n");
err = -EBADMSG;
break;
}
+ rx_msg_min_size = pcan_usb_fd_rx_msg_min_size(rx_msg_type);
+ if (rx_msg_size < rx_msg_min_size) {
+ netdev_err(netdev, "got short rec\n");
+ err = -EBADMSG;
+ break;
+ }
+
switch (rx_msg_type) {
case PUCAN_MSG_CAN_RX:
err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index aefcded8e12a..b6be8c19e537 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -534,12 +534,18 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
struct pcan_usb_pro_rxmsg *rx)
{
const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
- struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
- struct net_device *netdev = dev->netdev;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
struct can_frame *can_frame;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwts;
+ if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+ return -EINVAL;
+
+ dev = usb_if->dev[ctrl_idx];
+ netdev = dev->netdev;
+
skb = alloc_can_skb(netdev, &can_frame);
if (!skb)
return -ENOMEM;
@@ -573,14 +579,20 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
{
const u16 raw_status = le16_to_cpu(er->status);
const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f;
- struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
- struct net_device *netdev = dev->netdev;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
struct can_frame *can_frame;
enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
u8 err_mask = 0;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwts;
+ if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+ return -EINVAL;
+
+ dev = usb_if->dev[ctrl_idx];
+ netdev = dev->netdev;
+
/* nothing should be sent while in BUS_OFF state */
if (dev->can.state == CAN_STATE_BUS_OFF)
return 0;
diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c
index 11ea924a9f35..784dd58a7158 100644
--- a/drivers/net/dsa/mt7530-mdio.c
+++ b/drivers/net/dsa/mt7530-mdio.c
@@ -55,8 +55,15 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
if (ret < 0)
return ret;
- lo = bus->read(bus, priv->mdiodev->addr, r);
- hi = bus->read(bus, priv->mdiodev->addr, 0x10);
+ ret = bus->read(bus, priv->mdiodev->addr, r);
+ if (ret < 0)
+ return ret;
+ lo = ret;
+
+ ret = bus->read(bus, priv->mdiodev->addr, 0x10);
+ if (ret < 0)
+ return ret;
+ hi = ret;
*val = (hi << 16) | (lo & 0xffff);
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 3c2a3029b10c..aa33d94e11b5 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -192,12 +192,6 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
}
static u32
-_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
-{
- return mt7530_mii_read(p->priv, p->reg);
-}
-
-static u32
_mt7530_read(struct mt7530_dummy_poll *p)
{
u32 val;
@@ -248,15 +242,20 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
{
u32 val;
int ret;
- struct mt7530_dummy_poll p;
/* Set the command operating upon the MAC address entries */
val = ATC_BUSY | ATC_MAT(0) | cmd;
mt7530_write(priv, MT7530_ATC, val);
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_ATC);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
- !(val & ATC_BUSY), 20, 20000);
+ mt7530_mutex_lock(priv);
+
+ ret = regmap_read_poll_timeout(priv->regmap, MT7530_ATC, val,
+ !(val & ATC_BUSY), 20, 20000);
+ if (!ret)
+ ret = regmap_read(priv->regmap, MT7530_ATC, &val);
+
+ mt7530_mutex_unlock(priv);
+
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
return ret;
@@ -265,7 +264,6 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
/* Additional sanity for read command if the specified
* entry is invalid
*/
- val = mt7530_read(priv, MT7530_ATC);
if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
return -EINVAL;
@@ -549,16 +547,13 @@ static int
mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
int regnum)
{
- struct mt7530_dummy_poll p;
u32 reg, val;
int ret;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -568,8 +563,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -579,8 +574,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad);
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -597,16 +592,13 @@ static int
mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
int regnum, u16 data)
{
- struct mt7530_dummy_poll p;
u32 val, reg;
int ret;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -616,8 +608,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -627,8 +619,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -643,16 +635,13 @@ out:
static int
mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
- struct mt7530_dummy_poll p;
int ret;
u32 val;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -663,8 +652,8 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -681,16 +670,13 @@ static int
mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 data)
{
- struct mt7530_dummy_poll p;
int ret;
u32 reg;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
- !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -701,8 +687,8 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
- !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -1626,22 +1612,26 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
static int
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
{
- struct mt7530_dummy_poll p;
u32 val;
int ret;
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
mt7530_write(priv, MT7530_VTCR, val);
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
- !(val & VTCR_BUSY), 20, 20000);
+ mt7530_mutex_lock(priv);
+
+ ret = regmap_read_poll_timeout(priv->regmap, MT7530_VTCR, val,
+ !(val & VTCR_BUSY), 20, 20000);
+ if (!ret)
+ ret = regmap_read(priv->regmap, MT7530_VTCR, &val);
+
+ mt7530_mutex_unlock(priv);
+
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
return ret;
}
- val = mt7530_read(priv, MT7530_VTCR);
if (val & VTCR_INVALID) {
dev_err(priv->dev, "read VTCR invalid\n");
return -EINVAL;
diff --git a/drivers/net/dsa/realtek/rtl8365mb_main.c b/drivers/net/dsa/realtek/rtl8365mb_main.c
index 5ac091bf93c9..aa05375b090a 100644
--- a/drivers/net/dsa/realtek/rtl8365mb_main.c
+++ b/drivers/net/dsa/realtek/rtl8365mb_main.c
@@ -1988,16 +1988,19 @@ static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port,
spin_unlock(&p->stats_lock);
}
-static void rtl8365mb_stats_setup(struct realtek_priv *priv)
+static int rtl8365mb_stats_setup(struct realtek_priv *priv)
{
struct rtl8365mb *mb = priv->chip_data;
struct dsa_switch *ds = &priv->ds;
struct dsa_port *dp;
+ int ret;
/* Per-chip global mutex to protect MIB counter access, since doing
* so requires accessing a series of registers in a particular order.
*/
- mutex_init(&mb->mib_lock);
+ ret = devm_mutex_init(priv->dev, &mb->mib_lock);
+ if (ret)
+ return ret;
dsa_switch_for_each_available_port(dp, ds) {
struct rtl8365mb_port *p = &mb->ports[dp->index];
@@ -2010,6 +2013,8 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv)
*/
INIT_DELAYED_WORK(&p->mib_work, rtl8365mb_stats_poll);
}
+
+ return 0;
}
static void rtl8365mb_stats_teardown(struct realtek_priv *priv)
@@ -2567,7 +2572,12 @@ static int rtl8365mb_setup(struct dsa_switch *ds)
}
/* Start statistics counter polling */
- rtl8365mb_stats_setup(priv);
+ ret = rtl8365mb_stats_setup(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to setup stats: %pe\n",
+ ERR_PTR(ret));
+ goto out_teardown_irq;
+ }
return 0;
diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c
index 71124ecca92f..9dd50b20c000 100644
--- a/drivers/net/dsa/realtek/rtl83xx.c
+++ b/drivers/net/dsa/realtek/rtl83xx.c
@@ -156,9 +156,17 @@ rtl83xx_probe(struct device *dev,
if (!priv)
return ERR_PTR(-ENOMEM);
- mutex_init(&priv->map_lock);
- mutex_init(&priv->vlan_lock);
- mutex_init(&priv->l2_lock);
+ ret = devm_mutex_init(dev, &priv->map_lock);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = devm_mutex_init(dev, &priv->vlan_lock);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = devm_mutex_init(dev, &priv->l2_lock);
+ if (ret)
+ return ERR_PTR(ret);
rc.lock_arg = priv;
priv->map = devm_regmap_init(dev, NULL, priv, &rc);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 9b09eb144b81..d7f5c6f16142 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -1222,11 +1222,11 @@ err_eeprom:
if (hw->flash_address)
iounmap(hw->flash_address);
+err_mdio_ioremap:
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
err_dma:
err_sw_init:
-err_mdio_ioremap:
iounmap(hw->ce4100_gbe_mdio_base_virt);
iounmap(hw->hw_addr);
err_ioremap:
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 30c3a4db7d61..85a74cd6ea1f 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -793,7 +793,7 @@ err:
ret,
libie_aq_str(pf->hw.adminq.sq_last_status),
pin_type_name[pin_type], pin->idx);
- else
+ else if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
dev_err_ratelimited(ice_pf_to_dev(pf),
"err:%d %s failed to update %s pin:%u\n",
ret,
@@ -3024,7 +3024,8 @@ static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf,
*phase_offset_pins_updated = 0;
ret = ice_aq_get_cgu_input_pin_measure(&pf->hw, DPLL_TYPE_PPS, meas,
ARRAY_SIZE(meas));
- if (ret && pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN) {
+ if (ret && (pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN ||
+ pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EBUSY)) {
return 0;
} else if (ret) {
dev_err(ice_pf_to_dev(pf),
@@ -3086,10 +3087,12 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init)
d->dpll_idx, d->prev_input_idx, d->input_idx,
d->dpll_state, d->prev_dpll_state, d->mode);
if (ret) {
- dev_err(ice_pf_to_dev(pf),
- "update dpll=%d state failed, ret=%d %s\n",
- d->dpll_idx, ret,
- libie_aq_str(pf->hw.adminq.sq_last_status));
+ /* EBUSY is expected during reset recovery, don't log error */
+ if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
+ dev_err(ice_pf_to_dev(pf),
+ "update dpll=%d state failed, ret=%d %s\n",
+ d->dpll_idx, ret,
+ libie_aq_str(pf->hw.adminq.sq_last_status));
return ret;
}
if (init) {
@@ -3158,7 +3161,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
d->periodic_counter % dp->phase_offset_monitor_period == 0)
ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf);
if (ret) {
- d->cgu_state_acq_err_num++;
+ /* EBUSY is expected during reset recovery */
+ if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
+ d->cgu_state_acq_err_num++;
/* stop rescheduling this worker */
if (d->cgu_state_acq_err_num >
ICE_CGU_STATE_ACQ_ERR_THRESHOLD) {
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 49371b065845..7eb380be7ed2 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1069,18 +1069,18 @@ static int ice_lbtest_prepare_rings(struct ice_vsi *vsi)
status = ice_vsi_cfg_lan(vsi);
if (status)
- goto err_setup_rx_ring;
+ goto err_cfg_lan;
status = ice_vsi_start_all_rx_rings(vsi);
if (status)
- goto err_start_rx_ring;
+ goto err_cfg_lan;
return 0;
-err_start_rx_ring:
- ice_vsi_free_rx_rings(vsi);
-err_setup_rx_ring:
+err_cfg_lan:
ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
+err_setup_rx_ring:
+ ice_vsi_free_rx_rings(vsi);
err_setup_tx_ring:
ice_vsi_free_tx_rings(vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index e2fd2dab03e3..d88835482d3a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5637,6 +5637,16 @@ static int ice_resume(struct device *dev)
/* Restart the service task */
mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ /* Best-effort wait for the scheduled reset to finish so that the
+ * device is operational before returning. Without this, userspace
+ * (e.g. NetworkManager) may try to open the net device while the
+ * asynchronous reset is still in progress, hitting -EBUSY.
+ */
+ ret = ice_wait_for_reset(pf, secs_to_jiffies(10));
+ if (ret)
+ dev_err(dev, "Wait for reset timed out (10s) during resume: %d\n",
+ ret);
+
return 0;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 9052e71e9c99..a54cb2b8d3c7 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -849,6 +849,30 @@ static void ice_notify_vf_reset(struct ice_vf *vf)
}
/**
+ * ice_reset_interrupts - clear all queue interrupt configuration for a VSI
+ * @vsi: the VSI whose interrupt registers should be cleared
+ *
+ * Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues
+ * in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX,
+ * CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only
+ * clears the CAUSE_ENA bit.
+ */
+void ice_reset_interrupts(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int i;
+
+ ice_for_each_alloc_rxq(vsi, i)
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[i]), 0);
+
+ ice_for_each_alloc_txq(vsi, i)
+ wr32(hw, QINT_TQCTL(vsi->txq_map[i]), 0);
+
+ ice_flush(hw);
+}
+
+/**
* ice_reset_vf - Reset a particular VF
* @vf: pointer to the VF structure
* @flags: flags controlling behavior of the reset
@@ -919,6 +943,9 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
ice_dis_vf_qs(vf);
+ /* cleanup interrupt registers */
+ ice_reset_interrupts(vsi);
+
/* Call Disable LAN Tx queue AQ whether or not queues are
* enabled. This is needed for successful completion of VFR.
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
index 5392b0404986..321d29c25b7c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
@@ -26,6 +26,7 @@
void ice_initialize_vf_entry(struct ice_vf *vf);
void ice_deinitialize_vf_entry(struct ice_vf *vf);
void ice_dis_vf_qs(struct ice_vf *vf);
+void ice_reset_interrupts(struct ice_vsi *vsi);
int ice_check_vf_init(struct ice_vf *vf);
enum virtchnl_status_code ice_err_to_virt_err(int err);
struct ice_port_info *ice_vf_get_port_info(struct ice_vf *vf);
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 31be2f76181c..431c9c546b04 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -225,6 +225,24 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
}
/**
+ * ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL
+ * @vsi: VSI of the VF to configure
+ * @q_idx: VF queue index used to determine the queue in the PF's space
+ */
+static void ice_vf_dis_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ u32 pfq = vsi->rxq_map[q_idx];
+ u32 reg;
+
+ reg = rd32(hw, QINT_RQCTL(pfq));
+ reg &= ~QINT_RQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_RQCTL(pfq), reg);
+
+ ice_flush(hw);
+}
+
+/**
* ice_vc_ena_qs_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
@@ -416,6 +434,8 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF)
+ ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
} else if (q_map) {
for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
@@ -436,6 +456,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
+ ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
/* Clear enabled queues flag */
clear_bit(vf_q_id, vf->rxq_ena);
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 1a0c71c95ef1..4079a787657f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -87,7 +87,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index cf966fe6c759..bb81e620c5c8 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -139,7 +139,7 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
if (err) {
dev_err(&adapter->pdev->dev,
"IRQ request for mailbox failed, error: %d\n", err);
-
+ kfree(name);
return err;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 7f9056404f64..c724d429a7aa 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3097,10 +3097,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE;
tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP;
- /* Set the RE bit to periodically "clean" the descriptor ring.
- * MIN_GAP is set to MIN_RING size to ensure it will be set at
- * least once each time around the ring.
- */
+ /* Set the RE bit periodically to "clean" the descriptor ring */
if (idpf_tx_splitq_need_re(tx_q)) {
tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE;
tx_q->txq_grp->num_completions_pending++;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 4be5b3b6d3ed..908dfa28674e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -21,7 +21,7 @@
/* Mailbox Queue */
#define IDPF_MAX_MBXQ 1
-#define IDPF_MIN_TXQ_DESC 64
+#define IDPF_MIN_TXQ_DESC 128
#define IDPF_MIN_RXQ_DESC 64
#define IDPF_MIN_TXQ_COMPLQ_DESC 256
#define IDPF_MAX_QIDS 256
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index a07d7e808ca9..6726084f6cfa 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -86,7 +86,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index dc5ad784f456..8bd6cca64c9b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1318,11 +1318,12 @@ idpf_vport_init_queue_reg_chunks(struct idpf_vport_config *vport_config,
* idpf_get_reg_intr_vecs - Get vector queue register offset
* @adapter: adapter structure to get the vector chunks
* @reg_vals: Register offsets to store in
+ * @num_vecs: number of entries the @reg_vals array can hold
*
* Return: number of registers that got populated
*/
int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
- struct idpf_vec_regs *reg_vals)
+ struct idpf_vec_regs *reg_vals, int num_vecs)
{
struct virtchnl2_vector_chunks *chunks;
struct idpf_vec_regs reg_val;
@@ -1346,7 +1347,7 @@ int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
dynctl_reg_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
- for (i = 0; i < num_vec; i++) {
+ for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg;
reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
reg_vals[num_regs].itrn_index_spacing =
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 6876e3ed9d1b..9b1c9c86f6ea 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -104,7 +104,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter);
void idpf_vc_core_deinit(struct idpf_adapter *adapter);
int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
- struct idpf_vec_regs *reg_vals);
+ struct idpf_vec_regs *reg_vals, int num_vecs);
int idpf_queue_reg_init(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc,
struct idpf_queue_id_reg_info *chunks);
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 0a3d0a1cba43..c686ee120a14 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -2190,8 +2190,6 @@ dma_error:
buffer_info->time_stamp = 0;
buffer_info->length = 0;
buffer_info->mapped_as_page = false;
- if (count)
- count--;
/* clear timestamp and dma mappings for remaining portion of packet */
while (count--) {
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 2c9e2dfd8499..b3883a5a7d7a 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -5352,9 +5352,8 @@ void igc_down(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igc_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igc_set_queue_napi(adapter, i, NULL);
}
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index 2e94d5105016..f5fd6138c352 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -518,6 +518,18 @@ int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind)
return 0;
}
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!is_lmac_valid(cgx, lmac_id))
+ return -ENODEV;
+
+ *pkind = cgx_read(cgx, lmac_id, cgx->mac_ops->rxid_map_offset);
+ *pkind = *pkind & 0x3F;
+ return 0;
+}
+
static u8 cgx_get_lmac_type(void *cgxd, int lmac_id)
{
struct cgx *cgx = cgxd;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 92ccf343dfe0..8411a75dd723 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -141,6 +141,7 @@ int cgx_get_cgxid(void *cgxd);
int cgx_get_lmac_cnt(void *cgxd);
void *cgx_get_pdata(int cgx_id);
int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind);
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind);
int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id);
int cgx_lmac_evh_unregister(void *cgxd, int lmac_id);
int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 7f3505ae6860..9d5b7b51bdfa 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -1115,6 +1115,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
u8 *intf, u8 *ena);
int npc_config_cntr_default_entries(struct rvu *rvu, bool enable);
bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc);
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind);
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc);
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
void *rvu_first_cgx_pdata(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 4ff3935ed3fe..87d21889dc49 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -1355,3 +1355,82 @@ void rvu_mac_reset(struct rvu *rvu, u16 pcifunc)
if (mac_ops->mac_reset(cgxd, lmac, !is_vf(pcifunc)))
dev_err(rvu->dev, "Failed to reset MAC\n");
}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC. VFs must not program
+ * NPC_TX_DEF_PKIND on NIX_AF_LFX_TX_PARSE_CFG in that case: the PF owns
+ * parse mode and no separate NPC_TX_HIGIG_PKIND is installed on the VF LF.
+ * TX-parse callers skip the write when denied; rvu_lf_reset() clears each LF
+ * before alloc so the next permitted owner programs NPC_TX_DEF_PKIND.
+ */
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ void *cgxd;
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
+
+ if (!(pcifunc & RVU_PFVF_FUNC_MASK))
+ return true;
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return true;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ return false;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC.
+ */
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return false;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+
+ mutex_lock(&cgxd->lock);
+ if (!is_vf(pcifunc))
+ goto set;
+
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ goto err;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ goto err;
+ default:
+ break;
+ }
+
+set:
+ cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
+ mutex_unlock(&cgxd->lock);
+ return true;
+
+err:
+ mutex_unlock(&cgxd->lock);
+ return false;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 6a0ce2665031..964bcaae098e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -363,8 +363,8 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf,
pfvf->tx_chan_cnt = 1;
rsp->tx_link = cgx_id * hw->lmac_per_cgx + lmac_id;
- cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
- rvu_npc_set_pkind(rvu, pkind, pfvf);
+ if (rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, pkind))
+ rvu_npc_set_pkind(rvu, pkind, pfvf);
break;
case NIX_INTF_TYPE_LBK:
vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1;
@@ -1505,13 +1505,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
struct nix_lf_alloc_req *req,
struct nix_lf_alloc_rsp *rsp)
{
- int nixlf, qints, hwctx_size, intf, rc = 0;
+ int nixlf, qints, hwctx_size, intf, rc = 0, pf;
u16 bcast, mcast, promisc, ucast;
struct rvu_hwinfo *hw = rvu->hw;
u16 pcifunc = req->hdr.pcifunc;
+ u8 cgx_id = 0, lmac_id = 0;
bool rules_created = false;
struct rvu_block *block;
struct rvu_pfvf *pfvf;
+ struct cgx *cgxd;
u64 cfg, ctx_cfg;
int blkaddr;
@@ -1685,8 +1687,20 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
/* Configure pkind for TX parse config */
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
cfg = NPC_TX_DEF_PKIND;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ }
if (is_rep_dev(rvu, pcifunc)) {
pfvf->tx_chan_base = RVU_SWITCH_LBK_CHAN;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c7bc0b3a29b9..38554d51164e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -19,6 +19,7 @@
#include "cn20k/npc.h"
#include "rvu_npc.h"
#include "cn20k/reg.h"
+#include "lmac_common.h"
#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
@@ -4200,10 +4201,11 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
- int blkaddr, nixlf, rc, intf_mode;
int pf = rvu_get_pf(rvu->pdev, pcifunc);
+ int blkaddr, nixlf, rc, intf_mode;
+ u8 cgx_id = 0, lmac_id = 0;
u64 rxpkind, txpkind;
- u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
/* use default pkind to disable edsa/higig */
rxpkind = rvu_npc_get_pkind(rvu, pf);
@@ -4227,12 +4229,8 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
/* rx pkind set req valid only for cgx mapped PFs */
if (!is_cgx_config_permitted(rvu, pcifunc))
return 0;
- rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-
- rc = cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
- rxpkind);
- if (rc)
- return rc;
+ if (!rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, rxpkind))
+ return -EINVAL;
}
if (dir & PKIND_TX) {
@@ -4241,8 +4239,19 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
if (rc)
return rc;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
- txpkind);
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id,
+ &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ }
}
pfvf->intf_mode = intf_mode;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 2e33b33ec993..c995f2900859 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -889,8 +889,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);
} else {
- netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
}
}
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 5d291e50a47b..351444fb4871 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3467,7 +3467,7 @@ static void mtk_poll_controller(struct net_device *dev)
mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+ mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], eth);
mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index d507289096c2..6867a5aed42c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -984,7 +984,6 @@ struct mlx5e_priv {
struct mlx5e_mqprio_rl *mqprio_rl;
struct dentry *dfs_root;
struct mlx5_devcom_comp_dev *devcom;
- struct ethtool_fec_hist_range *fec_ranges;
};
static inline u16 mlx5e_stats_nch_read(const struct mlx5e_priv *priv)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index c1acb9012d3f..7d47a1da8b6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -6415,14 +6415,8 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
if (!priv->channel_stats)
goto err_free_tx_rates;
- priv->fec_ranges = kzalloc_objs(*priv->fec_ranges, ETHTOOL_FEC_HIST_MAX);
- if (!priv->fec_ranges)
- goto err_free_channel_stats;
-
return 0;
-err_free_channel_stats:
- kfree(priv->channel_stats);
err_free_tx_rates:
kfree(priv->tx_rates);
err_free_txq2sq_stats:
@@ -6447,7 +6441,6 @@ void mlx5e_priv_cleanup(struct mlx5e_priv *priv)
if (!priv->mdev)
return;
- kfree(priv->fec_ranges);
for (i = 0; i < priv->stats_nch; i++)
kvfree(priv->channel_stats[i]);
kfree(priv->channel_stats);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index de38b60806c2..e7e6db7f6bf1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -1550,7 +1550,7 @@ static bool fec_rs_validate_hist_type(int mode, int hist_type)
static u8
fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
- const struct ethtool_fec_hist_range **ranges)
+ struct ethtool_fec_hist_range *ranges)
{
struct mlx5_core_dev *mdev = priv->mdev;
u32 out[MLX5_ST_SZ_DW(pphcr_reg)] = {0};
@@ -1558,8 +1558,6 @@ fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
int sz = MLX5_ST_SZ_BYTES(pphcr_reg);
u8 hist_type, num_of_bins;
- memset(priv->fec_ranges, 0,
- ETHTOOL_FEC_HIST_MAX * sizeof(*priv->fec_ranges));
MLX5_SET(pphcr_reg, in, local_port, 1);
if (mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPHCR, 0, 0))
return 0;
@@ -1575,12 +1573,11 @@ fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
for (int i = 0; i < num_of_bins; i++) {
void *bin_range = MLX5_ADDR_OF(pphcr_reg, out, bin_range[i]);
- priv->fec_ranges[i].high = MLX5_GET(bin_range_layout, bin_range,
- high_val);
- priv->fec_ranges[i].low = MLX5_GET(bin_range_layout, bin_range,
- low_val);
+ ranges[i].high = MLX5_GET(bin_range_layout, bin_range,
+ high_val);
+ ranges[i].low = MLX5_GET(bin_range_layout, bin_range,
+ low_val);
}
- *ranges = priv->fec_ranges;
return num_of_bins;
}
@@ -1622,10 +1619,12 @@ static void fec_set_histograms_stats(struct mlx5e_priv *priv, int mode,
case MLX5E_FEC_LLRS_272_257_1:
case MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD:
num_of_bins =
- fec_rs_histogram_fill_ranges(priv, mode, &hist->ranges);
- if (num_of_bins)
+ fec_rs_histogram_fill_ranges(priv, mode, hist->ranges_buf);
+ if (num_of_bins) {
+ hist->ranges = hist->ranges_buf;
return fec_rs_histogram_fill_stats(priv, num_of_bins,
hist);
+ }
break;
default:
return;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 9d9bfd116dab..92bb55935c1c 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2829,7 +2829,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
rxq = kvzalloc_flex(*rxq, rx_oobs, apc->rx_queue_size);
if (!rxq)
- return NULL;
+ return ERR_PTR(-ENOMEM);
rxq->ndev = ndev;
rxq->num_rx_buf = apc->rx_queue_size;
@@ -2930,7 +2930,7 @@ out:
mana_destroy_rxq(apc, rxq, false);
- return NULL;
+ return ERR_PTR(err);
}
static void mana_create_rxq_debugfs(struct mana_port_context *apc, int idx)
@@ -2964,8 +2964,8 @@ static int mana_add_rx_queues(struct mana_port_context *apc,
for (i = 0; i < apc->num_queues; i++) {
rxq = mana_create_rxq(apc, i, &apc->eqs[i], ndev);
- if (!rxq) {
- err = -ENOMEM;
+ if (IS_ERR(rxq)) {
+ err = PTR_ERR(rxq);
netdev_err(ndev, "Failed to create rxq %d : %d\n", i, err);
goto out;
}
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 5b0435d7bc39..58d3e55def48 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -6187,10 +6187,10 @@ static void nv_remove(struct pci_dev *pci_dev)
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = netdev_priv(dev);
- free_percpu(np->txrx_stats);
-
unregister_netdev(dev);
+ free_percpu(np->txrx_stats);
+
nv_restore_mac_addr(pci_dev);
/* restore any phy related changes */
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index cb0ae0650905..7ed17faced54 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -107,7 +107,7 @@ static void qede_remove(struct pci_dev *pdev);
static void qede_shutdown(struct pci_dev *pdev);
static void qede_link_update(void *dev, struct qed_link_output *link);
static void qede_schedule_recovery_handler(void *dev);
-static void qede_recovery_handler(struct qede_dev *edev);
+static bool qede_recovery_handler(struct qede_dev *edev);
static void qede_schedule_hw_err_handler(void *dev,
enum qed_hw_err_type err_type);
static void qede_get_eth_tlv_data(void *edev, void *data);
@@ -1043,21 +1043,6 @@ void __qede_unlock(struct qede_dev *edev)
mutex_unlock(&edev->qede_lock);
}
-/* This version of the lock should be used when acquiring the RTNL lock is also
- * needed in addition to the internal qede lock.
- */
-static void qede_lock(struct qede_dev *edev)
-{
- rtnl_lock();
- __qede_lock(edev);
-}
-
-static void qede_unlock(struct qede_dev *edev)
-{
- __qede_unlock(edev);
- rtnl_unlock();
-}
-
static void qede_periodic_task(struct work_struct *work)
{
struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1094,6 +1079,8 @@ static void qede_sp_task(struct work_struct *work)
*/
if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) {
+ bool reloaded;
+
cancel_delayed_work_sync(&edev->periodic_task);
#ifdef CONFIG_QED_SRIOV
/* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1102,9 +1089,17 @@ static void qede_sp_task(struct work_struct *work)
if (pci_num_vf(edev->pdev))
qede_sriov_configure(edev->pdev, 0);
#endif
- qede_lock(edev);
- qede_recovery_handler(edev);
- qede_unlock(edev);
+ rtnl_lock();
+ __qede_lock(edev);
+ reloaded = qede_recovery_handler(edev);
+ __qede_unlock(edev);
+
+ /* The udp_tunnel core synchronously calls back into
+ * qede_udp_tunnel_sync(), which takes the qede lock.
+ */
+ if (reloaded)
+ udp_tunnel_nic_reset_ntf(edev->ndev);
+ rtnl_unlock();
}
__qede_lock(edev);
@@ -2645,9 +2640,13 @@ static void qede_recovery_failed(struct qede_dev *edev)
edev->ops->common->set_power_state(edev->cdev, PCI_D3hot);
}
-static void qede_recovery_handler(struct qede_dev *edev)
+/* Returns true if an open device was successfully reloaded and its
+ * udp_tunnel ports need to be re-synced by the caller.
+ */
+static bool qede_recovery_handler(struct qede_dev *edev)
{
u32 curr_state = edev->state;
+ bool reloaded = false;
int rc;
DP_NOTICE(edev, "Starting a recovery process\n");
@@ -2677,17 +2676,18 @@ static void qede_recovery_handler(struct qede_dev *edev)
goto err;
qede_config_rx_mode(edev->ndev);
- udp_tunnel_nic_reset_ntf(edev->ndev);
+ reloaded = true;
}
edev->state = curr_state;
DP_NOTICE(edev, "Recovery handling is done\n");
- return;
+ return reloaded;
err:
qede_recovery_failed(edev);
+ return false;
}
static void qede_atomic_hw_err_handler(struct qede_dev *edev)
diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 4168ad9e48ea..e3cd4f7c1380 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -1623,6 +1623,9 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
err_dma_1:
ring->skbuff[entry] = NULL;
rtase_tx_clear_range(ring, ring->cur_idx + 1, frags);
+ if (frags)
+ /* the frags were cleared above, along with the skb */
+ return NETDEV_TX_OK;
err_dma_0:
tp->stats.tx_dropped++;
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 5051ada43d2f..70cf3619555f 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -597,14 +597,13 @@ static int init_dma_desc_rings(struct net_device *netd)
return 0;
-txalloc_err:
- while (queue_num--)
- free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
- return ret;
-
rxalloc_err:
while (queue_num--)
free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+ queue_num = SXGBE_TX_QUEUES;
+txalloc_err:
+ while (queue_num--)
+ free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
return ret;
}
@@ -1079,7 +1078,9 @@ static int sxgbe_open(struct net_device *dev)
priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE);
priv->tx_tc = TC_DEFAULT;
priv->rx_tc = TC_DEFAULT;
- init_dma_desc_rings(dev);
+ ret = init_dma_desc_rings(dev);
+ if (ret)
+ goto init_phy_error;
/* DMA initialization and SW reset */
ret = sxgbe_init_dma_engine(priv);
@@ -1188,6 +1189,7 @@ static int sxgbe_open(struct net_device *dev)
init_error:
free_dma_desc_resources(priv);
+init_phy_error:
if (dev->phydev)
phy_disconnect(dev->phydev);
phy_error:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 151c77713025..3801f9d45278 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -755,7 +755,8 @@ static int stmmac_hwtstamp_set(struct net_device *dev,
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
- if (priv->synopsys_id < DWMAC_CORE_4_10)
+ if (priv->synopsys_id < DWMAC_CORE_3_70 &&
+ priv->plat->core_type != DWMAC_CORE_XGMAC)
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 814d88d2aee4..5d99e870de5e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1606,6 +1606,8 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb,
if (skb_vlan_tag_present(skb)) {
tx_flags |= skb_vlan_tag_get(skb) << WX_TX_FLAGS_VLAN_SHIFT;
tx_flags |= WX_TX_FLAGS_HW_VLAN;
+ } else if (eth_type_vlan(skb->protocol)) {
+ tx_flags |= WX_TX_FLAGS_SW_VLAN;
}
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 087ac63f9193..18d2ead97aa5 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1875,8 +1875,8 @@ struct phylink *phylink_create(struct phylink_config *config,
} else if (config->type == PHYLINK_DEV) {
pl->dev = config->dev;
} else {
- kfree(pl);
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto free_pl;
}
pl->mac_supports_eee_ops = phylink_mac_implements_lpi(mac_ops);
@@ -1909,28 +1909,29 @@ struct phylink *phylink_create(struct phylink_config *config,
phylink_validate(pl, pl->supported, &pl->link_config);
ret = phylink_parse_mode(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto free_pl;
if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
ret = phylink_parse_fixedlink(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto release_link_gpio;
}
pl->req_link_an_mode = pl->cfg_link_an_mode;
ret = phylink_register_sfp(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto release_link_gpio;
return pl;
+
+release_link_gpio:
+ if (pl->link_gpio)
+ gpiod_put(pl->link_gpio);
+free_pl:
+ kfree(pl);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(phylink_create);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffbe6f13fb1f..fed9dfdfcc3b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -145,8 +145,6 @@ struct tun_file {
struct list_head next;
struct tun_struct *detached;
struct ptr_ring tx_ring;
- /* Protected by tx_ring.consumer_lock */
- int cons_cnt;
struct xdp_rxq_info xdp_rxq;
};
@@ -590,13 +588,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
rcu_assign_pointer(tun->tfiles[index],
tun->tfiles[tun->numqueues - 1]);
ntfile = rtnl_dereference(tun->tfiles[index]);
- spin_lock(&ntfile->tx_ring.consumer_lock);
ntfile->queue_index = index;
ntfile->xdp_rxq.queue_index = index;
- ntfile->cons_cnt = 0;
- if (__ptr_ring_empty(&ntfile->tx_ring))
- netif_wake_subqueue(tun->dev, index);
- spin_unlock(&ntfile->tx_ring.consumer_lock);
rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
NULL);
@@ -737,9 +730,6 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
goto out;
}
- spin_lock(&tfile->tx_ring.consumer_lock);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
tfile->queue_index = tun->numqueues;
tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN;
@@ -1018,7 +1008,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *queue;
struct tun_file *tfile;
int len = skb->len;
- int ret;
rcu_read_lock();
tfile = rcu_dereference(tun->tfiles[txq]);
@@ -1073,33 +1062,13 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
nf_reset_ct(skb);
- queue = netdev_get_tx_queue(dev, txq);
-
- spin_lock(&tfile->tx_ring.producer_lock);
- ret = __ptr_ring_produce(&tfile->tx_ring, skb);
- if (!qdisc_txq_has_no_queue(queue) &&
- __ptr_ring_check_produce(&tfile->tx_ring) == -ENOSPC) {
- netif_tx_stop_queue(queue);
- /* Paired with smp_mb() in __tun_wake_queue() */
- smp_mb__after_atomic();
- if (!__ptr_ring_check_produce(&tfile->tx_ring))
- netif_tx_wake_queue(queue);
- }
- spin_unlock(&tfile->tx_ring.producer_lock);
-
- if (ret) {
- /* This should be a rare case if a qdisc is present, but
- * can happen due to lltx.
- * Since skb_tx_timestamp(), skb_orphan(),
- * run_ebpf_filter() and pskb_trim() could have tinkered
- * with the SKB, returning NETDEV_TX_BUSY is unsafe and
- * we must drop instead.
- */
+ if (ptr_ring_produce(&tfile->tx_ring, skb)) {
drop_reason = SKB_DROP_REASON_FULL_RING;
goto drop;
}
/* dev->lltx requires to do our own update of trans_start */
+ queue = netdev_get_tx_queue(dev, txq);
txq_trans_cond_update(queue);
/* Notify and wake up reader process */
@@ -2147,46 +2116,13 @@ done:
return total;
}
-/* Callers must hold ring.consumer_lock */
-static void __tun_wake_queue(struct tun_struct *tun,
- struct tun_file *tfile, int consumed)
-{
- struct netdev_queue *txq = netdev_get_tx_queue(tun->dev,
- tfile->queue_index);
-
- /* Paired with smp_mb__after_atomic() in tun_net_xmit() */
- smp_mb();
- if (netif_tx_queue_stopped(txq)) {
- tfile->cons_cnt += consumed;
- if (tfile->cons_cnt >= tfile->tx_ring.size / 2 ||
- __ptr_ring_empty(&tfile->tx_ring)) {
- netif_tx_wake_queue(txq);
- tfile->cons_cnt = 0;
- }
- }
-}
-
-static void *tun_ring_consume(struct tun_struct *tun, struct tun_file *tfile)
-{
- void *ptr;
-
- spin_lock(&tfile->tx_ring.consumer_lock);
- ptr = __ptr_ring_consume(&tfile->tx_ring);
- if (ptr)
- __tun_wake_queue(tun, tfile, 1);
-
- spin_unlock(&tfile->tx_ring.consumer_lock);
- return ptr;
-}
-
-static void *tun_ring_recv(struct tun_struct *tun, struct tun_file *tfile,
- int noblock, int *err)
+static void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err)
{
DECLARE_WAITQUEUE(wait, current);
void *ptr = NULL;
int error = 0;
- ptr = tun_ring_consume(tun, tfile);
+ ptr = ptr_ring_consume(&tfile->tx_ring);
if (ptr)
goto out;
if (noblock) {
@@ -2198,7 +2134,7 @@ static void *tun_ring_recv(struct tun_struct *tun, struct tun_file *tfile,
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- ptr = tun_ring_consume(tun, tfile);
+ ptr = ptr_ring_consume(&tfile->tx_ring);
if (ptr)
break;
if (signal_pending(current)) {
@@ -2235,7 +2171,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
if (!ptr) {
/* Read frames from ring */
- ptr = tun_ring_recv(tun, tfile, noblock, &err);
+ ptr = tun_ring_recv(tfile, noblock, &err);
if (!ptr)
return err;
}
@@ -3690,16 +3626,6 @@ static int tun_queue_resize(struct tun_struct *tun)
dev->tx_queue_len, GFP_KERNEL,
tun_ptr_free);
- if (!ret) {
- for (i = 0; i < tun->numqueues; i++) {
- tfile = rtnl_dereference(tun->tfiles[i]);
- spin_lock(&tfile->tx_ring.consumer_lock);
- netif_wake_subqueue(tun->dev, tfile->queue_index);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
- }
- }
-
kfree(rings);
return ret;
}
@@ -3808,29 +3734,6 @@ struct ptr_ring *tun_get_tx_ring(struct file *file)
}
EXPORT_SYMBOL_GPL(tun_get_tx_ring);
-/* Callers must hold ring.consumer_lock */
-void tun_wake_queue(struct file *file, int consumed)
-{
- struct tun_file *tfile;
- struct tun_struct *tun;
-
- if (file->f_op != &tun_fops)
- return;
-
- tfile = file->private_data;
- if (!tfile)
- return;
-
- rcu_read_lock();
-
- tun = rcu_dereference(tfile->tun);
- if (tun)
- __tun_wake_queue(tun, tfile, consumed);
-
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(tun_wake_queue);
-
module_init(tun_init);
module_exit(tun_cleanup);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1c5142149175..00e34afd858e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -756,7 +756,7 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq,
u32 frame_sz;
if (skb_shared(skb) || skb_head_is_locked(skb) ||
- skb_shinfo(skb)->nr_frags ||
+ skb_is_nonlinear(skb) ||
skb_headroom(skb) < XDP_PACKET_HEADROOM) {
if (skb_pp_cow_data(rq->page_pool, pskb, XDP_PACKET_HEADROOM))
goto drop;
@@ -771,7 +771,7 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq,
xdp_prepare_buff(xdp, skb->head, skb_headroom(skb),
skb_headlen(skb), true);
- if (skb_is_nonlinear(skb)) {
+ if (skb_shinfo(skb)->nr_frags) {
skb_shinfo(skb)->xdp_frags_size = skb->data_len;
xdp_buff_set_frags_flag(xdp);
} else {
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index d834a4865aec..1ded27768a97 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1850,7 +1850,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
if (dev->flags & IFF_NOARP)
goto out;
- if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
+ if (!pskb_network_may_pull(skb, arp_hdr_len(dev))) {
dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
@@ -2111,7 +2111,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct iphdr *pip;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return false;
pip = ip_hdr(skb);
n = neigh_lookup(&arp_tbl, &pip->daddr, dev);
@@ -2137,7 +2137,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
*/
if (!ipv6_mod_enabled())
return false;
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
pip6 = ipv6_hdr(skb);
n = neigh_lookup(&nd_tbl, &pip6->daddr, dev);
@@ -2159,13 +2159,19 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
}
if (n) {
+ u8 haddr[ETH_ALEN];
bool diff;
- diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha);
+ neigh_ha_snapshot(haddr, n, dev);
+ diff = !ether_addr_equal_unaligned(eth_hdr(skb)->h_dest, haddr);
if (diff) {
+ if (skb_cow_head(skb, 0)) {
+ neigh_release(n);
+ return false;
+ }
memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
dev->addr_len);
- memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);
+ memcpy(eth_hdr(skb)->h_dest, haddr, dev->addr_len);
}
neigh_release(n);
return diff;
@@ -2757,8 +2763,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
return arp_reduce(dev, skb, vni);
#if IS_ENABLED(CONFIG_IPV6)
else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
- pskb_may_pull(skb, sizeof(struct ipv6hdr) +
- sizeof(struct nd_msg)) &&
+ pskb_network_may_pull(skb, sizeof(struct ipv6hdr) +
+ sizeof(struct nd_msg)) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1);
@@ -2796,6 +2802,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
(ntohs(eth->h_proto) == ETH_P_IP ||
ntohs(eth->h_proto) == ETH_P_IPV6)) {
did_rsc = route_shortcircuit(dev, skb);
+ eth = eth_hdr(skb);
if (did_rsc)
f = vxlan_find_mac_tx(vxlan, eth->h_dest, vni);
}
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index af7a0d7f95a5..9a9038ae90c1 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -1631,7 +1631,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return NULL;
group.dst.sa.sa_family = AF_INET;
group.dst.sin.sin_addr.s_addr = ip_hdr(skb)->daddr;
@@ -1640,7 +1640,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return NULL;
group.dst.sa.sa_family = AF_INET6;
group.dst.sin6.sin6_addr = ipv6_hdr(skb)->daddr;
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 742d4fd1b598..e87165e4f4b3 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1544,6 +1544,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
}
wiphy_unlock(ah->hw->wiphy);
+
+ complete(&ah->peer_ml_id_done);
}
wake_up(&ab->wmi_ab.tx_credits_wq);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index fc5127b5c1a3..30726e580833 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -72,6 +72,7 @@
#define ATH12K_MAX_MLO_PEERS 256
#define ATH12K_MLO_PEER_ID_INVALID 0xFFFF
+#define ATH12K_MLO_PEER_ID_PENDING 0xFFFE
#define ATH12K_INVALID_RSSI_FULL -1
#define ATH12K_INVALID_RSSI_EMPTY -128
@@ -793,6 +794,8 @@ struct ath12k_hw {
enum ath12k_hw_state state;
bool regd_updated;
bool use_6ghz_regd;
+ bool host_alloc_ml_id;
+ struct completion peer_ml_id_done;
u8 num_radio;
diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c
index 52e10059c6d5..68968f96b4f1 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.c
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.c
@@ -6,6 +6,7 @@
#include "core.h"
#include "peer.h"
+#include "dp_peer.h"
#include "htc.h"
#include "dp_htt.h"
#include "debugfs_htt_stats.h"
@@ -575,6 +576,51 @@ exit:
rcu_read_unlock();
}
+static void ath12k_dp_htt_mlo_peer_map_handler(struct ath12k_base *ab,
+ struct sk_buff *skb)
+{
+ struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data;
+ struct htt_t2h_mlo_peer_map_event *ev = &resp->mlo_peer_map_ev;
+ u16 raw_peer_id, peer_id, addr_h16;
+ u8 peer_addr[ETH_ALEN];
+ int ret;
+
+ if (skb->len < sizeof(*ev)) {
+ ath12k_warn(ab, "unexpected htt mlo peer map event len %u\n",
+ skb->len);
+ return;
+ }
+
+ raw_peer_id = le32_get_bits(ev->info0,
+ HTT_T2H_MLO_PEER_MAP_INFO0_MLO_PEER_ID);
+ peer_id = raw_peer_id | ATH12K_PEER_ML_ID_VALID;
+
+ addr_h16 = le32_get_bits(ev->info1,
+ HTT_T2H_MLO_PEER_MAP_INFO1_MAC_ADDR_H16);
+ ath12k_dp_get_mac_addr(le32_to_cpu(ev->mac_addr_l32), addr_h16,
+ peer_addr);
+
+ ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt mlo peer map peer %pM id %u\n",
+ peer_addr, peer_id);
+
+ /*
+ * Fix up the dp_peer entry created with ATH12K_MLO_PEER_ID_PENDING
+ * earlier; on chips with host_alloc_ml_id == false this is the only
+ * point at which the host learns the firmware-assigned ID. Chips
+ * that allocate the ID on the host also receive this event but the
+ * firmware-reported ID matches the host-allocated one, so there is
+ * nothing to fix up.
+ */
+ if (!ab->hw_params->host_alloc_ml_id) {
+ ret = ath12k_dp_peer_fixup_peer_id(ab, peer_addr,
+ peer_id);
+ if (ret)
+ ath12k_warn(ab,
+ "failed to fix up peer id %u for dp peer %pM: %d\n",
+ peer_id, peer_addr, ret);
+ }
+}
+
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
struct sk_buff *skb)
{
@@ -659,6 +705,9 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
case HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND:
ath12k_htt_mlo_offset_event_handler(ab, skb);
break;
+ case HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP:
+ ath12k_dp_htt_mlo_peer_map_handler(ab, skb);
+ break;
default:
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt event %d not handled\n",
type);
diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.h b/drivers/net/wireless/ath/ath12k/dp_htt.h
index 987689f11cda..2db7fb27c036 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.h
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.h
@@ -930,6 +930,7 @@ enum htt_t2h_msg_type {
HTT_T2H_MSG_TYPE_EXT_STATS_CONF = 0x1c,
HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND = 0x24,
HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND = 0x28,
+ HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP = 0x29,
HTT_T2H_MSG_TYPE_PEER_MAP3 = 0x2b,
HTT_T2H_MSG_TYPE_VDEV_TXRX_STATS_PERIODIC_IND = 0x2c,
};
@@ -974,11 +975,22 @@ struct htt_t2h_peer_unmap_event {
__le32 info1;
} __packed;
+#define HTT_T2H_MLO_PEER_MAP_INFO0_MLO_PEER_ID GENMASK(23, 8)
+#define HTT_T2H_MLO_PEER_MAP_INFO1_MAC_ADDR_H16 GENMASK(15, 0)
+
+struct htt_t2h_mlo_peer_map_event {
+ __le32 info0;
+ __le32 mac_addr_l32;
+ __le32 info1;
+ __le32 reserved[5];
+} __packed;
+
struct htt_resp_msg {
union {
struct htt_t2h_version_conf_msg version_msg;
struct htt_t2h_peer_map_event peer_map_ev;
struct htt_t2h_peer_unmap_event peer_unmap_ev;
+ struct htt_t2h_mlo_peer_map_event mlo_peer_map_ev;
};
} __packed;
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c
index a12073afc307..bb5341b4251a 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
@@ -475,7 +475,9 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
dp_peer->is_mlo = params->is_mlo;
/*
- * For MLO client, the host assigns the ML peer ID, so set peer_id in dp_peer
+ * For MLO client, the ML peer ID, either known or PENDING, needs to be
+ * initialized here since the following logic depends on it.
+ *
* For non-MLO client, host gets link peer ID from firmware and will be
* assigned at the time of link peer creation
*/
@@ -491,13 +493,17 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
list_add(&dp_peer->list, &dp_hw->dp_peers_list);
/*
- * For MLO client, the peer_id for ath12k_dp_peer is allocated by host
- * and that peer_id is known at this point, and hence this ath12k_dp_peer
- * can be added to the RCU table using the peer_id.
- * For non-MLO client, this addition to RCU table shall be done at the
- * time of assignment of ath12k_dp_link_peer to ath12k_dp_peer.
+ * For an MLO client whose ML peer ID is allocated by the host, the
+ * peer_id is known here and the dp_peer can be added to the RCU
+ * table using it. For an MLO client on chips where the firmware
+ * allocates the ID, peer_id is ATH12K_MLO_PEER_ID_PENDING and the
+ * RCU table publish is deferred to the
+ * HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For a non-MLO client
+ * the publish happens later, at the time of assignment of
+ * ath12k_dp_link_peer to ath12k_dp_peer.
*/
- if (dp_peer->is_mlo)
+ if (dp_peer->is_mlo &&
+ dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
spin_unlock_bh(&dp_hw->peer_lock);
@@ -518,7 +524,8 @@ void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
return;
}
- if (dp_peer->is_mlo)
+ if (dp_peer->is_mlo &&
+ dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
list_del(&dp_peer->list);
@@ -695,3 +702,55 @@ void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
if (rx_stats)
memset(rx_stats, 0, sizeof(*rx_stats));
}
+
+int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab,
+ const u8 *peer_addr, u16 peer_id)
+{
+ struct ath12k_dp_link_peer *link_peer;
+ struct ath12k_dp_peer *dp_peer = NULL;
+ struct ath12k_hw_group *ag = ab->ag;
+ struct ath12k_dp_hw *dp_hw = NULL;
+ struct ath12k_hw *ah;
+ int i;
+
+ if (peer_id >= (ATH12K_PEER_ML_ID_VALID | ATH12K_MAX_MLO_PEERS))
+ return -EINVAL;
+
+ for (i = 0; i < ag->num_hw; i++) {
+ ah = ag->ah[i];
+ if (!ah)
+ continue;
+
+ spin_lock_bh(&ah->dp_hw.peer_lock);
+ dp_peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw,
+ (u8 *)peer_addr);
+ if (dp_peer) {
+ dp_hw = &ah->dp_hw;
+ break;
+ }
+ spin_unlock_bh(&ah->dp_hw.peer_lock);
+ }
+
+ if (!dp_peer)
+ return -ENOENT;
+
+ /* dp_hw->peer_lock is held */
+
+ dp_peer->peer_id = peer_id;
+ rcu_assign_pointer(dp_hw->dp_peers[peer_id], dp_peer);
+
+ for (i = 0; i < ATH12K_NUM_MAX_LINKS; i++) {
+ link_peer = rcu_dereference_protected(dp_peer->link_peers[i],
+ lockdep_is_held(&dp_hw->peer_lock));
+ if (link_peer)
+ link_peer->ml_id = peer_id;
+ }
+
+ ath12k_sta_to_ahsta(dp_peer->sta)->ml_peer_id = peer_id;
+
+ spin_unlock_bh(&dp_hw->peer_lock);
+
+ complete(&ah->peer_ml_id_done);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 7c9709bf717b..3503840b0329 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -181,4 +181,6 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id);
void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer);
+int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab, const u8 *peer_addr,
+ u16 peer_id);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 86fb8b719613..8d2fa0bfb96c 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -236,6 +236,8 @@ struct ath12k_hw_params {
u32 max_client_dbs;
u32 max_client_dbs_sbs;
} client;
+
+ bool host_alloc_ml_id;
};
struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 51c4df32e716..a0928890671a 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -1282,13 +1282,17 @@ void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah)
struct ath12k_dp_peer *dp_peer, *tmp;
struct ath12k_dp_hw *dp_hw = &ah->dp_hw;
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
INIT_LIST_HEAD(&peers);
spin_lock_bh(&dp_hw->peer_lock);
list_for_each_entry_safe(dp_peer, tmp, &dp_hw->dp_peers_list, list) {
if (dp_peer->is_mlo) {
- rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
- clear_bit(dp_peer->peer_id, ah->free_ml_peer_id_map);
+ if (dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
+ rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id],
+ NULL);
+ ath12k_peer_ml_free(ah, ath12k_sta_to_ahsta(dp_peer->sta));
}
list_move(&dp_peer->list, &peers);
@@ -3531,11 +3535,16 @@ static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta,
struct ath12k_sta *ahsta = arsta->ahsta;
struct ath12k_link_sta *arsta_p;
struct ath12k_link_vif *arvif;
+ struct ath12k_hw *ah = arsta->arvif->ar->ah;
unsigned long links;
u8 link_id;
int i;
- if (!sta->mlo || ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID)
+ if (!sta->mlo)
+ return;
+
+ if (ah->host_alloc_ml_id &&
+ ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID)
return;
ml->enabled = true;
@@ -3543,12 +3552,25 @@ static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta,
/* For now considering the primary umac based on assoc link */
ml->primary_umac = arsta->is_assoc_link;
- ml->peer_id_valid = true;
+ /*
+ * Only chips that allocate the MLD peer ID on the host send a valid
+ * ml_peer_id in WMI_PEER_ASSOC_CMDID. For chips where the firmware
+ * picks the ID, leave peer_id_valid false to avoid unexpected issues.
+ */
+ ml->peer_id_valid = ah->host_alloc_ml_id;
ml->logical_link_idx_valid = true;
ether_addr_copy(ml->mld_addr, sta->addr);
ml->logical_link_idx = arsta->link_idx;
- ml->ml_peer_id = ahsta->ml_peer_id;
+ /*
+ * WMI_MLO_PEER_ASSOC_PARAMS expects the raw ML peer ID without
+ * the host-side ATH12K_PEER_ML_ID_VALID bookkeeping bit. For chips
+ * where the firmware allocates the ID, the field is unused (the
+ * firmware always allocates regardless of the value here); send 0
+ * to make that intent explicit.
+ */
+ ml->ml_peer_id = ah->host_alloc_ml_id ?
+ (ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID) : 0;
ml->ieee_link_id = arsta->link_id;
ml->num_partner_links = 0;
ml->eml_cap = sta->eml_cap;
@@ -3595,8 +3617,6 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar,
memset(arg, 0, sizeof(*arg));
- reinit_completion(&ar->peer_assoc_done);
-
arg->peer_new_assoc = !reassoc;
ath12k_peer_assoc_h_basic(ar, arvif, arsta, arg);
ath12k_peer_assoc_h_crypto(ar, arvif, arsta, arg);
@@ -3836,6 +3856,52 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar,
return bw;
}
+static int ath12k_mac_peer_assoc(struct ath12k *ar,
+ struct ath12k_wmi_peer_assoc_arg *peer_arg)
+{
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ int ret;
+
+ reinit_completion(&ar->peer_assoc_done);
+ reinit_completion(&ah->peer_ml_id_done);
+
+ ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
+ peer_arg->peer_mac, peer_arg->vdev_id, ret);
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
+ ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+ peer_arg->peer_mac, peer_arg->vdev_id);
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * For devices where the firmware allocates the MLD peer ID, the host
+ * learns the real ID only from the MLO_RX_PEER_MAP HTT event, which is
+ * handled in a softirq (BH workqueue) context that cannot take the
+ * wiphy lock. Block here, while still holding the wiphy lock, until
+ * that event has fixed up the ID. This serialises the fixup against
+ * all other wiphy-locked ml_peer_id accesses.
+ *
+ * The firmware sends the event only once, in response to the assoc-link
+ * peer assoc, so block only for that link.
+ */
+ if (!ah->host_alloc_ml_id &&
+ peer_arg->is_assoc &&
+ peer_arg->ml.enabled &&
+ peer_arg->ml.assoc_link &&
+ !wait_for_completion_timeout(&ah->peer_ml_id_done, 1 * HZ)) {
+ ath12k_warn(ar->ab, "failed to get MLO peer map event for %pM vdev %i\n",
+ peer_arg->peer_mac, peer_arg->vdev_id);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static void ath12k_bss_assoc(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *bss_conf)
@@ -3916,18 +3982,10 @@ static void ath12k_bss_assoc(struct ath12k *ar,
}
peer_arg->is_assoc = true;
- ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (ret) {
- ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
- bss_conf->bssid, arvif->vdev_id, ret);
- return;
- }
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- bss_conf->bssid, arvif->vdev_id);
+ ret = ath12k_mac_peer_assoc(ar, peer_arg);
+ if (ret)
return;
- }
ret = ath12k_setup_peer_smps(ar, arvif, bss_conf->bssid,
&link_sta->ht_cap, &link_sta->he_6ghz_capa);
@@ -6481,18 +6539,10 @@ static int ath12k_mac_station_assoc(struct ath12k *ar,
}
peer_arg->is_assoc = true;
- ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (ret) {
- ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
- arsta->addr, arvif->vdev_id, ret);
- return ret;
- }
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- arsta->addr, arvif->vdev_id);
- return -ETIMEDOUT;
- }
+ ret = ath12k_mac_peer_assoc(ar, peer_arg);
+ if (ret)
+ return ret;
num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask);
@@ -6841,14 +6891,8 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
peer_arg, true);
peer_arg->is_assoc = false;
- err = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (err)
- ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
- arsta->addr, arvif->vdev_id, err);
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ))
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- arsta->addr, arvif->vdev_id);
+ ath12k_mac_peer_assoc(ar, peer_arg);
}
}
}
@@ -7266,10 +7310,8 @@ static void ath12k_mac_ml_station_remove(struct ath12k_vif *ahvif,
ath12k_mac_free_unassign_link_sta(ah, ahsta, link_id);
}
- if (sta->mlo) {
- clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
- ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
- }
+ if (sta->mlo)
+ ath12k_peer_ml_free(ah, ahsta);
}
static int ath12k_mac_handle_link_sta_state(struct ieee80211_hw *hw,
@@ -7733,15 +7775,23 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
/* ML sta */
if (sta->mlo && !ahsta->links_map &&
(hweight16(sta->valid_links) == 1)) {
- ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
- if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
- ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
- sta->addr);
- goto exit;
+ if (ah->host_alloc_ml_id) {
+ ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
+ if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
+ ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
+ sta->addr);
+ goto exit;
+ }
+ } else {
+ /*
+ * firmware allocates the ML peer ID and notifies
+ * the host via HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP
+ */
+ ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_PENDING;
}
dp_params.is_mlo = true;
- dp_params.peer_id = ahsta->ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+ dp_params.peer_id = ahsta->ml_peer_id;
}
dp_params.sta = sta;
@@ -7878,10 +7928,8 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
peer_delete:
ath12k_dp_peer_delete(&ah->dp_hw, sta->addr, sta);
ml_peer_id_clear:
- if (sta->mlo) {
- clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
- ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
- }
+ if (sta->mlo)
+ ath12k_peer_ml_free(ah, ahsta);
exit:
/* update the state if everything went well */
if (!ret)
@@ -15310,6 +15358,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
ah->num_radio = num_pdev_map;
mutex_init(&ah->hw_mutex);
+ init_completion(&ah->peer_ml_id_done);
spin_lock_init(&ah->dp_hw.peer_lock);
INIT_LIST_HEAD(&ah->dp_hw.dp_peers_list);
@@ -15384,8 +15433,9 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
int mac_id, device_id, total_radio, num_hw;
struct ath12k_base *ab;
struct ath12k_hw *ah;
- int ret, i, j;
+ bool conf = false;
u8 radio_per_hw;
+ int ret, i, j;
total_radio = 0;
for (i = 0; i < ag->num_devices; i++) {
@@ -15425,6 +15475,20 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
}
ab = ag->ab[device_id];
+
+ /*
+ * the assumption is all devices within an ah
+ * share the same host_alloc_ml_id configuration
+ */
+ if (j == 0) {
+ conf = ab->hw_params->host_alloc_ml_id;
+ } else if (conf != ab->hw_params->host_alloc_ml_id) {
+ ath12k_warn(ab, "inconsistent ML ID config within ah, device 0 uses %s allocated ID, while device %u doesn't\n",
+ conf ? "host" : "firmware", device_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
pdev_map[j].ab = ab;
pdev_map[j].pdev_idx = mac_id;
mac_id++;
@@ -15449,6 +15513,7 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
}
ah->dev = ab->dev;
+ ah->host_alloc_ml_id = conf;
ag->ah[i] = ah;
ag->num_hw++;
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 2681a047d4d5..ed0524ddff80 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -230,7 +230,16 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
/* Fill ML info into created peer */
if (sta->mlo) {
ml_peer_id = ahsta->ml_peer_id;
- peer->ml_id = ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+ /*
+ * For chips where firmware allocates the ML peer ID,
+ * ml_peer_id is ATH12K_MLO_PEER_ID_PENDING here. The
+ * MLO_RX_PEER_MAP HTT event handler fixes up
+ * peer->ml_id once the ID is known.
+ */
+ if (ml_peer_id == ATH12K_MLO_PEER_ID_PENDING)
+ peer->ml_id = ATH12K_MLO_PEER_ID_INVALID;
+ else
+ peer->ml_id = ml_peer_id;
ether_addr_copy(peer->ml_addr, sta->addr);
/* the assoc link is considered primary for now */
@@ -276,9 +285,25 @@ u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
}
if (ml_peer_id == ATH12K_MAX_MLO_PEERS)
- ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
+ return ATH12K_MLO_PEER_ID_INVALID;
- return ml_peer_id;
+ return ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+}
+
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta)
+{
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ /*
+ * Only devices that allocate the ID on the host own a slot in
+ * free_ml_peer_id_map.
+ */
+ if (ah->host_alloc_ml_id &&
+ (ahsta->ml_peer_id <
+ (ATH12K_MAX_MLO_PEERS | ATH12K_PEER_ML_ID_VALID)))
+ clear_bit(ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID,
+ ah->free_ml_peer_id_map);
+ ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
}
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta)
diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
index 49d89796bc46..0f7f25b8e89c 100644
--- a/drivers/net/wireless/ath/ath12k/peer.h
+++ b/drivers/net/wireless/ath/ath12k/peer.h
@@ -26,4 +26,5 @@ int ath12k_link_sta_rhash_add(struct ath12k_base *ab, struct ath12k_link_sta *ar
struct ath12k_link_sta *ath12k_link_sta_find_by_addr(struct ath12k_base *ab,
const u8 *addr);
u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah);
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta);
#endif /* _PEER_H_ */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index d9fdd2fc8298..03dedfd907fc 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -442,6 +442,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "wcn7850 hw2.0",
@@ -533,6 +535,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = false,
},
{
.name = "qcn9274 hw2.0",
@@ -620,6 +624,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "ipq5332 hw1.0",
@@ -700,6 +706,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "qcc2072 hw1.0",
@@ -792,6 +800,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = false,
},
{
.name = "ipq5424 hw1.0",
@@ -876,6 +886,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
};
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 8d0ff339ad08..0bb807ff8edf 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -2179,8 +2179,8 @@ il_remove_station(struct il_priv *il, const u8 sta_id, const u8 * addr)
il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE;
il->num_stations--;
-
- BUG_ON(il->num_stations < 0);
+ if (WARN_ON(il->num_stations < 0))
+ il->num_stations = 0;
spin_unlock_irqrestore(&il->sta_lock, flags);
@@ -2328,7 +2328,8 @@ il_dealloc_bcast_stations(struct il_priv *il)
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
il->num_stations--;
- BUG_ON(il->num_stations < 0);
+ if (WARN_ON(il->num_stations < 0))
+ il->num_stations = 0;
kfree(il->stations[i].lq);
il->stations[i].lq = NULL;
}
diff --git a/drivers/net/wireless/intel/iwlegacy/debug.c b/drivers/net/wireless/intel/iwlegacy/debug.c
index d998a3f1b056..8a9f79ff1c6e 100644
--- a/drivers/net/wireless/intel/iwlegacy/debug.c
+++ b/drivers/net/wireless/intel/iwlegacy/debug.c
@@ -396,7 +396,7 @@ il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count,
int i, j, pos = 0;
ssize_t ret;
/* Add 30 for initial string */
- const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations);
+ const size_t bufsz = 30 + sizeof(char) * 500 * max_sta;
buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index 610ec8302adf..9deb47f22a61 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -44,7 +44,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
mwifiex_process_tdls_action_frame(priv,
(u8 *)rx_hdr,
- skb->len);
+ rx_skb->len);
}
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index cf4aab11e9b1..499d37ceae21 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -753,6 +753,7 @@ EXPORT_SYMBOL(of_property_read_reg);
static int parser_init(struct of_pci_range_parser *parser,
struct device_node *node, const char *name)
{
+ const __be32 *range;
int rlen;
parser->node = node;
@@ -761,12 +762,20 @@ static int parser_init(struct of_pci_range_parser *parser,
parser->ns = of_bus_n_size_cells(node);
parser->dma = !strcmp(name, "dma-ranges");
parser->bus = of_match_bus(node);
+ parser->range = NULL;
+ parser->end = NULL;
- parser->range = of_get_property(node, name, &rlen);
- if (parser->range == NULL)
+ range = of_get_property(node, name, &rlen);
+ if (!range)
return -ENOENT;
- parser->end = parser->range + rlen / sizeof(__be32);
+ if (!parser->bus ||
+ !OF_CHECK_COUNTS(parser->na, parser->ns) ||
+ !OF_CHECK_ADDR_COUNT(parser->pna))
+ return -EINVAL;
+
+ parser->range = range;
+ parser->end = range + rlen / sizeof(__be32);
return 0;
}
@@ -792,7 +801,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
int na = parser->na;
int ns = parser->ns;
int np = parser->pna + na + ns;
- int busflag_na = parser->bus->flag_cells;
+ int busflag_na;
if (!range)
return NULL;
@@ -800,6 +809,8 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
if (!parser->range || parser->range + np > parser->end)
return NULL;
+ busflag_na = parser->bus->flag_cells;
+
range->flags = parser->bus->get_flags(parser->range);
range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
@@ -976,8 +987,7 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
np = of_root;
ranges = of_get_property(np, "dma-ranges", &len);
- if (ranges && len) {
- of_dma_range_parser_init(&parser, np);
+ if (ranges && len && !of_dma_range_parser_init(&parser, np)) {
for_each_of_range(&parser, &range)
if (range.cpu_addr + range.size > cpu_end)
cpu_end = range.cpu_addr + range.size - 1;
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 82222bd45ac6..42e3e2d8a2b8 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -359,6 +359,7 @@ int __init fdt_scan_reserved_mem(void)
err = __reserved_mem_reserve_reg(child, uname);
if (!err)
count++;
+
/*
* Save the nodes for the dynamically-placed regions
* into an array which will be used for allocation right
@@ -366,10 +367,17 @@ int __init fdt_scan_reserved_mem(void)
* or marked as no-map. This is done to avoid dynamically
* allocating from one of the statically-placed regions.
*/
- if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) {
- dynamic_nodes[dynamic_nodes_cnt] = child;
- dynamic_nodes_cnt++;
+ if (err != -ENOENT || !of_get_flat_dt_prop(child, "size", NULL))
+ continue;
+
+ if (dynamic_nodes_cnt == MAX_RESERVED_REGIONS) {
+ pr_err("too many defined dynamic regions, skip '%s'\n",
+ uname);
+ continue;
}
+
+ dynamic_nodes[dynamic_nodes_cnt] = child;
+ dynamic_nodes_cnt++;
}
for (int i = 0; i < dynamic_nodes_cnt; i++) {
const char *uname;
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 98e1db751132..f7389b5437df 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -680,21 +680,12 @@ static int imx_pcie_attach_pd(struct device *dev)
static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
- if (enable) {
- /* power up core phy and enable ref clock */
- regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD);
- /*
- * The async reset input need ref clock to sync internally,
- * when the ref clock comes after reset, internal synced
- * reset time is too short, cannot meet the requirement.
- * Add a ~10us delay here.
- */
- usleep_range(10, 100);
- regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN);
- } else {
- regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN);
- regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD);
- }
+ if (enable)
+ regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_REF_CLK_EN);
+ else
+ regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_REF_CLK_EN);
return 0;
}
@@ -825,8 +816,16 @@ static int imx6sx_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
{
+ if (assert)
+ regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD);
+ else
+ regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD);
+
regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_SW_RST,
assert ? IMX6Q_GPR1_PCIE_SW_RST : 0);
+
if (!assert)
usleep_range(200, 500);
@@ -835,11 +834,15 @@ static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
static int imx6q_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
{
- if (!assert)
- return 0;
+ if (assert)
+ regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD);
+ else
+ regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD);
- regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD);
- regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN);
+ if (!assert)
+ usleep_range(200, 500);
return 0;
}
@@ -1445,6 +1448,7 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
return 0;
err_phy_off:
+ imx_pcie_assert_core_reset(imx_pcie);
phy_power_off(imx_pcie->phy);
err_phy_exit:
phy_exit(imx_pcie->phy);
@@ -1466,6 +1470,7 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct imx_pcie *imx_pcie = to_imx_pcie(pci);
+ imx_pcie_assert_core_reset(imx_pcie);
if (imx_pcie->phy) {
if (phy_power_off(imx_pcie->phy))
dev_err(pci->dev, "unable to power off PHY\n");
@@ -1995,7 +2000,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
.flags = IMX_PCIE_FLAG_IMX_PHY |
IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
IMX_PCIE_FLAG_BROKEN_SUSPEND |
- IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
+ IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP,
.dbi_length = 0x200,
.gpr = "fsl,imx6q-iomuxc-gpr",
.ltssm_off = IOMUXC_GPR12,
@@ -2011,7 +2017,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
.flags = IMX_PCIE_FLAG_IMX_PHY |
IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
IMX_PCIE_FLAG_SKIP_L23_READY |
- IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
+ IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP,
.gpr = "fsl,imx6q-iomuxc-gpr",
.ltssm_off = IOMUXC_GPR12,
.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2,
@@ -2026,7 +2033,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
.flags = IMX_PCIE_FLAG_IMX_PHY |
IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
IMX_PCIE_FLAG_SKIP_L23_READY |
- IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
+ IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+ IMX_PCIE_FLAG_KEEP_MSI_CAP,
.dbi_length = 0x200,
.gpr = "fsl,imx6q-iomuxc-gpr",
.ltssm_off = IOMUXC_GPR12,
diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
index 0bec8657149c..275df38256de 100644
--- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c
@@ -221,7 +221,7 @@ disable_repeater:
disable_vreg:
regulator_bulk_disable(M31_EUSB_NUM_VREGS, phy->vregs);
- return 0;
+ return ret;
}
static int m31eusb2_phy_exit(struct phy *uphy)
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 2b0f152f5470..7843356a4dd4 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -452,9 +452,6 @@ static void rk_combphy_common_cfg_ssc(struct rockchip_combphy_priv *priv, unsign
struct device_node *np = priv->dev->of_node;
u32 val;
- if (!priv->enable_ssc)
- return;
-
/* Set SSC downward spread spectrum for PCIe and USB3 */
if (priv->type == PHY_TYPE_PCIE || priv->type == PHY_TYPE_USB3) {
val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD);
@@ -471,6 +468,9 @@ static void rk_combphy_common_cfg_ssc(struct rockchip_combphy_priv *priv, unsign
RK3568_PHYREG32);
}
+ if (!priv->enable_ssc)
+ return;
+
/* Enable SSC */
val = readl(priv->mmio + RK3568_PHYREG8);
val |= RK3568_PHYREG8_SSC_EN;
diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index fe6b4925d166..240626b55475 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -53,7 +53,7 @@
#define L0_TM_DIG_6 0x106c
#define L0_TM_DIS_DESCRAMBLE_DECODER 0x0f
#define L0_TX_DIG_61 0x00f4
-#define L0_TM_DISABLE_SCRAMBLE_ENCODER 0x0f
+#define L0_TM_DISABLE_SCRAMBLE_ENCODER (BIT(3) | GENMASK(1, 0))
/* PLL Test Mode register parameters */
#define L0_TM_PLL_DIG_37 0x2094
@@ -502,11 +502,30 @@ static void xpsgtr_lane_set_protocol(struct xpsgtr_phy *gtr_phy)
}
}
-/* Bypass (de)scrambler and 8b/10b decoder and encoder. */
-static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
+/**
+ * xpsgtr_bypass_scrambler_8b10b - Configure scrambler/encoder behavior
+ * @gtr_phy: pointer to lane context
+ * @bypass: true to enable scrambler/encoder bypass (SATA/SGMII),
+ * false to disable scrambler/encoder bypass (USB3)
+ *
+ * Uses RMW to preserve reserved and unrelated register fields.
+ */
+static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy,
+ bool bypass)
{
- xpsgtr_write_phy(gtr_phy, L0_TM_DIG_6, L0_TM_DIS_DESCRAMBLE_DECODER);
- xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61, L0_TM_DISABLE_SCRAMBLE_ENCODER);
+ if (bypass) {
+ xpsgtr_clr_set_phy(gtr_phy, L0_TM_DIG_6,
+ L0_TM_DIS_DESCRAMBLE_DECODER,
+ L0_TM_DIS_DESCRAMBLE_DECODER);
+ xpsgtr_clr_set_phy(gtr_phy, L0_TX_DIG_61,
+ L0_TM_DISABLE_SCRAMBLE_ENCODER,
+ L0_TM_DISABLE_SCRAMBLE_ENCODER);
+ } else {
+ xpsgtr_clr_set_phy(gtr_phy, L0_TM_DIG_6,
+ L0_TM_DIS_DESCRAMBLE_DECODER, 0);
+ xpsgtr_clr_set_phy(gtr_phy, L0_TX_DIG_61,
+ L0_TM_DISABLE_SCRAMBLE_ENCODER, 0);
+ }
}
/* DP-specific initialization. */
@@ -527,7 +546,7 @@ static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
{
struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
- xpsgtr_bypass_scrambler_8b10b(gtr_phy);
+ xpsgtr_bypass_scrambler_8b10b(gtr_phy, true);
writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
}
@@ -543,7 +562,7 @@ static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, mask, val);
xpsgtr_clr_set(gtr_dev, RX_PROT_BUS_WIDTH, mask, val);
- xpsgtr_bypass_scrambler_8b10b(gtr_phy);
+ xpsgtr_bypass_scrambler_8b10b(gtr_phy, true);
}
/* Configure TX de-emphasis and margining for DP. */
@@ -658,12 +677,13 @@ static int xpsgtr_phy_init(struct phy *phy)
{
struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
- int ret = 0;
+ int ret;
mutex_lock(&gtr_dev->gtr_mutex);
/* Configure and enable the clock when peripheral phy_init call */
- if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
+ ret = clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]);
+ if (ret)
goto out;
/* Skip initialization if not required. */
@@ -673,7 +693,7 @@ static int xpsgtr_phy_init(struct phy *phy)
if (gtr_dev->tx_term_fix) {
ret = xpsgtr_phy_tx_term_fix(gtr_phy);
if (ret < 0)
- goto out;
+ goto out_disable_clk;
gtr_dev->tx_term_fix = false;
}
@@ -687,7 +707,7 @@ static int xpsgtr_phy_init(struct phy *phy)
*/
ret = xpsgtr_configure_pll(gtr_phy);
if (ret)
- goto out;
+ goto out_disable_clk;
xpsgtr_lane_set_protocol(gtr_phy);
@@ -703,8 +723,16 @@ static int xpsgtr_phy_init(struct phy *phy)
case ICM_PROTOCOL_SGMII:
xpsgtr_phy_init_sgmii(gtr_phy);
break;
+
+ case ICM_PROTOCOL_USB:
+ xpsgtr_bypass_scrambler_8b10b(gtr_phy, false);
+ break;
}
+ goto out;
+
+out_disable_clk:
+ clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
out:
mutex_unlock(&gtr_dev->gtr_mutex);
return ret;
@@ -1039,6 +1067,12 @@ static int xpsgtr_probe(struct platform_device *pdev)
return PTR_ERR(provider);
}
+ gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
+ sizeof(save_reg_address),
+ GFP_KERNEL);
+ if (!gtr_dev->saved_regs)
+ return -ENOMEM;
+
pm_runtime_set_active(gtr_dev->dev);
pm_runtime_enable(gtr_dev->dev);
@@ -1048,12 +1082,6 @@ static int xpsgtr_probe(struct platform_device *pdev)
return ret;
}
- gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
- sizeof(save_reg_address),
- GFP_KERNEL);
- if (!gtr_dev->saved_regs)
- return -ENOMEM;
-
return 0;
}
diff --git a/drivers/platform/x86/dell/dell-dw5826e-reset.c b/drivers/platform/x86/dell/dell-dw5826e-reset.c
index 1ca7c3421bb5..64e6e9b1d7a0 100644
--- a/drivers/platform/x86/dell/dell-dw5826e-reset.c
+++ b/drivers/platform/x86/dell/dell-dw5826e-reset.c
@@ -13,7 +13,7 @@
#include <linux/types.h>
#include <linux/uuid.h>
-#define PALC_DSM_FN_TRIGGER_PLDR BIT(1)
+#define PALC_DSM_FN_TRIGGER_PLDR 1
static guid_t palc_dsm_guid =
GUID_INIT(0x5a1a4bba, 0x8006, 0x487e, 0xbe, 0x0a, 0xac, 0xf5, 0xd8, 0xfd, 0xfe, 0x59);
@@ -66,7 +66,7 @@ static int palc_probe(struct platform_device *pdev)
if (!handle)
return -ENODEV;
- if (!acpi_check_dsm(handle, &palc_dsm_guid, 1, PALC_DSM_FN_TRIGGER_PLDR))
+ if (!acpi_check_dsm(handle, &palc_dsm_guid, 1, BIT(PALC_DSM_FN_TRIGGER_PLDR)))
return -ENODEV;
return 0;
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index c1c12a447178..180bc137a863 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -320,7 +320,7 @@ static const u32 bq25890_tspct_tbl[] = {
145, 140, 130, 120, 115, 110, 100, 90,
80, 70, 60, 50, 40, 30, 20, 10,
0, -10, -20, -30, -40, -60, -70, -80,
- -90, -10, -120, -140, -150, -170, -190, -210,
+ -90, -100, -120, -140, -150, -170, -190, -210,
};
#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl)
diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c
index ced07f71e0a8..ef735f86394e 100644
--- a/drivers/power/supply/macsmc-power.c
+++ b/drivers/power/supply/macsmc-power.c
@@ -86,6 +86,11 @@ struct macsmc_power {
bool has_ch0i; /* Force discharge (Older firmware) */
bool has_ch0c; /* Inhibit charge (Older firmware) */
bool has_chte; /* Inhibit charge (Modern firmware) */
+ /*
+ * Battery critical key is 1 byte and charge key is little endian
+ * (Modern firmware)
+ */
+ bool fw_ge_27;
u8 num_cells;
int nominal_voltage_mv;
@@ -273,6 +278,20 @@ static int macsmc_battery_get_date(const char *s, int *out)
return 0;
}
+static int macsmc_battery_read_bcf0(struct macsmc_power *power, u32 *val)
+{
+ u8 tval = 0;
+ int ret;
+
+ if (power->fw_ge_27) {
+ ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
+ *val = tval;
+ return ret;
+ }
+
+ return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
+}
+
static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
{
bool flag;
@@ -280,7 +299,7 @@ static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
int ret;
/* Check for emergency shutdown condition */
- if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >= 0 && val)
+ if (macsmc_battery_read_bcf0(power, &val) >= 0 && val)
return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
/* Check AC status for whether we could boot in this state */
@@ -303,6 +322,12 @@ static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
}
+static s16 macsmc_swap_b0rm(struct macsmc_power *power, s16 b0rm)
+{
+ /* B0RM was Big Endian, likely pass through from TI gas gauge */
+ return power->fw_ge_27 ? b0rm : (s16)swab16(b0rm);
+}
+
static int macsmc_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -397,8 +422,7 @@ static int macsmc_battery_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
- /* B0RM is Big Endian, likely pass through from TI gas gauge */
- val->intval = (s16)swab16(vu16) * 1000;
+ val->intval = macsmc_swap_b0rm(power, vu16) * 1000;
break;
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16);
@@ -410,8 +434,7 @@ static int macsmc_battery_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
- /* B0RM is Big Endian, likely pass through from TI gas gauge */
- val->intval = (s16)swab16(vu16) * power->nominal_voltage_mv;
+ val->intval = macsmc_swap_b0rm(power, vu16) * power->nominal_voltage_mv;
break;
case POWER_SUPPLY_PROP_TEMP:
ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AT), &vu16);
@@ -577,7 +600,7 @@ static void macsmc_power_critical_work(struct work_struct *wrk)
* Check if SMC flagged the battery as empty.
* We trigger a graceful shutdown to let the OS save data.
*/
- if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &bcf0) == 0 && bcf0 != 0) {
+ if (macsmc_battery_read_bcf0(power, &bcf0) == 0 && bcf0 != 0) {
power->orderly_shutdown_triggered = true;
dev_crit(power->dev, "Battery critical (empty flag set). Triggering orderly shutdown.\n");
orderly_poweroff(true);
@@ -616,6 +639,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
struct power_supply_config psy_cfg = {};
+ struct apple_smc_key_info info;
struct macsmc_power *power;
bool has_battery = false;
bool has_ac_adapter = false;
@@ -714,6 +738,20 @@ static int macsmc_power_probe(struct platform_device *pdev)
if (apple_smc_key_exists(smc, SMC_KEY(CH0I)))
power->has_ch0i = true;
+ ret = apple_smc_get_key_info(power->smc, SMC_KEY(BCF0), &info);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to determine BCF0 key size\n");
+ return ret;
+ }
+ if (info.size == 1)
+ power->fw_ge_27 = true;
+ else if (info.size == 4)
+ power->fw_ge_27 = false;
+ else {
+ dev_err(&pdev->dev, "Unexpected BCF0 key size %d\n", info.size);
+ return -EIO;
+ }
+
/* Reset "Optimised Battery Charging" flags to default state */
if (power->has_chte)
apple_smc_write_u32(smc, SMC_KEY(CHTE), 0);
@@ -766,7 +804,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->num_cells;
/* Enable critical shutdown notifications by reading status once */
- apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32);
+ macsmc_battery_read_bcf0(power, &val32);
psy_cfg.drv_data = power;
power->batt = devm_power_supply_register(dev, &power->batt_desc, &psy_cfg);
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index e94d53b36aa4..03ac569e185c 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -405,7 +405,11 @@ static int max17040_get_property(struct power_supply *psy,
val->intval = chip->low_soc_alert;
break;
case POWER_SUPPLY_PROP_STATUS:
- power_supply_get_property_from_supplier(psy, psp, val);
+ ret = power_supply_get_property_from_supplier(psy, psp, val);
+ if (ret == -ENODEV)
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ else if (ret)
+ return ret;
break;
case POWER_SUPPLY_PROP_TEMP:
if (!chip->channel_temp)
diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c
index 5e381c354d74..1c20d7efab92 100644
--- a/drivers/ptp/ptp_netc.c
+++ b/drivers/ptp/ptp_netc.c
@@ -769,6 +769,7 @@ static void netc_timer_init(struct netc_timer *priv)
TMR_CTRL_TE | TMR_CTRL_FS;
netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl);
netc_timer_wr(priv, NETC_TMR_PRSC, priv->oclk_prsc);
+ netc_timer_wr(priv, NETC_TMR_TEMASK, 0);
/* Disable FIPER by default */
fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
@@ -901,6 +902,11 @@ static irqreturn_t netc_timer_isr(int irq, void *data)
/* Clear interrupts status */
netc_timer_wr(priv, NETC_TMR_TEVENT, tmr_event);
+ if (!tmr_event) {
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+ }
+
if (tmr_event & TMR_TEVENT_ALMEN(0))
netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0);
@@ -936,7 +942,8 @@ static int netc_timer_init_msix_irq(struct netc_timer *priv)
}
priv->irq = pci_irq_vector(pdev, 0);
- err = request_irq(priv->irq, netc_timer_isr, 0, priv->irq_name, priv);
+ err = request_irq(priv->irq, netc_timer_isr, IRQF_NO_AUTOEN,
+ priv->irq_name, priv);
if (err) {
dev_err(&pdev->dev, "request_irq() failed\n");
pci_free_irq_vectors(pdev);
@@ -951,7 +958,6 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv)
{
struct pci_dev *pdev = priv->pdev;
- disable_irq(priv->irq);
free_irq(priv->irq, priv);
pci_free_irq_vectors(pdev);
}
@@ -1005,6 +1011,8 @@ static int netc_timer_probe(struct pci_dev *pdev,
goto free_msix_irq;
}
+ enable_irq(priv->irq);
+
return 0;
free_msix_irq:
@@ -1019,9 +1027,10 @@ static void netc_timer_remove(struct pci_dev *pdev)
{
struct netc_timer *priv = pci_get_drvdata(pdev);
+ disable_irq(priv->irq);
+ ptp_clock_unregister(priv->clock);
netc_timer_wr(priv, NETC_TMR_TEMASK, 0);
netc_timer_wr(priv, NETC_TMR_CTRL, 0);
- ptp_clock_unregister(priv->clock);
netc_timer_free_msix_irq(priv);
netc_timer_pci_remove(pdev);
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 3181c06d91ce..d8d912a3b3fe 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -21,6 +21,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
+#include <linux/delay.h>
#include <asm/machine.h>
#include <asm/ccwdev.h>
@@ -2511,6 +2512,13 @@ static inline int _dasd_term_running_cqr(struct dasd_device *device)
if (list_empty(&device->ccw_queue))
return 0;
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
+ /*
+ * Path verification requests must not be terminated. They are critical
+ * for bringing paths back online. Terminating them would cause rc=-EIO
+ * because CLEARED requests skip the retry path.
+ */
+ if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
+ return -EAGAIN;
rc = device->discipline->term_IO(cqr);
if (!rc)
/*
@@ -2535,7 +2543,11 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
return -EIO;
}
spin_lock_irq(get_ccwdev_lock(device->cdev));
- rc = _dasd_term_running_cqr(device);
+ while ((rc = _dasd_term_running_cqr(device)) == -EAGAIN) {
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ msleep(1);
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ }
if (rc) {
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 74fe73b5738a..d356a9f8f016 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -20,6 +20,7 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/overflow.h>
#include <asm/css_chars.h>
#include <asm/machine.h>
@@ -3475,11 +3476,11 @@ static int dasd_eckd_check_device_format(struct dasd_device *base,
{
struct dasd_eckd_private *private = base->private;
struct eckd_count *fmt_buffer;
- struct irb irb;
+ size_t fmt_buffer_size;
+ unsigned int trkcount;
int rpt_max, rpt_exp;
- int fmt_buffer_size;
+ struct irb irb;
int trk_per_cyl;
- int trkcount;
int tpm = 0;
int rc;
@@ -3490,7 +3491,9 @@ static int dasd_eckd_check_device_format(struct dasd_device *base,
rpt_exp = recs_per_track(&private->rdc_data, 0, cdata->expect.blksize);
trkcount = cdata->expect.stop_unit - cdata->expect.start_unit + 1;
- fmt_buffer_size = trkcount * rpt_max * sizeof(struct eckd_count);
+ if (check_mul_overflow(trkcount, rpt_max, &fmt_buffer_size) ||
+ check_mul_overflow(fmt_buffer_size, sizeof(struct eckd_count), &fmt_buffer_size))
+ return -EINVAL;
fmt_buffer = kzalloc(fmt_buffer_size, GFP_KERNEL | GFP_DMA);
if (!fmt_buffer)
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index c85ee42732a3..e5b8b413f5ab 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -324,7 +324,7 @@ out_err:
static int dasd_release_space(struct dasd_device *device,
struct format_data_t *rdata)
{
- if (!device->discipline->is_ese && !device->discipline->is_ese(device))
+ if (!device->discipline->is_ese || !device->discipline->is_ese(device))
return -ENOTSUPP;
if (!device->discipline->release_space)
return -ENOTSUPP;
diff --git a/drivers/s390/crypto/pkey_cca.c b/drivers/s390/crypto/pkey_cca.c
index 4bc47952324e..e8dc2f77c137 100644
--- a/drivers/s390/crypto/pkey_cca.c
+++ b/drivers/s390/crypto/pkey_cca.c
@@ -236,22 +236,16 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
if (hdr->type == TOKTYPE_CCA_INTERNAL &&
hdr->version == TOKVER_CCA_AES) {
/* CCA AES data key */
- if (keylen < sizeof(struct secaeskeytoken))
- return -EINVAL;
- if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
+ if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0))
return -EINVAL;
} else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
hdr->version == TOKVER_CCA_VLSC) {
/* CCA AES cipher key */
- if (keylen < hdr->len)
- return -EINVAL;
if (cca_check_secaescipherkey(pkey_dbf_info,
- 3, key, 0, 1))
+ 3, key, keylen, 0, 1))
return -EINVAL;
} else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
/* CCA ECC (private) key */
- if (keylen < sizeof(struct eccprivkeytoken))
- return -EINVAL;
if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
return -EINVAL;
} else {
@@ -484,7 +478,7 @@ static int cca_verifykey(const u8 *key, u32 keylen,
hdr->version == TOKVER_CCA_AES) {
struct secaeskeytoken *t = (struct secaeskeytoken *)key;
- rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
+ rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0);
if (rc)
goto out;
*keytype = PKEY_TYPE_CCA_DATA;
@@ -512,7 +506,8 @@ static int cca_verifykey(const u8 *key, u32 keylen,
hdr->version == TOKVER_CCA_VLSC) {
struct cipherkeytoken *t = (struct cipherkeytoken *)key;
- rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
+ rc = cca_check_secaescipherkey(pkey_dbf_info, 3,
+ key, keylen, 0, 1);
if (rc)
goto out;
*keytype = PKEY_TYPE_CCA_CIPHER;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index f57189c2b839..ec6a4c2f9f04 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -879,6 +879,7 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
if (perms != &ap_perms && domain < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
+ domain = array_index_nospec(domain, AP_DOMAINS);
if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out;
@@ -1077,8 +1078,9 @@ static long _zcrypt_send_ep11_cprb(u32 xflags, struct ap_perms *perms,
print_hex_dump_debug("ep11req: ", DUMP_PREFIX_ADDRESS, 16, 1,
ap_msg.msg, ap_msg.len, false);
- if (perms != &ap_perms && domain < AUTOSEL_DOM) {
+ if (perms != &ap_perms && domain < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
+ domain = array_index_nospec(domain, AP_DOMAINS);
if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out;
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index 84936a795b95..86d2ee78c9f4 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -62,12 +62,18 @@ static DEFINE_MUTEX(dev_status_mem_mutex);
* also checked. Returns 0 on success or errno value on failure.
*/
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize)
+ const u8 *token, u32 keysize, int keybitsize)
{
struct secaeskeytoken *t = (struct secaeskeytoken *)token;
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -101,14 +107,20 @@ EXPORT_SYMBOL(cca_check_secaeskeytoken);
* Returns 0 on success or errno value on failure.
*/
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize,
- int checkcpacfexport)
+ const u8 *token, u32 keysize,
+ int keybitsize, int checkcpacfexport)
{
struct cipherkeytoken *t = (struct cipherkeytoken *)token;
bool keybitsizeok = true;
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -121,6 +133,18 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
__func__, (int)t->version, TOKVER_CCA_VLSC);
return -EINVAL;
}
+ if (t->len > keysize) {
+ if (dbg)
+ DBF("%s token check failed, len %d > keysize %u\n",
+ __func__, (int)t->len, keysize);
+ return -EINVAL;
+ }
+ if (t->len < sizeof(*t)) {
+ if (dbg)
+ DBF("%s token check failed, len %d < min token size %zu\n",
+ __func__, (int)t->len, sizeof(*t));
+ return -EINVAL;
+ }
if (t->algtype != 0x02) {
if (dbg)
DBF("%s token check failed, algtype 0x%02x != 0x02\n",
@@ -195,6 +219,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL_PKA) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -207,6 +237,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
__func__, (int)t->len, keysize);
return -EINVAL;
}
+ if (t->len < sizeof(*t)) {
+ if (dbg)
+ DBF("%s token check failed, len %d < min token size %zu\n",
+ __func__, (int)t->len, sizeof(*t));
+ return -EINVAL;
+ }
if (t->secid != 0x20) {
if (dbg)
DBF("%s token check failed, secid 0x%02x != 0x20\n",
@@ -443,7 +479,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
/* check secure key token */
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
- prepparm->lv3.keyblock.tok, 8 * keysize);
+ prepparm->lv3.keyblock.tok,
+ seckeysize, 8 * keysize);
if (rc) {
rc = -EIO;
goto out;
@@ -582,7 +619,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
/* check secure key token */
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
- prepparm->lv3.keyblock.tok, 8 * keysize);
+ prepparm->lv3.keyblock.tok,
+ seckeysize, 8 * keysize);
if (rc) {
rc = -EIO;
goto out;
@@ -842,6 +880,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
} kb;
} __packed * prepparm;
struct cipherkeytoken *t;
+ u32 keybuflen;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
@@ -936,23 +975,28 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
}
/* and some checks on the generated key */
+ t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
+ if (prepparm->kb.tlv1.len < 2 * sizeof(uint16_t) + sizeof(*t)) {
+ rc = -EIO;
+ goto out;
+ }
+ keybuflen = prepparm->kb.tlv1.len - 2 * sizeof(uint16_t);
rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR,
prepparm->kb.tlv1.gen_key,
- keybitsize, 1);
+ keybuflen, keybitsize, 1);
if (rc) {
rc = -EIO;
goto out;
}
/* copy the generated vlsc key token */
- t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
if (keybuf) {
- if (*keybufsize >= t->len)
- memcpy(keybuf, t, t->len);
+ if (*keybufsize >= keybuflen)
+ memcpy(keybuf, t, keybuflen);
else
rc = -EINVAL;
}
- *keybufsize = t->len;
+ *keybufsize = keybuflen;
out:
free_cprbmem(mem, PARMBSIZE, false, xflags);
@@ -971,7 +1015,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
int clr_key_bit_size,
u8 *key_token,
int *key_token_size,
- u32 xflags)
+ u32 xflags,
+ bool scrub)
{
int rc, n;
u8 *mem, *ptr;
@@ -1111,7 +1156,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
*key_token_size = t->len;
out:
- free_cprbmem(mem, PARMBSIZE, false, xflags);
+ free_cprbmem(mem, PARMBSIZE, scrub, xflags);
return rc;
}
@@ -1162,28 +1207,32 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
* 4/4 COMPLETE the secure cipher key import
*/
rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART",
- exorbuf, keybitsize, token, &tokensize, xflags);
+ exorbuf, keybitsize, token, &tokensize,
+ xflags, true);
if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc);
goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
- clrkey, keybitsize, token, &tokensize, xflags);
+ clrkey, keybitsize, token, &tokensize,
+ xflags, true);
if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc);
goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
- exorbuf, keybitsize, token, &tokensize, xflags);
+ exorbuf, keybitsize, token, &tokensize,
+ xflags, true);
if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc);
goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL,
- NULL, keybitsize, token, &tokensize, xflags);
+ NULL, keybitsize, token, &tokensize,
+ xflags, true);
if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc);
@@ -1200,6 +1249,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
*keybufsize = tokensize;
out:
+ memzero_explicit(exorbuf, sizeof(exorbuf));
+ memzero_explicit(mem, CPRB_MEMPOOL_ITEM_SIZE);
mempool_free(mem, cprb_mempool);
return rc;
}
@@ -1261,6 +1312,9 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
} __packed * prepparm;
int keytoklen = ((struct cipherkeytoken *)ckey)->len;
+ if (keytoklen > PARMBSIZE - sizeof(struct aureqparm))
+ return -EINVAL;
+
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags);
@@ -1425,6 +1479,9 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
} __packed * prepparm;
int keylen = ((struct eccprivkeytoken *)key)->len;
+ if (keylen > PARMBSIZE - sizeof(struct aureqparm))
+ return -EINVAL;
+
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags);
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h
index 07bbb1c20022..a4534f8b2f1d 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.h
+++ b/drivers/s390/crypto/zcrypt_ccamisc.h
@@ -136,7 +136,7 @@ struct eccprivkeytoken {
* also checked. Returns 0 on success or errno value on failure.
*/
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize);
+ const u8 *token, u32 keysize, int keybitsize);
/*
* Simple check if the token is a valid CCA secure AES cipher key
@@ -146,8 +146,8 @@ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
* Returns 0 on success or errno value on failure.
*/
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize,
- int checkcpacfexport);
+ const u8 *token, u32 keysize,
+ int keybitsize, int checkcpacfexport);
/*
* Simple check if the token is a valid CCA secure ECC private
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 20fb0d2e02a9..f18eed9df3c7 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -6525,6 +6525,9 @@ int qeth_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *d
struct qeth_card *card = dev->ml_priv;
int rc = 0;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch (cmd) {
case SIOC_QETH_ADP_SET_SNMP_CONTROL:
rc = qeth_snmp_command(card, data);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 8ff7db7921b5..fea573e00f9d 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -253,6 +253,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{
mempool_destroy(adapter->pool.erp_req);
+ mempool_destroy(adapter->pool.gid_pn_req);
mempool_destroy(adapter->pool.scsi_req);
mempool_destroy(adapter->pool.scsi_abort);
mempool_destroy(adapter->pool.qtcb_pool);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 213d5b5dea94..8a2500993e19 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -5261,15 +5261,7 @@ static int _resume_v3_hw(struct device *device)
return rc;
}
phys_init_v3_hw(hisi_hba);
-
- /*
- * If a directly-attached disk is removed during suspend, a deadlock
- * may occur, as the PHYE_RESUME_TIMEOUT processing will require the
- * hisi_hba->device to be active, which can only happen when resume
- * completes. So don't wait for the HA event workqueue to drain upon
- * resume.
- */
- sas_resume_ha_no_sync(sha);
+ sas_resume_ha(sha);
clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags);
dev_warn(dev, "end of resuming controller\n");
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 160f02f2f51d..5cbc51899de0 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -918,7 +918,7 @@ invalid_datalen:
}
senselen = get_unaligned_be16(data);
- if (datalen < senselen)
+ if (datalen < senselen + 2)
goto invalid_datalen;
memcpy(sc->sense_buffer, data + 2,
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index e90805ba868f..7223bb18b048 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -752,13 +752,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
spin_unlock(&conn->session->back_lock);
break;
- case ISCSI_OP_SCSI_CMD_RSP:
- if (tcp_conn->in.datalen) {
- iscsi_tcp_data_recv_prep(tcp_conn);
- return 0;
- }
- rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
- break;
case ISCSI_OP_R2T:
if (ahslen) {
rc = ISCSI_ERR_AHSLEN;
@@ -766,6 +759,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
}
rc = iscsi_tcp_r2t_rsp(conn, hdr);
break;
+ case ISCSI_OP_SCSI_CMD_RSP:
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
case ISCSI_OP_REJECT:
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 0bec236f0fb5..c3f3d05b46de 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -410,7 +410,7 @@ static void sas_resume_insert_broadcast_ha(struct sas_ha_struct *ha)
}
}
-static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
+void sas_resume_ha(struct sas_ha_struct *ha)
{
const unsigned long tmo = msecs_to_jiffies(25000);
int i;
@@ -426,6 +426,23 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
i, i > 1 ? "s" : "");
wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
+
+ /*
+ * All phys are back up or timed out. Turn on I/O and drain
+ * pending work.
+ */
+ scsi_unblock_requests(ha->shost);
+ sas_drain_work(ha);
+
+ /*
+ * Send PHYE_RESUME_TIMEOUT after sas_drain_work(). The handler
+ * calls sas_deform_port() -> sas_destruct_devices(), which removes
+ * SCSI devices and, for LLDDs using device_link() PM sync, waits
+ * for the host to be runtime-active. Sending it before the drain
+ * would deadlock: the drain waits for the handler, the handler
+ * waits for host resume, and host resume waits for the drain to
+ * finish.
+ */
for (i = 0; i < ha->num_phys; i++) {
struct asd_sas_phy *phy = ha->sas_phy[i];
@@ -436,12 +453,6 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
}
}
- /* all phys are back up or timed out, turn on i/o so we can
- * flush out disks that did not return
- */
- scsi_unblock_requests(ha->shost);
- if (drain)
- sas_drain_work(ha);
clear_bit(SAS_HA_RESUMING, &ha->state);
sas_queue_deferred_work(ha);
@@ -450,20 +461,8 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain)
*/
sas_resume_insert_broadcast_ha(ha);
}
-
-void sas_resume_ha(struct sas_ha_struct *ha)
-{
- _sas_resume_ha(ha, true);
-}
EXPORT_SYMBOL(sas_resume_ha);
-/* A no-sync variant, which does not call sas_drain_ha(). */
-void sas_resume_ha_no_sync(struct sas_ha_struct *ha)
-{
- _sas_resume_ha(ha, false);
-}
-EXPORT_SYMBOL(sas_resume_ha_no_sync);
-
void sas_suspend_ha(struct sas_ha_struct *ha)
{
int i;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index c83282733ec4..97ac3db5dccb 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -502,6 +502,21 @@ int sas_eh_target_reset_handler(struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler);
+/*
+ * Handle deferred QCs in case of a command timeout.
+ * See ata_scsi_eh_timed_out() for details.
+ */
+enum scsi_timeout_action sas_eh_timed_out(struct scsi_cmnd *cmd)
+{
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+
+ if (dev_is_sata(dev))
+ return ata_scsi_retry_deferred_qc(dev->sata_dev.ap, cmd);
+
+ return SCSI_EH_NOT_HANDLED;
+}
+EXPORT_SYMBOL_GPL(sas_eh_timed_out);
+
/* Try to reset a device */
static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
{
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 31b19ed1528e..681868716ebd 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -9,6 +9,7 @@
#include "mpi3mr.h"
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/sched/mm.h>
static int
mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u16 reset_reason);
@@ -1287,11 +1288,14 @@ out_failed:
static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc)
{
struct kobj_uevent_env *env;
+ unsigned int noio_flag;
int ret;
+ noio_flag = memalloc_noio_save();
+
env = kzalloc_obj(*env);
if (!env)
- return;
+ goto out_restore;
ret = add_uevent_var(env, "DRIVER=%s", mrioc->driver_name);
if (ret)
@@ -1326,7 +1330,8 @@ static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc)
out_free:
kfree(env);
-
+out_restore:
+ memalloc_noio_restore(noio_flag);
}
/**
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9d1c9c41d0f9..643051332132 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -5890,6 +5890,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
u32 alloc_len, rep_opts, rep_len;
bool partial;
u64 lba, zs_lba;
+ u64 arr_len;
u8 *arr = NULL, *desc;
u8 *cmd = scp->cmnd;
struct sdeb_zone_state *zsp = NULL;
@@ -5911,9 +5912,12 @@ static int resp_report_zones(struct scsi_cmnd *scp,
return check_condition_result;
}
- rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
+ rep_max_zones = (ALIGN((u64)alloc_len, RZONES_DESC_HD) - RZONES_DESC_HD) >>
+ ilog2(RZONES_DESC_HD);
+ rep_max_zones = min_t(unsigned int, rep_max_zones, devip->nr_zones);
+ arr_len = (u64)RZONES_DESC_HD * (rep_max_zones + 1);
- arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
+ arr = kzalloc(arr_len, GFP_ATOMIC | __GFP_NOWARN);
if (!arr) {
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
INSUFF_RES_ASCQ);
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 9b4e5b7013ae..af1a05e78492 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -388,11 +388,13 @@ static inline void cdns_spi_writer(struct cdns_spi *xspi)
/**
* cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
+ * @ctlr: Pointer to the spi_controller structure
* @xspi: Pointer to the cdns_spi structure
* @ntx: Number of bytes to pack into the TX FIFO
* @nrx: Number of bytes to drain from the RX FIFO
*/
-static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
+static void cdns_spi_process_fifo(struct spi_controller *ctlr,
+ struct cdns_spi *xspi, int ntx, int nrx)
{
ntx = clamp(ntx, 0, xspi->tx_bytes);
nrx = clamp(nrx, 0, xspi->rx_bytes);
@@ -407,6 +409,16 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
}
if (ntx) {
+ /* When xspi in busy condition, bytes may send failed,
+ * then spi control didn't work thoroughly, add one byte
+ * delay. Only in host mode; in target mode this delay
+ * causes data corruption as the target fails to prepare
+ * data in time.
+ */
+ if (!spi_controller_is_target(ctlr) &&
+ (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL))
+ udelay(10);
+
cdns_spi_writer(xspi);
ntx--;
}
@@ -460,14 +472,14 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
cdns_spi_write(xspi, CDNS_SPI_THLD, 1);
if (xspi->tx_bytes) {
- cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
+ cdns_spi_process_fifo(ctlr, xspi, trans_cnt, trans_cnt);
} else {
/* Fixed delay due to controller limitation with
* RX_NEMPTY incorrect status
* Xilinx AR:65885 contains more details
*/
udelay(10);
- cdns_spi_process_fifo(xspi, 0, trans_cnt);
+ cdns_spi_process_fifo(ctlr, xspi, 0, trans_cnt);
cdns_spi_write(xspi, CDNS_SPI_IDR,
CDNS_SPI_IXR_DEFAULT);
spi_finalize_current_transfer(ctlr);
@@ -520,17 +532,11 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
}
- /* When xspi in busy condition, bytes may send failed,
- * then spi control didn't work thoroughly, add one byte delay
- */
- if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
- udelay(10);
-
xspi->n_bytes = cdns_spi_n_bytes(transfer);
xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes);
xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes);
- cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
+ cdns_spi_process_fifo(ctlr, xspi, xspi->tx_fifo_depth, 0);
cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
return transfer->len;
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 1e36ae084dd8..4425132432ec 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -340,6 +340,18 @@ struct nxp_fspi_devtype_data {
unsigned int quirks;
unsigned int lut_num;
bool little_endian;
+ /*
+ * The max clock rate (Hz) that FlexSPI can output to the device
+ * in SDR mode (RXCLKSRC=0). Defaults to 66MHz if zero.
+ * Some SoCs (e.g. LX2160A) support up to 100MHz in SDR mode.
+ */
+ unsigned long max_sdr_rate;
+ /*
+ * The max clock rate (Hz) that FlexSPI can output to the device
+ * in DTR mode (RXCLKSRC=3). Defaults to 166MHz if zero.
+ * Some SoCs (e.g. i.MX95, i.MX8QM, i.MX8DXL) support up to 200MHz.
+ */
+ unsigned long max_dtr_rate;
};
static struct nxp_fspi_devtype_data lx2160a_data = {
@@ -349,6 +361,10 @@ static struct nxp_fspi_devtype_data lx2160a_data = {
.quirks = FSPI_QUIRK_DISABLE_DTR,
.lut_num = 32,
.little_endian = true, /* little-endian */
+ /*
+ * LX2160ACEC: SDR RXCLKSRC=0 max 100MHz, DTR disabled via quirk.
+ */
+ .max_sdr_rate = 100000000,
};
static struct nxp_fspi_devtype_data imx8mm_data = {
@@ -358,6 +374,21 @@ static struct nxp_fspi_devtype_data imx8mm_data = {
.quirks = 0,
.lut_num = 32,
.little_endian = true, /* little-endian */
+ /* IMX8MMCEC §3.9.10: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */
+ .max_sdr_rate = 66000000,
+ .max_dtr_rate = 166000000,
+};
+
+static struct nxp_fspi_devtype_data imx8mp_data = {
+ .rxfifo = SZ_512, /* (64 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = 0,
+ .lut_num = 32,
+ .little_endian = true, /* little-endian */
+ /* IMX8MPCEC: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */
+ .max_sdr_rate = 66000000,
+ .max_dtr_rate = 166000000,
};
static struct nxp_fspi_devtype_data imx8qxp_data = {
@@ -367,6 +398,12 @@ static struct nxp_fspi_devtype_data imx8qxp_data = {
.quirks = 0,
.lut_num = 32,
.little_endian = true, /* little-endian */
+ /*
+ * IMX8QXPCEC: SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 200MHz.
+ * i.MX8QM and i.MX8DXL share the same FlexSPI IP and limits.
+ */
+ .max_sdr_rate = 60000000,
+ .max_dtr_rate = 200000000,
};
static struct nxp_fspi_devtype_data imx8dxl_data = {
@@ -376,6 +413,12 @@ static struct nxp_fspi_devtype_data imx8dxl_data = {
.quirks = FSPI_QUIRK_USE_IP_ONLY,
.lut_num = 32,
.little_endian = true, /* little-endian */
+ /*
+ * IMX8DXLCEC (i.MX 8XLite): SDR RXCLKSRC=0 max 60MHz,
+ * DDR RXCLKSRC=3 max 200MHz.
+ */
+ .max_sdr_rate = 60000000,
+ .max_dtr_rate = 200000000,
};
static struct nxp_fspi_devtype_data imx8ulp_data = {
@@ -385,6 +428,29 @@ static struct nxp_fspi_devtype_data imx8ulp_data = {
.quirks = 0,
.lut_num = 16,
.little_endian = true, /* little-endian */
+ /*
+ * IMX8ULPCEC §7.3.1, Normal Drive (ND, 1.0V) mode:
+ * SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 166MHz.
+ * Note: Overdrive (OD, 1.05V) allows up to 180MHz DTR
+ * but is not the default use case.
+ */
+ .max_sdr_rate = 60000000,
+ .max_dtr_rate = 166000000,
+};
+
+static struct nxp_fspi_devtype_data imx95_data = {
+ .rxfifo = SZ_512, /* (64 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = 0,
+ .lut_num = 32,
+ .little_endian = true, /* little-endian */
+ /*
+ * IMX95CEC Rev.8 §4.11.7: SDR RXCLKSRC=0 max 66MHz,
+ * DDR RXCLKSRC=3 max 200MHz (Nominal/Overdrive mode).
+ */
+ .max_sdr_rate = 66000000,
+ .max_dtr_rate = 200000000,
};
struct nxp_fspi {
@@ -691,10 +757,20 @@ static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f,
reg = fspi_readl(f, f->iobase + FSPI_MCR0);
if (op_is_dtr) {
reg |= FSPI_MCR0_RXCLKSRC(3);
- f->max_rate = 166000000;
+ /*
+ * Use the SoC-specific DTR max rate if provided, otherwise
+ * fall back to 166MHz (limit from IMX8MN datasheet §3.9.9).
+ */
+ f->max_rate = f->devtype_data->max_dtr_rate ?
+ f->devtype_data->max_dtr_rate : 166000000;
} else { /*select mode 0 */
reg &= ~FSPI_MCR0_RXCLKSRC(3);
- f->max_rate = 66000000;
+ /*
+ * Use the SoC-specific SDR max rate if provided, otherwise
+ * fall back to 66MHz (limit from IMX8MN datasheet §3.9.9).
+ */
+ f->max_rate = f->devtype_data->max_sdr_rate ?
+ f->devtype_data->max_sdr_rate : 66000000;
}
fspi_writel(f, reg, f->iobase + FSPI_MCR0);
}
@@ -783,14 +859,15 @@ static void nxp_fspi_dll_override(struct nxp_fspi *f)
* Value for rest of the CS FLSHxxCR0 register would be zero.
*
*/
-static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
- const struct spi_mem_op *op)
+static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
/* flexspi only support one DTR mode: 8D-8D-8D */
bool op_is_dtr = op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr;
unsigned long rate = op->max_freq;
int ret;
uint64_t size_kb;
+ u32 reg;
/*
* Return when following condition all meet,
@@ -804,7 +881,7 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
if ((f->selected == spi_get_chipselect(spi, 0)) &&
(!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) &&
(f->pre_op_rate == op->max_freq))
- return;
+ return 0;
/* Reset FLSHxxCR0 registers */
fspi_writel(f, 0, f->iobase + FSPI_FLSHA1CR0);
@@ -820,6 +897,15 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
+ /*
+ * Per the FlexSPI reference manual (initialization sequence), MCR0 and
+ * the DLL control registers should be configured while the module is in
+ * stop mode (MCR0[MDIS] = 1). Enter stop mode before reconfiguring the
+ * RX sample clock source and the DLL, then exit stop mode afterwards.
+ */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg | FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr);
rate = min(f->max_rate, op->max_freq);
@@ -836,12 +922,19 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
nxp_fspi_clk_disable_unprep(f);
ret = clk_set_rate(f->clk, rate);
- if (ret)
- return;
+ if (ret) {
+ /*
+ * clk_set_rate() failed with the clocks already disabled.
+ * Re-enable them so the enable count matches what the caller's
+ * pm_runtime_put() (runtime_suspend) will drop.
+ */
+ nxp_fspi_clk_prep_enable(f);
+ return ret;
+ }
ret = nxp_fspi_clk_prep_enable(f);
if (ret)
- return;
+ return ret;
/*
* If clock rate > 100MHz, then switch from DLL override mode to
@@ -852,9 +945,15 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
else
nxp_fspi_dll_override(f);
+ /* Exit stop mode now that MCR0 and the DLL have been reconfigured. */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg & ~FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
f->pre_op_rate = op->max_freq;
f->selected = spi_get_chipselect(spi, 0);
+
+ return 0;
}
static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
@@ -1042,7 +1141,16 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true);
WARN_ON(err);
- nxp_fspi_select_mem(f, mem->spi, op);
+ err = nxp_fspi_select_mem(f, mem->spi, op);
+ if (err) {
+ /*
+ * On failure the FlexSPI clock may be left disabled, so avoid
+ * any further register access (which would trigger a synchronous
+ * external abort) and bail out.
+ */
+ pm_runtime_put_autosuspend(f->dev);
+ return err;
+ }
nxp_fspi_prepare_lut(f, op);
/*
@@ -1444,10 +1552,11 @@ static const struct dev_pm_ops nxp_fspi_pm_ops = {
static const struct of_device_id nxp_fspi_dt_ids[] = {
{ .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, },
{ .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, },
- { .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mm_data, },
+ { .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mp_data, },
{ .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, },
{ .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, },
{ .compatible = "nxp,imx8ulp-fspi", .data = (void *)&imx8ulp_data, },
+ { .compatible = "nxp,imx95-fspi", .data = (void *)&imx95_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids);
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
index caf55a6f70b3..e9fdefa9d65d 100644
--- a/drivers/spi/spi-qcom-qspi.c
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -775,7 +775,8 @@ static int qcom_qspi_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "could not set DMA mask\n");
host->max_speed_hz = 300000000;
- host->max_dma_len = 65536; /* as per HPG */
+ /* as per HPG, it is 64KB, limit to 60KB to avoid boundary condition failures */
+ host->max_dma_len = 0xf000;
host->dma_alignment = QSPI_ALIGN_REQ;
host->num_chipselect = QSPI_NUM_CS;
host->bus_num = -1;
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
index 66f2d1b78ade..b6c58d9cfe14 100644
--- a/drivers/spi/spi-qpic-snand.c
+++ b/drivers/spi/spi-qpic-snand.c
@@ -1358,6 +1358,22 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
snandc->regs->addr0 = cpu_to_le32(op->addr.val);
snandc->regs->addr1 = cpu_to_le32(0);
+ /*
+ * The feature value has to reach NAND_FLASH_FEATURES before the
+ * command is executed, otherwise the controller programs the chip
+ * with whatever the register happened to hold from a previous
+ * operation.
+ */
+ if (opcode == SPINAND_SET_FEATURE) {
+ u32 ftr = 0;
+
+ memcpy(&ftr, op->data.buf.out,
+ min_t(size_t, op->data.nbytes, sizeof(ftr)));
+ snandc->regs->flash_feature = cpu_to_le32(ftr);
+ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
+ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
+ }
+
qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
@@ -1395,10 +1411,8 @@ static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_
copy_ftr = true;
break;
case SPINAND_SET_FEATURE:
- snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
- qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
- NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
- break;
+ /* fully handled by qcom_spi_send_cmdaddr() */
+ return 0;
case SPINAND_PROGRAM_EXECUTE:
case SPINAND_WRITE_EN:
case SPINAND_RESET:
diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c
index 0faf7ffed676..fd5893a92e59 100644
--- a/drivers/spi/spi-spacemit-k1.c
+++ b/drivers/spi/spi-spacemit-k1.c
@@ -278,25 +278,25 @@ static int k1_spi_dma_one(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *transfer)
{
struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
- struct dma_async_tx_descriptor *desc;
+ struct dma_async_tx_descriptor *txdesc, *rxdesc;
u32 val;
- /* Prepare the TX descriptor and submit it */
- desc = k1_spi_dma_prep(drv_data, transfer, true);
- if (!desc)
+ /* Prepare the TX descriptor */
+ txdesc = k1_spi_dma_prep(drv_data, transfer, true);
+ if (!txdesc)
goto fallback;
- dmaengine_submit(desc);
- /* Prepare the RX descriptor and submit it */
- desc = k1_spi_dma_prep(drv_data, transfer, false);
- if (!desc)
+ /* Prepare the RX descriptor */
+ rxdesc = k1_spi_dma_prep(drv_data, transfer, false);
+ if (!rxdesc)
goto fallback;
/* When RX is complete we also know TX has completed */
- desc->callback = k1_spi_dma_callback;
- desc->callback_param = drv_data;
+ rxdesc->callback = k1_spi_dma_callback;
+ rxdesc->callback_param = drv_data;
- dmaengine_submit(desc);
+ dmaengine_submit(txdesc);
+ dmaengine_submit(rxdesc);
val = readl(drv_data->base + SSP_TOP_CTRL);
val |= TOP_TRAIL; /* Trailing bytes handled by DMA */
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 1087d1d17c36..ea65d39fef88 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -906,7 +906,7 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
break;
case PRO_PREEMPT:
case PRO_PREEMPT_AND_ABORT:
- if (!ops->pr_clear) {
+ if (!ops->pr_preempt) {
pr_err("block_device does not support pr_preempt.\n");
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
@@ -916,8 +916,8 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
sa == PRO_PREEMPT_AND_ABORT);
break;
case PRO_RELEASE:
- if (!ops->pr_clear) {
- pr_err("block_device does not support pr_pclear.\n");
+ if (!ops->pr_release) {
+ pr_err("block_device does not support pr_release.\n");
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index fad03a15c969..dcfe94594916 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1734,6 +1734,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
u32 data_length, int task_attr, int data_dir, int flags)
{
struct se_portal_group *se_tpg;
+ int ret;
se_tpg = se_sess->se_tpg;
BUG_ON(!se_tpg);
@@ -1763,7 +1764,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
* necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
* kref_put() to happen during fabric packet acknowledgement.
*/
- return target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+ ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+ if (ret)
+ se_cmd->cmd_cnt = NULL;
+
+ return ret;
}
EXPORT_SYMBOL_GPL(target_init_cmd);
@@ -2039,8 +2044,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
* allocation failure.
*/
ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp);
- if (ret < 0)
+ if (ret < 0) {
+ se_cmd->cmd_cnt = NULL;
return -ENOMEM;
+ }
if (tm_type == TMR_ABORT_TASK)
se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2048,6 +2055,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
/* See target_submit_cmd for commentary */
ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
if (ret) {
+ se_cmd->cmd_cnt = NULL;
core_tmr_release_req(se_cmd->se_tmr_req);
return ret;
}
diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c
index ffad049872b9..62120dc2e9da 100644
--- a/drivers/ufs/core/ufs-rpmb.c
+++ b/drivers/ufs/core/ufs-rpmb.c
@@ -152,8 +152,6 @@ int ufs_rpmb_probe(struct ufs_hba *hba)
return -EINVAL;
}
- INIT_LIST_HEAD(&hba->rpmbs);
-
struct rpmb_descr descr = {
.type = RPMB_TYPE_UFS,
.route_frames = ufs_rpmb_route_frames,
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index d3044a3089b5..13e6357a8bbb 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -7357,7 +7357,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
}
/**
- * ufshcd_threaded_intr - Threaded interrupt service routine
+ * ufshcd_intr - Main interrupt service routine
* @irq: irq number
* @__hba: pointer to adapter instance
*
@@ -7365,7 +7365,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
* IRQ_HANDLED - If interrupt is valid
* IRQ_NONE - If invalid interrupt
*/
-static irqreturn_t ufshcd_threaded_intr(int irq, void *__hba)
+static irqreturn_t ufshcd_intr(int irq, void *__hba)
{
u32 last_intr_status, intr_status, enabled_intr_status = 0;
irqreturn_t retval = IRQ_NONE;
@@ -7404,38 +7404,6 @@ static irqreturn_t ufshcd_threaded_intr(int irq, void *__hba)
return retval;
}
-/**
- * ufshcd_intr - Main interrupt service routine
- * @irq: irq number
- * @__hba: pointer to adapter instance
- *
- * Return:
- * IRQ_HANDLED - If interrupt is valid
- * IRQ_WAKE_THREAD - If handling is moved to threaded handled
- * IRQ_NONE - If invalid interrupt
- */
-static irqreturn_t ufshcd_intr(int irq, void *__hba)
-{
- struct ufs_hba *hba = __hba;
- u32 intr_status, enabled_intr_status;
-
- /*
- * Handle interrupt in thread if MCQ or ESI is disabled,
- * and no active UIC command.
- */
- if ((!hba->mcq_enabled || !hba->mcq_esi_enabled) &&
- !hba->active_uic_cmd)
- return IRQ_WAKE_THREAD;
-
- intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
- enabled_intr_status = intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
-
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
-
- /* Directly handle interrupts since MCQ ESI handlers does the hard job */
- return ufshcd_sl_intr(hba, enabled_intr_status);
-}
-
static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
{
int err = 0;
@@ -10269,6 +10237,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
req_link_state == UIC_LINK_ACTIVE_STATE) {
ufshcd_disable_auto_bkops(hba);
flush_work(&hba->eeh_work);
+ cancel_delayed_work_sync(&hba->ufs_rtc_update_work);
goto vops_suspend;
}
@@ -10478,10 +10447,11 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (ret)
goto set_old_link_state;
ufshcd_set_timestamp_attr(hba);
- schedule_delayed_work(&hba->ufs_rtc_update_work,
- msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
}
+ schedule_delayed_work(&hba->ufs_rtc_update_work,
+ msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
+
if (ufshcd_keep_autobkops_enabled_except_suspend(hba))
ufshcd_enable_auto_bkops(hba);
else
@@ -10988,6 +10958,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
hba->nop_out_timeout = NOP_OUT_TIMEOUT;
ufshcd_set_sg_entry_size(hba, sizeof(struct ufshcd_sg_entry));
INIT_LIST_HEAD(&hba->clk_list_head);
+ INIT_LIST_HEAD(&hba->rpmbs);
spin_lock_init(&hba->outstanding_lock);
*hba_handle = hba;
@@ -11236,8 +11207,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
/* IRQ registration */
- err = devm_request_threaded_irq(dev, irq, ufshcd_intr, ufshcd_threaded_intr,
- IRQF_ONESHOT | IRQF_SHARED, UFSHCD, hba);
+ err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
dev_err(hba->dev, "request irq failed\n");
goto out_disable;
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 3e72b9c6af0c..6949b704166d 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -176,21 +176,13 @@ static void *vhost_net_buf_consume(struct vhost_net_buf *rxq)
return ret;
}
-static int vhost_net_buf_produce(struct sock *sk,
- struct vhost_net_virtqueue *nvq)
+static int vhost_net_buf_produce(struct vhost_net_virtqueue *nvq)
{
- struct file *file = sk->sk_socket->file;
struct vhost_net_buf *rxq = &nvq->rxq;
rxq->head = 0;
- spin_lock(&nvq->rx_ring->consumer_lock);
- rxq->tail = __ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
- VHOST_NET_BATCH);
-
- if (rxq->tail)
- tun_wake_queue(file, rxq->tail);
-
- spin_unlock(&nvq->rx_ring->consumer_lock);
+ rxq->tail = ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
+ VHOST_NET_BATCH);
return rxq->tail;
}
@@ -217,15 +209,14 @@ static int vhost_net_buf_peek_len(void *ptr)
return __skb_array_len_with_tag(ptr);
}
-static int vhost_net_buf_peek(struct sock *sk,
- struct vhost_net_virtqueue *nvq)
+static int vhost_net_buf_peek(struct vhost_net_virtqueue *nvq)
{
struct vhost_net_buf *rxq = &nvq->rxq;
if (!vhost_net_buf_is_empty(rxq))
goto out;
- if (!vhost_net_buf_produce(sk, nvq))
+ if (!vhost_net_buf_produce(nvq))
return 0;
out:
@@ -1013,7 +1004,7 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
unsigned long flags;
if (rvq->rx_ring)
- return vhost_net_buf_peek(sk, rvq);
+ return vhost_net_buf_peek(rvq);
spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
head = skb_peek(&sk->sk_receive_queue);