summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-03-31 07:47:05 +1000
committerDave Airlie <airlied@redhat.com>2026-03-31 07:51:02 +1000
commitf6225b546dfccfc322b18c0d757b7b9c767a1e27 (patch)
tree14aee2a223e3f5e3e7850e6674d8367b4c835235 /drivers
parenta51973c5dff8a0f01cc7d1b2007306ea0004fa16 (diff)
parent7aaa8047eafd0bd628065b15757d9b48c5f9c07d (diff)
BackMerge tag 'v7.0-rc6' into drm-next
Linux 7.0-rc6 Requested by a few people on irc to resolve conflicts in other tress. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accel/ivpu/ivpu_drv.h1
-rw-r--r--drivers/accel/ivpu/ivpu_hw.c6
-rw-r--r--drivers/acpi/acpi_processor.c15
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/bus.c3
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/ata/libata-core.c3
-rw-r--r--drivers/ata/libata-scsi.c2
-rw-r--r--drivers/base/bus.c43
-rw-r--r--drivers/base/core.c2
-rw-r--r--drivers/base/dd.c60
-rw-r--r--drivers/base/platform.c37
-rw-r--r--drivers/base/power/runtime.c1
-rw-r--r--drivers/base/regmap/regmap.c30
-rw-r--r--drivers/block/zram/zram_drv.c39
-rw-r--r--drivers/bluetooth/btintel.c11
-rw-r--r--drivers/bluetooth/btqca.c2
-rw-r--r--drivers/bluetooth/btusb.c5
-rw-r--r--drivers/bluetooth/hci_ll.c2
-rw-r--r--drivers/bus/simple-pm-bus.c4
-rw-r--r--drivers/cache/ax45mp_cache.c4
-rw-r--r--drivers/cache/starfive_starlink_cache.c4
-rw-r--r--drivers/clk/imx/clk-scu.c3
-rw-r--r--drivers/cpufreq/cpufreq.c9
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c12
-rw-r--r--drivers/cpufreq/cpufreq_governor.c3
-rw-r--r--drivers/cpufreq/cpufreq_governor.h1
-rw-r--r--drivers/cpufreq/freq_table.c4
-rw-r--r--drivers/crypto/ccp/sev-dev.c4
-rw-r--r--drivers/crypto/padlock-sha.c7
-rw-r--r--drivers/cxl/Kconfig1
-rw-r--r--drivers/cxl/core/hdm.c25
-rw-r--r--drivers/cxl/core/mbox.c2
-rw-r--r--drivers/cxl/core/port.c8
-rw-r--r--drivers/cxl/core/region.c4
-rw-r--r--drivers/cxl/pmem.c2
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.c8
-rw-r--r--drivers/dma/dw-edma/dw-hdma-v0-core.c6
-rw-r--r--drivers/dma/fsl-edma-main.c26
-rw-r--r--drivers/dma/idxd/cdev.c8
-rw-r--r--drivers/dma/idxd/device.c45
-rw-r--r--drivers/dma/idxd/dma.c18
-rw-r--r--drivers/dma/idxd/idxd.h1
-rw-r--r--drivers/dma/idxd/init.c14
-rw-r--r--drivers/dma/idxd/irq.c16
-rw-r--r--drivers/dma/idxd/submit.c2
-rw-r--r--drivers/dma/idxd/sysfs.c1
-rw-r--r--drivers/dma/sh/rz-dmac.c66
-rw-r--r--drivers/dma/xilinx/xdma.c4
-rw-r--r--drivers/dma/xilinx/xilinx_dma.c46
-rw-r--r--drivers/firewire/net.c5
-rw-r--r--drivers/firmware/arm_ffa/driver.c8
-rw-r--r--drivers/firmware/arm_scmi/notify.c4
-rw-r--r--drivers/firmware/arm_scmi/protocols.h4
-rw-r--r--drivers/firmware/arm_scpi.c5
-rw-r--r--drivers/gpu/drm/drm_file.c5
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c45
-rw-r--r--drivers/gpu/drm/drm_mode_config.c9
-rw-r--r--drivers/gpu/drm/drm_pagemap_util.c14
-rw-r--r--drivers/gpu/drm/drm_syncobj.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.c20
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c7
-rw-r--r--drivers/gpu/drm/i915/i915_wait_util.h2
-rw-r--r--drivers/gpu/drm/imagination/pvr_device.c17
-rw-r--r--drivers/gpu/drm/imagination/pvr_power.c51
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h93
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c3
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.c2
-rw-r--r--drivers/hid/hid-appletb-kbd.c5
-rw-r--r--drivers/hid/hid-asus.c3
-rw-r--r--drivers/hid/hid-core.c7
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-input.c18
-rw-r--r--drivers/hid/hid-logitech-hidpp.c6
-rw-r--r--drivers/hid/hid-multitouch.c7
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c1
-rw-r--r--drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c1
-rw-r--r--drivers/hid/wacom_wac.c10
-rw-r--r--drivers/hv/mshv_regions.c6
-rw-r--r--drivers/hv/mshv_root.h5
-rw-r--r--drivers/hv/mshv_root_main.c93
-rw-r--r--drivers/hv/mshv_synic.c188
-rw-r--r--drivers/hwmon/adm1177.c54
-rw-r--r--drivers/hwmon/axi-fan-control.c2
-rw-r--r--drivers/hwmon/max6639.c10
-rw-r--r--drivers/hwmon/peci/cputemp.c4
-rw-r--r--drivers/hwmon/pmbus/hac300s.c2
-rw-r--r--drivers/hwmon/pmbus/ina233.c5
-rw-r--r--drivers/hwmon/pmbus/isl68137.c28
-rw-r--r--drivers/hwmon/pmbus/mp2869.c35
-rw-r--r--drivers/hwmon/pmbus/mp2975.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c192
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-cp2615.c3
-rw-r--r--drivers/i2c/busses/i2c-designware-amdisp.c11
-rw-r--r--drivers/i2c/busses/i2c-fsi.c1
-rw-r--r--drivers/i2c/busses/i2c-imx.c51
-rw-r--r--drivers/i2c/busses/i2c-pxa.c17
-rw-r--r--drivers/i2c/busses/i2c-tegra.c5
-rw-r--r--drivers/infiniband/core/rw.c37
-rw-r--r--drivers/infiniband/core/umem.c5
-rw-r--r--drivers/infiniband/hw/bng_re/bng_dev.c14
-rw-r--r--drivers/infiniband/hw/efa/efa_com.c88
-rw-r--r--drivers/infiniband/hw/ionic/ionic_controlpath.c4
-rw-r--r--drivers/infiniband/hw/irdma/cm.c29
-rw-r--r--drivers/infiniband/hw/irdma/uk.c39
-rw-r--r--drivers/infiniband/hw/irdma/utils.c2
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c10
-rw-r--r--drivers/iommu/amd/iommu.c15
-rw-r--r--drivers/iommu/dma-iommu.c21
-rw-r--r--drivers/iommu/intel/dmar.c3
-rw-r--r--drivers/iommu/intel/svm.c12
-rw-r--r--drivers/iommu/iommu-sva.c12
-rw-r--r--drivers/iommu/iommu.c6
-rw-r--r--drivers/irqchip/irq-qcom-mpm.c3
-rw-r--r--drivers/irqchip/irq-renesas-rzv2h.c2
-rw-r--r--drivers/irqchip/irq-riscv-rpmi-sysmsi.c1
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c2
-rw-r--r--drivers/media/mc/mc-request.c5
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c4
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c50
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c3
-rw-r--r--drivers/media/platform/synopsys/Kconfig1
-rw-r--r--drivers/media/platform/synopsys/dw-mipi-csi2rx.c2
-rw-r--r--drivers/media/platform/verisilicon/imx8m_vpu_hw.c2
-rw-r--r--drivers/media/usb/uvc/uvc_video.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c5
-rw-r--r--drivers/mmc/host/sdhci-pci-gli.c9
-rw-r--r--drivers/mmc/host/sdhci.c9
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c6
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c14
-rw-r--r--drivers/mtd/nand/raw/pl35x-nand-controller.c3
-rw-r--r--drivers/mtd/parsers/redboot.c6
-rw-r--r--drivers/mtd/spi-nor/core.c14
-rw-r--r--drivers/net/bonding/bond_debugfs.c16
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/dev/netlink.c4
-rw-r--r--drivers/net/can/spi/mcp251x.c29
-rw-r--r--drivers/net/dsa/bcm_sf2.c8
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c1
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe.c2
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig2
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp.c41
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c2
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c11
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c67
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c4
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c31
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c9
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h22
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c32
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_idc.c6
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c14
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c33
-rw-r--r--drivers/net/ethernet/intel/libie/fwlog.c49
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c23
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.c5
-rw-r--r--drivers/net/ethernet/microsoft/mana/hw_channel.c6
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c6
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c17
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_common.c9
-rw-r--r--drivers/net/netdevsim/netdev.c5
-rw-r--r--drivers/net/team/team_core.c65
-rw-r--r--drivers/net/tun_vnet.h2
-rw-r--r--drivers/net/usb/aqc111.c12
-rw-r--r--drivers/net/usb/cdc_ncm.c10
-rw-r--r--drivers/net/virtio_net.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/scan.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c2
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c3
-rw-r--r--drivers/nfc/nxp-nci/i2c.c4
-rw-r--r--drivers/nvdimm/bus.c5
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c5
-rw-r--r--drivers/pci/pwrctrl/core.c56
-rw-r--r--drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c12
-rw-r--r--drivers/pci/pwrctrl/slot.c1
-rw-r--r--drivers/phy/Kconfig5
-rw-r--r--drivers/phy/freescale/phy-fsl-lynx-28g.c2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c3
-rw-r--r--drivers/phy/spacemit/phy-k1-usb2.c14
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c9
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c16
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza1.c2
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzt2h.c15
-rw-r--r--drivers/pinctrl/stm32/Kconfig1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c43
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.h4
-rw-r--r--drivers/platform/olpc/olpc-xo175-ec.c2
-rw-r--r--drivers/platform/x86/amd/hsmp/hsmp.c2
-rw-r--r--drivers/platform/x86/asus-armoury.h77
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c2
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c19
-rw-r--r--drivers/platform/x86/intel/hid.c10
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c5
-rw-r--r--drivers/platform/x86/lenovo/wmi-gamezone.c2
-rw-r--r--drivers/pmdomain/bcm/bcm2835-power.c12
-rw-r--r--drivers/pmdomain/mediatek/mtk-pm-domains.c2
-rw-r--r--drivers/resctrl/mpam_devices.c2
-rw-r--r--drivers/resctrl/test_mpam_devices.c22
-rw-r--r--drivers/reset/reset-rzg2l-usbphy-ctrl.c3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c3
-rw-r--r--drivers/scsi/scsi_transport_sas.c2
-rw-r--r--drivers/scsi/ses.c2
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c6
-rw-r--r--drivers/soc/fsl/qbman/qman.c24
-rw-r--r--drivers/soc/fsl/qe/qmc.c4
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c13
-rw-r--r--drivers/soc/rockchip/grf.c1
-rw-r--r--drivers/spi/spi-amlogic-spifc-a4.c46
-rw-r--r--drivers/spi/spi-amlogic-spisg.c12
-rw-r--r--drivers/spi/spi-axiado.c31
-rw-r--r--drivers/spi/spi-fsl-lpspi.c3
-rw-r--r--drivers/spi/spi-geni-qcom.c13
-rw-r--r--drivers/spi/spi-meson-spicc.c2
-rw-r--r--drivers/spi/spi-sn-f-ospi.c42
-rw-r--r--drivers/spi/spi.c57
-rw-r--r--drivers/target/loopback/tcm_loop.c52
-rw-r--r--drivers/target/target_core_file.c2
-rw-r--r--drivers/tee/tee_shm.c27
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c8
-rw-r--r--drivers/tty/serial/8250/8250.h25
-rw-r--r--drivers/tty/serial/8250/8250_dma.c15
-rw-r--r--drivers/tty/serial/8250/8250_dw.c296
-rw-r--r--drivers/tty/serial/8250/8250_pci.c17
-rw-r--r--drivers/tty/serial/8250/8250_port.c75
-rw-r--r--drivers/tty/serial/serial_core.c5
-rw-r--r--drivers/tty/serial/uartlite.c1
-rw-r--r--drivers/tty/vt/vt.c8
-rw-r--r--drivers/vfio/pci/vfio_pci_dmabuf.c5
-rw-r--r--drivers/virt/coco/tdx-guest/tdx-guest.c12
-rw-r--r--drivers/virtio/virtio_ring.c10
-rw-r--r--drivers/xen/privcmd.c76
253 files changed, 2782 insertions, 1315 deletions
diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h
index b739738c4566..c77dde310e81 100644
--- a/drivers/accel/ivpu/ivpu_drv.h
+++ b/drivers/accel/ivpu/ivpu_drv.h
@@ -36,6 +36,7 @@
#define IVPU_HW_IP_60XX 60
#define IVPU_HW_IP_REV_LNL_B0 4
+#define IVPU_HW_IP_REV_NVL_A0 0
#define IVPU_HW_BTRS_MTL 1
#define IVPU_HW_BTRS_LNL 2
diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c
index d69cd0d93569..d4a9bcda4100 100644
--- a/drivers/accel/ivpu/ivpu_hw.c
+++ b/drivers/accel/ivpu/ivpu_hw.c
@@ -70,8 +70,10 @@ static void wa_init(struct ivpu_device *vdev)
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
- if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
- ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0)
+ if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
+ ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) ||
+ (ivpu_device_id(vdev) == PCI_DEVICE_ID_NVL &&
+ ivpu_revision(vdev) == IVPU_HW_IP_REV_NVL_A0))
vdev->wa.disable_clock_relinquish = true;
if (ivpu_test_mode & IVPU_TEST_MODE_CLK_RELINQ_ENABLE)
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index b34a48068a8d..b1652cab631a 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -113,6 +113,10 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (ide_dev) {
errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
+ if (errata.piix4.bmisx)
+ dev_dbg(&ide_dev->dev,
+ "Bus master activity detection (BM-IDE) erratum enabled\n");
+
pci_dev_put(ide_dev);
}
@@ -131,20 +135,17 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
if (isa_dev) {
pci_read_config_byte(isa_dev, 0x76, &value1);
pci_read_config_byte(isa_dev, 0x77, &value2);
- if ((value1 & 0x80) || (value2 & 0x80))
+ if ((value1 & 0x80) || (value2 & 0x80)) {
errata.piix4.fdma = 1;
+ dev_dbg(&isa_dev->dev,
+ "Type-F DMA livelock erratum (C3 disabled)\n");
+ }
pci_dev_put(isa_dev);
}
break;
}
- if (ide_dev)
- dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
-
- if (isa_dev)
- dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
-
return 0;
}
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 6c9b5bf7d392..07d5790d09f8 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -451,7 +451,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DSM",
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
- ACPI_TYPE_ANY | ACPI_TYPE_PACKAGE) |
+ ACPI_TYPE_PACKAGE | ACPI_TYPE_ANY) |
ARG_COUNT_IS_MINIMUM,
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index f6707325f582..2ec095e2009e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -818,9 +818,6 @@ const struct acpi_device *acpi_companion_match(const struct device *dev)
if (list_empty(&adev->pnp.ids))
return NULL;
- if (adev->pnp.type.backlight)
- return adev;
-
return acpi_primary_dev_companion(adev, dev);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5f63ed120a2c..6f0065257a77 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1656,6 +1656,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca
ret = ec_install_handlers(ec, device, call_reg);
if (ret) {
+ ec_remove_handlers(ec);
+
if (ec == first_ec)
first_ec = NULL;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6c4e567b6582..374993031895 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4188,6 +4188,9 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "ST3320[68]13AS", "SD1[5-9]", ATA_QUIRK_NONCQ |
ATA_QUIRK_FIRMWARE_WARN },
+ /* ADATA devices with LPM issues. */
+ { "ADATA SU680", NULL, ATA_QUIRK_NOLPM },
+
/* Seagate disks with LPM issues */
{ "ST1000DM010-2EP102", NULL, ATA_QUIRK_NOLPM },
{ "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM },
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index ad798e5246b4..3b65df914ebb 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3600,7 +3600,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
if (cdb[2] != 1 && cdb[2] != 3) {
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
- ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
+ ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
return 0;
}
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index bb61d8adbab1..8b6722ff8590 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -504,6 +504,36 @@ int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
}
EXPORT_SYMBOL_GPL(bus_for_each_drv);
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ ret = __device_set_driver_override(dev, buf, count);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ guard(spinlock)(&dev->driver_override.lock);
+ return sysfs_emit(buf, "%s\n", dev->driver_override.name);
+}
+static DEVICE_ATTR_RW(driver_override);
+
+static struct attribute *driver_override_dev_attrs[] = {
+ &dev_attr_driver_override.attr,
+ NULL,
+};
+
+static const struct attribute_group driver_override_dev_group = {
+ .attrs = driver_override_dev_attrs,
+};
+
/**
* bus_add_device - add device to bus
* @dev: device being added
@@ -537,9 +567,15 @@ int bus_add_device(struct device *dev)
if (error)
goto out_put;
+ if (dev->bus->driver_override) {
+ error = device_add_group(dev, &driver_override_dev_group);
+ if (error)
+ goto out_groups;
+ }
+
error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
if (error)
- goto out_groups;
+ goto out_override;
error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem");
if (error)
@@ -550,6 +586,9 @@ int bus_add_device(struct device *dev)
out_subsys:
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
+out_override:
+ if (dev->bus->driver_override)
+ device_remove_group(dev, &driver_override_dev_group);
out_groups:
device_remove_groups(dev, sp->bus->dev_groups);
out_put:
@@ -607,6 +646,8 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->kobj, "subsystem");
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
+ if (dev->bus->driver_override)
+ device_remove_group(dev, &driver_override_dev_group);
device_remove_groups(dev, dev->bus->dev_groups);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 791f9e444df8..09b98f02f559 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2556,6 +2556,7 @@ static void device_release(struct kobject *kobj)
devres_release_all(dev);
kfree(dev->dma_range_map);
+ kfree(dev->driver_override.name);
if (dev->release)
dev->release(dev);
@@ -3159,6 +3160,7 @@ void device_initialize(struct device *dev)
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
+ spin_lock_init(&dev->driver_override.lock);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index bea8da5f8a3a..37c7e54e0e4c 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -381,6 +381,66 @@ static void __exit deferred_probe_exit(void)
}
__exitcall(deferred_probe_exit);
+int __device_set_driver_override(struct device *dev, const char *s, size_t len)
+{
+ const char *new, *old;
+ char *cp;
+
+ if (!s)
+ return -EINVAL;
+
+ /*
+ * The stored value will be used in sysfs show callback (sysfs_emit()),
+ * which has a length limit of PAGE_SIZE and adds a trailing newline.
+ * Thus we can store one character less to avoid truncation during sysfs
+ * show.
+ */
+ if (len >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ /*
+ * Compute the real length of the string in case userspace sends us a
+ * bunch of \0 characters like python likes to do.
+ */
+ len = strlen(s);
+
+ if (!len) {
+ /* Empty string passed - clear override */
+ spin_lock(&dev->driver_override.lock);
+ old = dev->driver_override.name;
+ dev->driver_override.name = NULL;
+ spin_unlock(&dev->driver_override.lock);
+ kfree(old);
+
+ return 0;
+ }
+
+ cp = strnchr(s, len, '\n');
+ if (cp)
+ len = cp - s;
+
+ new = kstrndup(s, len, GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ spin_lock(&dev->driver_override.lock);
+ old = dev->driver_override.name;
+ if (cp != s) {
+ dev->driver_override.name = new;
+ spin_unlock(&dev->driver_override.lock);
+ } else {
+ /* "\n" passed - clear override */
+ dev->driver_override.name = NULL;
+ spin_unlock(&dev->driver_override.lock);
+
+ kfree(new);
+ }
+ kfree(old);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__device_set_driver_override);
+
/**
* device_is_bound() - Check if device is bound to a driver
* @dev: device to check
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b45d41b018ca..d44591d52e36 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -603,7 +603,6 @@ static void platform_device_release(struct device *dev)
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
kfree(pa->pdev.resource);
- kfree(pa->pdev.driver_override);
kfree(pa);
}
@@ -1306,38 +1305,9 @@ static ssize_t numa_node_show(struct device *dev,
}
static DEVICE_ATTR_RO(numa_node);
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev = to_platform_device(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", pdev->driver_override);
- device_unlock(dev);
-
- return len;
-}
-
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int ret;
-
- ret = driver_set_override(dev, &pdev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *platform_dev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_numa_node.attr,
- &dev_attr_driver_override.attr,
NULL,
};
@@ -1377,10 +1347,12 @@ static int platform_match(struct device *dev, const struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (pdev->driver_override)
- return !strcmp(pdev->driver_override, drv->name);
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
@@ -1516,6 +1488,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
const struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
+ .driver_override = true,
.match = platform_match,
.uevent = platform_uevent,
.probe = platform_probe,
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 0ee8ea971aa4..335288e8b5b3 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1895,6 +1895,7 @@ void pm_runtime_reinit(struct device *dev)
void pm_runtime_remove(struct device *dev)
{
__pm_runtime_disable(dev, false);
+ flush_work(&dev->power.work);
pm_runtime_reinit(dev);
}
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 607c1246d994..e388b19850e3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
unsigned int val_num)
{
void *orig_work_buf;
+ unsigned int selector_reg;
unsigned int win_offset;
unsigned int win_page;
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return -EINVAL;
}
- /* It is possible to have selector register inside data window.
- In that case, selector register is located on every page and
- it needs no page switching, when accessed alone. */
+ /*
+ * Calculate the address of the selector register in the corresponding
+ * data window if it is located on every page.
+ */
+ page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
+ if (page_chg)
+ selector_reg = range->range_min + win_page * range->window_len +
+ range->selector_reg - range->window_start;
+
+ /*
+ * It is possible to have selector register inside data window.
+ * In that case, selector register is located on every page and it
+ * needs no page switching, when accessed alone.
+ *
+ * Nevertheless we should synchronize the cache values for it.
+ * This can't be properly achieved if the selector register is
+ * the first and the only one to be read inside the data window.
+ * That's why we update it in that case as well.
+ *
+ * However, we specifically avoid updating it for the default page,
+ * when it's overlapped with the real data window, to prevent from
+ * infinite looping.
+ */
if (val_num > 1 ||
+ (page_chg && selector_reg != range->selector_reg) ||
range->window_start + win_offset != range->selector_reg) {
/* Use separate work_buf during page switching */
orig_work_buf = map->work_buf;
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
ret = _regmap_update_bits(map, range->selector_reg,
range->selector_mask,
win_page << range->selector_shift,
- &page_chg, false);
+ NULL, false);
map->work_buf = orig_work_buf;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a324ede6206d..af679375b193 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram)
static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
{
- u32 size, index = req->pps->index;
- int err, prio;
- bool huge;
+ u32 index = req->pps->index;
+ int err;
err = blk_status_to_errno(req->bio.bi_status);
if (err) {
@@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
goto out;
}
- if (zram->compressed_wb) {
- /*
- * ZRAM_WB slots get freed, we need to preserve data required
- * for read decompression.
- */
- size = get_slot_size(zram, index);
- prio = get_slot_comp_priority(zram, index);
- huge = test_slot_flag(zram, index, ZRAM_HUGE);
- }
-
- slot_free(zram, index);
- set_slot_flag(zram, index, ZRAM_WB);
+ clear_slot_flag(zram, index, ZRAM_IDLE);
+ if (test_slot_flag(zram, index, ZRAM_HUGE))
+ atomic64_dec(&zram->stats.huge_pages);
+ atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size);
+ zs_free(zram->mem_pool, get_slot_handle(zram, index));
set_slot_handle(zram, index, req->blk_idx);
-
- if (zram->compressed_wb) {
- if (huge)
- set_slot_flag(zram, index, ZRAM_HUGE);
- set_slot_size(zram, index, size);
- set_slot_comp_priority(zram, index, prio);
- }
-
- atomic64_inc(&zram->stats.pages_stored);
+ set_slot_flag(zram, index, ZRAM_WB);
out:
slot_unlock(zram, index);
@@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index)
set_slot_comp_priority(zram, index, 0);
if (test_slot_flag(zram, index, ZRAM_HUGE)) {
+ /*
+ * Writeback completion decrements ->huge_pages but keeps
+ * ZRAM_HUGE flag for deferred decompression path.
+ */
+ if (!test_slot_flag(zram, index, ZRAM_WB))
+ atomic64_dec(&zram->stats.huge_pages);
clear_slot_flag(zram, index, ZRAM_HUGE);
- atomic64_dec(&zram->stats.huge_pages);
}
if (test_slot_flag(zram, index, ZRAM_WB)) {
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 246b6205c5e0..ab146894ba4e 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -251,11 +251,13 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
bt_dev_err(hdev, "Hardware error 0x%2.2x", code);
+ hci_req_sync_lock(hdev);
+
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reset after hardware error failed (%ld)",
PTR_ERR(skb));
- return;
+ goto unlock;
}
kfree_skb(skb);
@@ -263,18 +265,21 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)",
PTR_ERR(skb));
- return;
+ goto unlock;
}
if (skb->len != 13) {
bt_dev_err(hdev, "Exception info size mismatch");
kfree_skb(skb);
- return;
+ goto unlock;
}
bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1));
kfree_skb(skb);
+
+unlock:
+ hci_req_sync_unlock(hdev);
}
EXPORT_SYMBOL_GPL(btintel_hw_error);
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 74f820e89655..3b0626920193 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/
if (soc_type == QCA_WCN3988)
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
+ else if (soc_type == QCA_WCN3998)
+ rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index a1c5eb993e47..5c535f3ab722 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2376,8 +2376,11 @@ static void btusb_work(struct work_struct *work)
if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
+ unsigned int sco_idx;
- new_alts = alts[data->sco_num - 1];
+ sco_idx = min_t(unsigned int, data->sco_num - 1,
+ ARRAY_SIZE(alts) - 1);
+ new_alts = alts[sco_idx];
} else {
new_alts = data->sco_num;
}
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 91acf24f1ef5..91c96ad12342 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
if (err || !fw->data || !fw->size) {
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
err, bts_scr_name);
+ if (!err)
+ release_firmware(fw);
return -EINVAL;
}
ptr = (void *)fw->data;
diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
index 3f00d953fb9a..c920bd6fbaaf 100644
--- a/drivers/bus/simple-pm-bus.c
+++ b/drivers/bus/simple-pm-bus.c
@@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
* that's not listed in simple_pm_bus_of_match. We don't want to do any
* of the simple-pm-bus tasks for these devices, so return early.
*/
- if (pdev->driver_override)
+ if (device_has_driver_override(&pdev->dev))
return 0;
match = of_match_device(dev->driver->of_match_table, dev);
@@ -78,7 +78,7 @@ static void simple_pm_bus_remove(struct platform_device *pdev)
{
const void *data = of_device_get_match_data(&pdev->dev);
- if (pdev->driver_override || data)
+ if (device_has_driver_override(&pdev->dev) || data)
return;
dev_dbg(&pdev->dev, "%s\n", __func__);
diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c
index 1d7dd3d2c101..934c5087ec2b 100644
--- a/drivers/cache/ax45mp_cache.c
+++ b/drivers/cache/ax45mp_cache.c
@@ -178,11 +178,11 @@ static const struct of_device_id ax45mp_cache_ids[] = {
static int __init ax45mp_cache_init(void)
{
- struct device_node *np;
struct resource res;
int ret;
- np = of_find_matching_node(NULL, ax45mp_cache_ids);
+ struct device_node *np __free(device_node) =
+ of_find_matching_node(NULL, ax45mp_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;
diff --git a/drivers/cache/starfive_starlink_cache.c b/drivers/cache/starfive_starlink_cache.c
index 24c7d078ca22..3a25d2d7c70c 100644
--- a/drivers/cache/starfive_starlink_cache.c
+++ b/drivers/cache/starfive_starlink_cache.c
@@ -102,11 +102,11 @@ static const struct of_device_id starlink_cache_ids[] = {
static int __init starlink_cache_init(void)
{
- struct device_node *np;
u32 block_size;
int ret;
- np = of_find_matching_node(NULL, starlink_cache_ids);
+ struct device_node *np __free(device_node) =
+ of_find_matching_node(NULL, starlink_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index a85ec48a798b..9b33df9967ec 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -706,8 +706,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
if (ret)
goto put_device;
- ret = driver_set_override(&pdev->dev, &pdev->driver_override,
- "imx-scu-clk", strlen("imx-scu-clk"));
+ ret = device_set_driver_override(&pdev->dev, "imx-scu-clk");
if (ret)
goto put_device;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 277884d91913..1f794524a1d9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1427,12 +1427,9 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
* If there is a problem with its frequency table, take it
* offline and drop it.
*/
- if (policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_ASCENDING &&
- policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_DESCENDING) {
- ret = cpufreq_table_validate_and_sort(policy);
- if (ret)
- goto out_offline_policy;
- }
+ ret = cpufreq_table_validate_and_sort(policy);
+ if (ret)
+ goto out_offline_policy;
/* related_cpus should at least include policy->cpus. */
cpumask_copy(policy->related_cpus, policy->cpus);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index e0e847764511..df01d33993d8 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy)
dbs_info->requested_freq = policy->cur;
}
+static void cs_limits(struct cpufreq_policy *policy)
+{
+ struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ /*
+ * The limits have changed, so may have the current frequency. Reset
+ * requested_freq to avoid any unintended outcomes due to the mismatch.
+ */
+ dbs_info->requested_freq = policy->cur;
+}
+
static struct dbs_governor cs_governor = {
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
.kobj_type = { .default_groups = cs_groups },
@@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = {
.init = cs_init,
.exit = cs_exit,
.start = cs_start,
+ .limits = cs_limits,
};
#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 36eb7aee4bcd..acf101878733 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
{
+ struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs;
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
@@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
mutex_lock(&policy_dbs->update_mutex);
cpufreq_policy_apply_limits(policy);
gov_update_sample_delay(policy_dbs, 0);
+ if (gov->limits)
+ gov->limits(policy);
mutex_unlock(&policy_dbs->update_mutex);
out:
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 168c23fd7fca..1462d59277bd 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -138,6 +138,7 @@ struct dbs_governor {
int (*init)(struct dbs_data *dbs_data);
void (*exit)(struct dbs_data *dbs_data);
void (*start)(struct cpufreq_policy *policy);
+ void (*limits)(struct cpufreq_policy *policy);
};
static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 7f251daf03ce..5b364d8da4f9 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
if (policy_has_boost_freq(policy))
policy->boost_supported = true;
+ if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING ||
+ policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_DESCENDING)
+ return 0;
+
return set_freq_table_sorted(policy);
}
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 8b2dfc11289b..aebf4dad545e 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -2408,10 +2408,8 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
* in Firmware state on failure. Use snp_reclaim_pages() to
* transition either case back to Hypervisor-owned state.
*/
- if (snp_reclaim_pages(__pa(data), 1, true)) {
- snp_leak_pages(__page_to_pfn(status_page), 1);
+ if (snp_reclaim_pages(__pa(data), 1, true))
return -EFAULT;
- }
}
if (ret)
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 329f60ad422e..9214bbfc868f 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -332,6 +332,13 @@ static int __init padlock_init(void)
if (!x86_match_cpu(padlock_sha_ids) || !boot_cpu_has(X86_FEATURE_PHE_EN))
return -ENODEV;
+ /*
+ * Skip family 0x07 and newer used by Zhaoxin processors,
+ * as the driver's self-tests fail on these CPUs.
+ */
+ if (c->x86 >= 0x07)
+ return -ENODEV;
+
/* Register the newly added algorithm module if on *
* VIA Nano processor, or else just do as before */
if (c->x86_model < 0x0f) {
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 4589bf11d3fe..80aeb0d556bd 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -59,6 +59,7 @@ config CXL_ACPI
tristate "CXL ACPI: Platform Support"
depends on ACPI
depends on ACPI_NUMA
+ depends on CXL_PMEM || !CXL_PMEM
default CXL_BUS
select ACPI_TABLE_LIB
select ACPI_HMAT
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index c222e98ae736..cb5d5a047a9d 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -94,7 +94,6 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
struct cxl_hdm *cxlhdm;
void __iomem *hdm;
u32 ctrl;
- int i;
if (!info)
return false;
@@ -113,22 +112,16 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
return false;
/*
- * If any decoders are committed already, there should not be any
- * emulated DVSEC decoders.
+ * If HDM decoders are globally enabled, do not fall back to DVSEC
+ * range emulation. Zeroed decoder registers after region teardown
+ * do not imply absence of HDM capability.
+ *
+ * Falling back to DVSEC here would treat the decoder as AUTO and
+ * may incorrectly latch default interleave settings.
*/
- for (i = 0; i < cxlhdm->decoder_count; i++) {
- ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
- dev_dbg(&info->port->dev,
- "decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n",
- info->port->id, i,
- FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl),
- readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i)));
- if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
- return false;
- }
+ ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
+ if (ctrl & CXL_HDM_DECODER_ENABLE)
+ return false;
return true;
}
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index e7a6452bf544..12386d912705 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1301,7 +1301,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
* Require an endpoint to be safe otherwise the driver can not
* be sure that the device is unmapped.
*/
- if (endpoint && cxl_num_decoders_committed(endpoint) == 0)
+ if (cxlmd->dev.driver && cxl_num_decoders_committed(endpoint) == 0)
return __cxl_mem_sanitize(mds, cmd);
return -EBUSY;
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 0c5957d1d329..c5aacd7054f1 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -552,10 +552,13 @@ static void cxl_port_release(struct device *dev)
xa_destroy(&port->dports);
xa_destroy(&port->regions);
ida_free(&cxl_port_ida, port->id);
- if (is_cxl_root(port))
+
+ if (is_cxl_root(port)) {
kfree(to_cxl_root(port));
- else
+ } else {
+ put_device(dev->parent);
kfree(port);
+ }
}
static ssize_t decoders_committed_show(struct device *dev,
@@ -707,6 +710,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
struct cxl_port *iter;
dev->parent = &parent_port->dev;
+ get_device(dev->parent);
port->depth = parent_port->depth + 1;
port->parent_dport = parent_dport;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 42874948b589..c37ae0b28bbb 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -3854,8 +3854,10 @@ static int __construct_region(struct cxl_region *cxlr,
}
rc = sysfs_update_group(&cxlr->dev.kobj, &cxl_region_group);
- if (rc)
+ if (rc) {
+ kfree(res);
return rc;
+ }
rc = insert_resource(cxlrd->res, res);
if (rc) {
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index 082ec0f1c3a0..261dff7ced9f 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -554,7 +554,7 @@ static __exit void cxl_pmem_exit(void)
MODULE_DESCRIPTION("CXL PMEM: Persistent Memory Support");
MODULE_LICENSE("GPL v2");
-module_init(cxl_pmem_init);
+subsys_initcall(cxl_pmem_init);
module_exit(cxl_pmem_exit);
MODULE_IMPORT_NS("CXL");
MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index e7d698b352d3..5397dbda4f72 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -844,6 +844,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
{
struct dw_edma_chip *chip = dw->chip;
struct device *dev = dw->chip->dev;
+ struct msi_desc *msi_desc;
u32 wr_mask = 1;
u32 rd_mask = 1;
int i, err = 0;
@@ -895,9 +896,12 @@ static int dw_edma_irq_request(struct dw_edma *dw,
&dw->irq[i]);
if (err)
goto err_irq_free;
-
- if (irq_get_msi_desc(irq))
+ msi_desc = irq_get_msi_desc(irq);
+ if (msi_desc) {
get_cached_msi_msg(irq, &dw->irq[i].msi);
+ if (!msi_desc->pci.msi_attrib.is_msix)
+ dw->irq[i].msi.data = dw->irq[0].msi.data + i;
+ }
}
dw->nr_irqs = i;
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index e3f8db4fe909..ce8f7254bab2 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -252,10 +252,10 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
lower_32_bits(chunk->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
upper_32_bits(chunk->ll_region.paddr));
+ /* Set consumer cycle */
+ SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
+ HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
}
- /* Set consumer cycle */
- SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
- HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
dw_hdma_v0_sync_ll_data(chunk);
diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
index dbcdd1e68319..b596baa0a182 100644
--- a/drivers/dma/fsl-edma-main.c
+++ b/drivers/dma/fsl-edma-main.c
@@ -317,10 +317,8 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
return NULL;
i = fsl_chan - fsl_edma->chans;
- fsl_chan->priority = dma_spec->args[1];
- fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
- fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
- fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
+ if (!b_chmux && i != dma_spec->args[0])
+ continue;
if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
continue;
@@ -328,17 +326,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
continue;
- if (!b_chmux && i == dma_spec->args[0]) {
- chan = dma_get_slave_channel(chan);
- chan->device->privatecnt++;
- return chan;
- } else if (b_chmux && !fsl_chan->srcid) {
- /* if controller support channel mux, choose a free channel */
- chan = dma_get_slave_channel(chan);
- chan->device->privatecnt++;
- fsl_chan->srcid = dma_spec->args[0];
- return chan;
- }
+ fsl_chan->srcid = dma_spec->args[0];
+ fsl_chan->priority = dma_spec->args[1];
+ fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
+ fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
+ fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
+
+ chan = dma_get_slave_channel(chan);
+ chan->device->privatecnt++;
+ return chan;
}
return NULL;
}
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index c37d233535f9..0366c7cf3502 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -158,11 +158,7 @@ static const struct device_type idxd_cdev_file_type = {
static void idxd_cdev_dev_release(struct device *dev)
{
struct idxd_cdev *idxd_cdev = dev_to_cdev(dev);
- struct idxd_cdev_context *cdev_ctx;
- struct idxd_wq *wq = idxd_cdev->wq;
- cdev_ctx = &ictx[wq->idxd->data->type];
- ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
kfree(idxd_cdev);
}
@@ -582,11 +578,15 @@ int idxd_wq_add_cdev(struct idxd_wq *wq)
void idxd_wq_del_cdev(struct idxd_wq *wq)
{
+ struct idxd_cdev_context *cdev_ctx;
struct idxd_cdev *idxd_cdev;
idxd_cdev = wq->idxd_cdev;
wq->idxd_cdev = NULL;
cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev));
+
+ cdev_ctx = &ictx[wq->idxd->data->type];
+ ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
put_device(cdev_dev(idxd_cdev));
}
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index c26128529ff4..131138483b87 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -175,6 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq)
free_descs(wq);
dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
sbitmap_queue_free(&wq->sbq);
+ wq->type = IDXD_WQT_NONE;
}
EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD");
@@ -382,7 +383,6 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
lockdep_assert_held(&wq->wq_lock);
wq->state = IDXD_WQ_DISABLED;
memset(wq->wqcfg, 0, idxd->wqcfg_size);
- wq->type = IDXD_WQT_NONE;
wq->threshold = 0;
wq->priority = 0;
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
@@ -831,8 +831,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
struct device *dev = &idxd->pdev->dev;
struct idxd_evl *evl = idxd->evl;
- gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
- if (!gencfg.evl_en)
+ if (!evl)
return;
mutex_lock(&evl->lock);
@@ -1125,7 +1124,11 @@ int idxd_device_config(struct idxd_device *idxd)
{
int rc;
- lockdep_assert_held(&idxd->dev_lock);
+ guard(spinlock)(&idxd->dev_lock);
+
+ if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
+ return 0;
+
rc = idxd_wqs_setup(idxd);
if (rc < 0)
return rc;
@@ -1332,6 +1335,11 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
free_irq(ie->vector, ie);
idxd_flush_pending_descs(ie);
+
+ /* The interrupt might have been already released by FLR */
+ if (ie->int_handle == INVALID_INT_HANDLE)
+ return;
+
if (idxd->request_int_handles)
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
idxd_device_clear_perm_entry(idxd, ie);
@@ -1340,6 +1348,23 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
ie->pasid = IOMMU_PASID_INVALID;
}
+void idxd_wq_flush_descs(struct idxd_wq *wq)
+{
+ struct idxd_irq_entry *ie = &wq->ie;
+ struct idxd_device *idxd = wq->idxd;
+
+ guard(mutex)(&wq->wq_lock);
+
+ if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL)
+ return;
+
+ idxd_flush_pending_descs(ie);
+ if (idxd->request_int_handles)
+ idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
+ idxd_device_clear_perm_entry(idxd, ie);
+ ie->int_handle = INVALID_INT_HANDLE;
+}
+
int idxd_wq_request_irq(struct idxd_wq *wq)
{
struct idxd_device *idxd = wq->idxd;
@@ -1454,11 +1479,7 @@ int idxd_drv_enable_wq(struct idxd_wq *wq)
}
}
- rc = 0;
- spin_lock(&idxd->dev_lock);
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
- rc = idxd_device_config(idxd);
- spin_unlock(&idxd->dev_lock);
+ rc = idxd_device_config(idxd);
if (rc < 0) {
dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc);
goto err;
@@ -1533,7 +1554,6 @@ void idxd_drv_disable_wq(struct idxd_wq *wq)
idxd_wq_reset(wq);
idxd_wq_free_resources(wq);
percpu_ref_exit(&wq->wq_active);
- wq->type = IDXD_WQT_NONE;
wq->client_count = 0;
}
EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD");
@@ -1554,10 +1574,7 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
}
/* Device configuration */
- spin_lock(&idxd->dev_lock);
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
- rc = idxd_device_config(idxd);
- spin_unlock(&idxd->dev_lock);
+ rc = idxd_device_config(idxd);
if (rc < 0)
return -ENXIO;
diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c
index dbecd699237e..9937b671f637 100644
--- a/drivers/dma/idxd/dma.c
+++ b/drivers/dma/idxd/dma.c
@@ -194,6 +194,22 @@ static void idxd_dma_release(struct dma_device *device)
kfree(idxd_dma);
}
+static int idxd_dma_terminate_all(struct dma_chan *c)
+{
+ struct idxd_wq *wq = to_idxd_wq(c);
+
+ idxd_wq_flush_descs(wq);
+
+ return 0;
+}
+
+static void idxd_dma_synchronize(struct dma_chan *c)
+{
+ struct idxd_wq *wq = to_idxd_wq(c);
+
+ idxd_wq_drain(wq);
+}
+
int idxd_register_dma_device(struct idxd_device *idxd)
{
struct idxd_dma_dev *idxd_dma;
@@ -224,6 +240,8 @@ int idxd_register_dma_device(struct idxd_device *idxd)
dma->device_issue_pending = idxd_dma_issue_pending;
dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources;
dma->device_free_chan_resources = idxd_dma_free_chan_resources;
+ dma->device_terminate_all = idxd_dma_terminate_all;
+ dma->device_synchronize = idxd_dma_synchronize;
rc = dma_async_device_register(dma);
if (rc < 0) {
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index ea8c4daed38d..ce78b9a7c641 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -803,6 +803,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq);
int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
void idxd_wq_free_irq(struct idxd_wq *wq);
int idxd_wq_request_irq(struct idxd_wq *wq);
+void idxd_wq_flush_descs(struct idxd_wq *wq);
/* submission */
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index fb80803d5b57..f1cfc7790d95 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -973,7 +973,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd,
idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
- idxd->evl->size = saved_evl->size;
+ if (idxd->evl)
+ idxd->evl->size = saved_evl->size;
for (i = 0; i < idxd->max_groups; i++) {
struct idxd_group *saved_group, *group;
@@ -1104,12 +1105,10 @@ static void idxd_reset_done(struct pci_dev *pdev)
idxd_device_config_restore(idxd, idxd->idxd_saved);
/* Re-configure IDXD device if allowed. */
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
- rc = idxd_device_config(idxd);
- if (rc < 0) {
- dev_err(dev, "HALT: %s config fails\n", idxd_name);
- goto out;
- }
+ rc = idxd_device_config(idxd);
+ if (rc < 0) {
+ dev_err(dev, "HALT: %s config fails\n", idxd_name);
+ goto out;
}
/* Bind IDXD device to driver. */
@@ -1147,6 +1146,7 @@ static void idxd_reset_done(struct pci_dev *pdev)
}
out:
kfree(idxd->idxd_saved);
+ idxd->idxd_saved = NULL;
}
static const struct pci_error_handlers idxd_error_handler = {
diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
index 7782f8c51c32..6a25e1fd0e62 100644
--- a/drivers/dma/idxd/irq.c
+++ b/drivers/dma/idxd/irq.c
@@ -397,6 +397,17 @@ static void idxd_device_flr(struct work_struct *work)
dev_err(&idxd->pdev->dev, "FLR failed\n");
}
+static void idxd_wqs_flush_descs(struct idxd_device *idxd)
+{
+ int i;
+
+ for (i = 0; i < idxd->max_wqs; i++) {
+ struct idxd_wq *wq = idxd->wqs[i];
+
+ idxd_wq_flush_descs(wq);
+ }
+}
+
static irqreturn_t idxd_halt(struct idxd_device *idxd)
{
union gensts_reg gensts;
@@ -415,6 +426,11 @@ static irqreturn_t idxd_halt(struct idxd_device *idxd)
} else if (gensts.reset_type == IDXD_DEVICE_RESET_FLR) {
idxd->state = IDXD_DEV_HALTED;
idxd_mask_error_interrupts(idxd);
+ /* Flush all pending descriptors, and disable
+ * interrupts, they will be re-enabled when FLR
+ * concludes.
+ */
+ idxd_wqs_flush_descs(idxd);
dev_dbg(&idxd->pdev->dev,
"idxd halted, doing FLR. After FLR, configs are restored\n");
INIT_WORK(&idxd->work, idxd_device_flr);
diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c
index 6db1c5fcedc5..03217041b8b3 100644
--- a/drivers/dma/idxd/submit.c
+++ b/drivers/dma/idxd/submit.c
@@ -138,7 +138,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
*/
list_for_each_entry_safe(d, t, &flist, list) {
list_del_init(&d->list);
- idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true,
+ idxd_dma_complete_txd(d, IDXD_COMPLETE_ABORT, true,
NULL, NULL);
}
}
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index cc2c83d7f710..6d251095c350 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -1836,6 +1836,7 @@ static void idxd_conf_device_release(struct device *dev)
{
struct idxd_device *idxd = confdev_to_idxd(dev);
+ destroy_workqueue(idxd->wq);
kfree(idxd->groups);
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index d84ca551b2bf..f30bdf69c740 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -10,6 +10,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
@@ -296,13 +297,10 @@ static void rz_dmac_disable_hw(struct rz_dmac_chan *channel)
{
struct dma_chan *chan = &channel->vc.chan;
struct rz_dmac *dmac = to_rz_dmac(chan->device);
- unsigned long flags;
dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
- local_irq_save(flags);
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
- local_irq_restore(flags);
}
static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
@@ -447,6 +445,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)
if (!desc)
break;
+ /* No need to lock. This is called only for the 1st client. */
list_add_tail(&desc->node, &channel->ld_free);
channel->descs_allocated++;
}
@@ -502,18 +501,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n",
__func__, channel->index, &src, &dest, len);
- if (list_empty(&channel->ld_free))
- return NULL;
+ scoped_guard(spinlock_irqsave, &channel->vc.lock) {
+ if (list_empty(&channel->ld_free))
+ return NULL;
- desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
- desc->type = RZ_DMAC_DESC_MEMCPY;
- desc->src = src;
- desc->dest = dest;
- desc->len = len;
- desc->direction = DMA_MEM_TO_MEM;
+ desc->type = RZ_DMAC_DESC_MEMCPY;
+ desc->src = src;
+ desc->dest = dest;
+ desc->len = len;
+ desc->direction = DMA_MEM_TO_MEM;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ }
- list_move_tail(channel->ld_free.next, &channel->ld_queue);
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
}
@@ -529,27 +531,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
int dma_length = 0;
int i = 0;
- if (list_empty(&channel->ld_free))
- return NULL;
+ scoped_guard(spinlock_irqsave, &channel->vc.lock) {
+ if (list_empty(&channel->ld_free))
+ return NULL;
- desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
- for_each_sg(sgl, sg, sg_len, i) {
- dma_length += sg_dma_len(sg);
- }
+ for_each_sg(sgl, sg, sg_len, i)
+ dma_length += sg_dma_len(sg);
- desc->type = RZ_DMAC_DESC_SLAVE_SG;
- desc->sg = sgl;
- desc->sgcount = sg_len;
- desc->len = dma_length;
- desc->direction = direction;
+ desc->type = RZ_DMAC_DESC_SLAVE_SG;
+ desc->sg = sgl;
+ desc->sgcount = sg_len;
+ desc->len = dma_length;
+ desc->direction = direction;
- if (direction == DMA_DEV_TO_MEM)
- desc->src = channel->src_per_address;
- else
- desc->dest = channel->dst_per_address;
+ if (direction == DMA_DEV_TO_MEM)
+ desc->src = channel->src_per_address;
+ else
+ desc->dest = channel->dst_per_address;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ }
- list_move_tail(channel->ld_free.next, &channel->ld_queue);
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
}
@@ -561,8 +565,8 @@ static int rz_dmac_terminate_all(struct dma_chan *chan)
unsigned int i;
LIST_HEAD(head);
- rz_dmac_disable_hw(channel);
spin_lock_irqsave(&channel->vc.lock, flags);
+ rz_dmac_disable_hw(channel);
for (i = 0; i < DMAC_NR_LMDESC; i++)
lmdesc[i].header = 0;
@@ -699,7 +703,9 @@ static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel)
if (chstat & CHSTAT_ER) {
dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
channel->index, chstat);
- rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+
+ scoped_guard(spinlock_irqsave, &channel->vc.lock)
+ rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
goto done;
}
diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c
index d02a4dac2291..782a55edc55b 100644
--- a/drivers/dma/xilinx/xdma.c
+++ b/drivers/dma/xilinx/xdma.c
@@ -1234,8 +1234,8 @@ static int xdma_probe(struct platform_device *pdev)
xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base,
&xdma_regmap_config);
- if (!xdev->rmap) {
- xdma_err(xdev, "config regmap failed: %d", ret);
+ if (IS_ERR(xdev->rmap)) {
+ xdma_err(xdev, "config regmap failed: %pe", xdev->rmap);
goto failed;
}
INIT_LIST_HEAD(&xdev->dma_dev.channels);
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index b53292e02448..e3a18ee42aa2 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -997,16 +997,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
struct xilinx_cdma_tx_segment,
node);
cdma_hw = &cdma_seg->hw;
- residue += (cdma_hw->control - cdma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (cdma_hw->control & chan->xdev->max_buffer_len) -
+ (cdma_hw->status & chan->xdev->max_buffer_len);
} else if (chan->xdev->dma_config->dmatype ==
XDMA_TYPE_AXIDMA) {
axidma_seg = list_entry(entry,
struct xilinx_axidma_tx_segment,
node);
axidma_hw = &axidma_seg->hw;
- residue += (axidma_hw->control - axidma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (axidma_hw->control & chan->xdev->max_buffer_len) -
+ (axidma_hw->status & chan->xdev->max_buffer_len);
} else {
aximcdma_seg =
list_entry(entry,
@@ -1014,8 +1014,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
node);
aximcdma_hw = &aximcdma_seg->hw;
residue +=
- (aximcdma_hw->control - aximcdma_hw->status) &
- chan->xdev->max_buffer_len;
+ (aximcdma_hw->control & chan->xdev->max_buffer_len) -
+ (aximcdma_hw->status & chan->xdev->max_buffer_len);
}
}
@@ -1235,14 +1235,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
dma_cookie_init(dchan);
- if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
- /* For AXI DMA resetting once channel will reset the
- * other channel as well so enable the interrupts here.
- */
- dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
- XILINX_DMA_DMAXR_ALL_IRQ_MASK);
- }
-
if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
XILINX_CDMA_CR_SGMODE);
@@ -1564,8 +1556,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
if (chan->err)
return;
- if (list_empty(&chan->pending_list))
+ if (list_empty(&chan->pending_list)) {
+ if (chan->cyclic) {
+ struct xilinx_dma_tx_descriptor *desc;
+ struct list_head *entry;
+
+ desc = list_last_entry(&chan->done_list,
+ struct xilinx_dma_tx_descriptor, node);
+ list_for_each(entry, &desc->segments) {
+ struct xilinx_axidma_tx_segment *axidma_seg;
+ struct xilinx_axidma_desc_hw *axidma_hw;
+ axidma_seg = list_entry(entry,
+ struct xilinx_axidma_tx_segment,
+ node);
+ axidma_hw = &axidma_seg->hw;
+ axidma_hw->status = 0;
+ }
+
+ list_splice_tail_init(&chan->done_list, &chan->active_list);
+ chan->desc_pendingcount = 0;
+ chan->idle = false;
+ }
return;
+ }
if (!chan->idle)
return;
@@ -1591,6 +1604,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
head_desc->async_tx.phys);
reg &= ~XILINX_DMA_CR_DELAY_MAX;
reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT;
+ reg |= XILINX_DMA_DMAXR_ALL_IRQ_MASK;
dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
xilinx_dma_start(chan);
@@ -3024,7 +3038,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
return -EINVAL;
}
- xdev->common.directions |= chan->direction;
+ xdev->common.directions |= BIT(chan->direction);
/* Request the interrupt */
chan->irq = of_irq_get(node, chan->tdest);
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index f1a2bee39bf1..82b3b6d9ed2d 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -257,9 +257,10 @@ static void fwnet_header_cache_update(struct hh_cache *hh,
memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
}
-static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int fwnet_header_parse(const struct sk_buff *skb, const struct net_device *dev,
+ unsigned char *haddr)
{
- memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
+ memcpy(haddr, dev->dev_addr, FWNET_ALEN);
return FWNET_ALEN;
}
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 12a625387d6e..f2f94d4d533e 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -205,12 +205,12 @@ static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt)
return 0;
}
-static int ffa_rxtx_unmap(u16 vm_id)
+static int ffa_rxtx_unmap(void)
{
ffa_value_t ret;
invoke_ffa_fn((ffa_value_t){
- .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0),
+ .a0 = FFA_RXTX_UNMAP,
}, &ret);
if (ret.a0 == FFA_ERROR)
@@ -2097,7 +2097,7 @@ static int __init ffa_init(void)
pr_err("failed to setup partitions\n");
ffa_notifications_cleanup();
- ffa_rxtx_unmap(drv_info->vm_id);
+ ffa_rxtx_unmap();
free_pages:
if (drv_info->tx_buffer)
free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);
@@ -2112,7 +2112,7 @@ static void __exit ffa_exit(void)
{
ffa_notifications_cleanup();
ffa_partitions_cleanup();
- ffa_rxtx_unmap(drv_info->vm_id);
+ ffa_rxtx_unmap();
free_pages_exact(drv_info->tx_buffer, drv_info->rxtx_bufsz);
free_pages_exact(drv_info->rx_buffer, drv_info->rxtx_bufsz);
kfree(drv_info);
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 9168794adae4..40ec184eedae 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1066,7 +1066,7 @@ static int scmi_register_event_handler(struct scmi_notify_instance *ni,
* since at creation time we usually want to have all setup and ready before
* events really start flowing.
*
- * Return: A properly refcounted handler on Success, NULL on Failure
+ * Return: A properly refcounted handler on Success, ERR_PTR on Failure
*/
static inline struct scmi_event_handler *
__scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
@@ -1113,7 +1113,7 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
}
mutex_unlock(&ni->pending_mtx);
- return hndl;
+ return hndl ?: ERR_PTR(-ENODEV);
}
static struct scmi_event_handler *
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 4c75970326e6..f51245aca259 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -189,13 +189,13 @@ struct scmi_protocol_handle {
/**
* struct scmi_iterator_state - Iterator current state descriptor
- * @desc_index: Starting index for the current mulit-part request.
+ * @desc_index: Starting index for the current multi-part request.
* @num_returned: Number of returned items in the last multi-part reply.
* @num_remaining: Number of remaining items in the multi-part message.
* @max_resources: Maximum acceptable number of items, configured by the caller
* depending on the underlying resources that it is querying.
* @loop_idx: The iterator loop index in the current multi-part reply.
- * @rx_len: Size in bytes of the currenly processed message; it can be used by
+ * @rx_len: Size in bytes of the currently processed message; it can be used by
* the user of the iterator to verify a reply size.
* @priv: Optional pointer to some additional state-related private data setup
* by the caller during the iterations.
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 00e74449ce09..2acad5fa5a28 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -18,6 +18,7 @@
#include <linux/bitmap.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -940,13 +941,13 @@ static int scpi_probe(struct platform_device *pdev)
int idx = scpi_drvinfo->num_chans;
struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
struct mbox_client *cl = &pchan->cl;
- struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
+ struct device_node *shmem __free(device_node) =
+ of_parse_phandle(np, "shmem", idx);
if (!of_match_node(shmem_of_match, shmem))
return -ENXIO;
ret = of_address_to_resource(shmem, 0, &res);
- of_node_put(shmem);
if (ret) {
dev_err(dev, "failed to get SCPI payload mem resource\n");
return ret;
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index ec820686b302..f52141f842a1 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -233,6 +233,7 @@ static void drm_events_release(struct drm_file *file_priv)
void drm_file_free(struct drm_file *file)
{
struct drm_device *dev;
+ int idx;
if (!file)
return;
@@ -249,9 +250,11 @@ void drm_file_free(struct drm_file *file)
drm_events_release(file);
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (drm_core_check_feature(dev, DRIVER_MODESET) &&
+ drm_dev_enter(dev, &idx)) {
drm_fb_release(file);
drm_property_destroy_user_blobs(dev, file);
+ drm_dev_exit(idx);
}
if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 4500deef4127..2062ca607833 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -554,23 +554,27 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
-static vm_fault_t drm_gem_shmem_try_insert_pfn_pmd(struct vm_fault *vmf, unsigned long pfn)
+static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
+ unsigned long pfn)
{
+ if (!order) {
+ return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
- unsigned long paddr = pfn << PAGE_SHIFT;
- bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
-
- if (aligned && pmd_none(*vmf->pmd)) {
- /* Read-only mapping; split upon write fault */
- pfn &= PMD_MASK >> PAGE_SHIFT;
- return vmf_insert_pfn_pmd(vmf, pfn, false);
- }
+ } else if (order == PMD_ORDER) {
+ unsigned long paddr = pfn << PAGE_SHIFT;
+ bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
+
+ if (aligned &&
+ folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
+ pfn &= PMD_MASK >> PAGE_SHIFT;
+ return vmf_insert_pfn_pmd(vmf, pfn, false);
+ }
#endif
-
- return 0;
+ }
+ return VM_FAULT_FALLBACK;
}
-static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
+static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int order)
{
struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
@@ -584,6 +588,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
struct folio *folio;
unsigned long pfn;
+ if (order && order != PMD_ORDER)
+ return VM_FAULT_FALLBACK;
+
dma_resv_lock(obj->resv, NULL);
if (page_offset >= num_pages || drm_WARN_ON_ONCE(dev, !shmem->pages) ||
@@ -597,11 +604,7 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
pfn = page_to_pfn(page);
- if (folio_test_pmd_mappable(folio))
- ret = drm_gem_shmem_try_insert_pfn_pmd(vmf, pfn);
- if (ret != VM_FAULT_NOPAGE)
- ret = vmf_insert_pfn(vma, vmf->address, pfn);
-
+ ret = try_insert_pfn(vmf, order, pfn);
if (ret == VM_FAULT_NOPAGE)
folio_mark_accessed(folio);
@@ -611,6 +614,11 @@ out:
return ret;
}
+static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
+{
+ return drm_gem_shmem_any_fault(vmf, 0);
+}
+
static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
@@ -665,6 +673,9 @@ static vm_fault_t drm_gem_shmem_pfn_mkwrite(struct vm_fault *vmf)
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
.fault = drm_gem_shmem_fault,
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+ .huge_fault = drm_gem_shmem_any_fault,
+#endif
.open = drm_gem_shmem_vm_open,
.close = drm_gem_shmem_vm_close,
.pfn_mkwrite = drm_gem_shmem_pfn_mkwrite,
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 66f7dc37b597..65b7f4f22f09 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -589,10 +589,13 @@ void drm_mode_config_cleanup(struct drm_device *dev)
*/
WARN_ON(!list_empty(&dev->mode_config.fb_list));
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
- struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]");
+ if (list_empty(&fb->filp_head) || drm_framebuffer_read_refcount(fb) > 1) {
+ struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]");
- drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
- drm_framebuffer_print_info(&p, 1, fb);
+ drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
+ drm_framebuffer_print_info(&p, 1, fb);
+ }
+ list_del_init(&fb->filp_head);
drm_framebuffer_free(&fb->base.refcount);
}
diff --git a/drivers/gpu/drm/drm_pagemap_util.c b/drivers/gpu/drm/drm_pagemap_util.c
index 14ddb948a32e..6111d90a38e2 100644
--- a/drivers/gpu/drm/drm_pagemap_util.c
+++ b/drivers/gpu/drm/drm_pagemap_util.c
@@ -65,18 +65,14 @@ static void drm_pagemap_cache_fini(void *arg)
drm_dbg(cache->shrinker->drm, "Destroying dpagemap cache.\n");
spin_lock(&cache->lock);
dpagemap = cache->dpagemap;
- if (!dpagemap) {
- spin_unlock(&cache->lock);
- goto out;
- }
+ cache->dpagemap = NULL;
+ if (dpagemap && !drm_pagemap_shrinker_cancel(dpagemap))
+ dpagemap = NULL;
+ spin_unlock(&cache->lock);
- if (drm_pagemap_shrinker_cancel(dpagemap)) {
- cache->dpagemap = NULL;
- spin_unlock(&cache->lock);
+ if (dpagemap)
drm_pagemap_destroy(dpagemap, false);
- }
-out:
mutex_destroy(&cache->lookup_mutex);
kfree(cache);
}
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 250734dee928..8d9fd1917c6e 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -602,7 +602,7 @@ int drm_syncobj_get_handle(struct drm_file *file_private,
drm_syncobj_get(syncobj);
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
- GFP_NOWAIT);
+ GFP_KERNEL);
if (ret)
drm_syncobj_put(syncobj);
@@ -716,7 +716,7 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
drm_syncobj_get(syncobj);
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
- GFP_NOWAIT);
+ GFP_KERNEL);
if (ret)
drm_syncobj_put(syncobj);
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index b18ce0c36a64..720a2c6e247f 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -4640,6 +4640,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
struct intel_crtc_state *saved_state;
+ int err;
saved_state = intel_crtc_state_alloc(crtc);
if (!saved_state)
@@ -4648,7 +4649,12 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
/* free the old crtc_state->hw members */
intel_crtc_free_hw_state(crtc_state);
- intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
+ err = intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
+ if (err) {
+ kfree(saved_state);
+
+ return err;
+ }
/* FIXME: before the switch to atomic started, a new pipe_config was
* kzalloc'd. Code that depends on any field being zero should be
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index e189f8c39ccb..d3a9ace4c9d1 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1188,6 +1188,7 @@ struct intel_crtc_state {
u32 dc3co_exitline;
u16 su_y_granularity;
u8 active_non_psr_pipes;
+ u8 entry_setup_frames;
const char *no_psr_reason;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 1fd1ac8d556d..7363c9817297 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -659,19 +659,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
*
* Clear any DP tunnel stream BW requirement set by
* intel_dp_tunnel_atomic_compute_stream_bw().
+ *
+ * Returns 0 in case of success, a negative error code otherwise.
*/
-void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state)
+int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ int err;
if (!crtc_state->dp_tunnel_ref.tunnel)
- return;
+ return 0;
+
+ err = drm_dp_tunnel_atomic_set_stream_bw(&state->base,
+ crtc_state->dp_tunnel_ref.tunnel,
+ crtc->pipe, 0);
+ if (err)
+ return err;
- drm_dp_tunnel_atomic_set_stream_bw(&state->base,
- crtc_state->dp_tunnel_ref.tunnel,
- crtc->pipe, 0);
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
+
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
index 7f0f720e8dca..10ab9eebcef6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
@@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
const struct intel_connector *connector,
struct intel_crtc_state *crtc_state);
-void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state);
+int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state);
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
struct intel_crtc *crtc);
@@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
return 0;
}
-static inline void
+static inline int
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state) {}
+ struct intel_crtc_state *crtc_state)
+{
+ return 0;
+}
static inline int
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index df48f27f1cc1..dd79a866b87e 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -495,8 +495,10 @@ gmbus_xfer_read_chunk(struct intel_display *display,
val = intel_de_read_fw(display, GMBUS3(display));
do {
- if (extra_byte_added && len == 1)
+ if (extra_byte_added && len == 1) {
+ len--;
break;
+ }
*buf++ = val & 0xff;
val >>= 8;
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index e06a0618b4c6..076b9b356481 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -436,11 +436,16 @@ void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
drm_framebuffer_get(plane_state->hw.fb);
}
+static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *plane_state);
+
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ unlink_nv12_plane(crtc_state, plane_state);
+
crtc_state->active_planes &= ~BIT(plane->id);
crtc_state->scaled_planes &= ~BIT(plane->id);
crtc_state->nv12_planes &= ~BIT(plane->id);
@@ -1513,6 +1518,9 @@ static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ if (!plane_state->planar_linked_plane)
+ return;
+
plane_state->planar_linked_plane = NULL;
if (!plane_state->is_y_plane)
@@ -1550,8 +1558,7 @@ static int icl_check_nv12_planes(struct intel_atomic_state *state,
if (plane->pipe != crtc->pipe)
continue;
- if (plane_state->planar_linked_plane)
- unlink_nv12_plane(crtc_state, plane_state);
+ unlink_nv12_plane(crtc_state, plane_state);
}
if (!crtc_state->nv12_planes)
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 5041a5a138d1..c13116e6f17f 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1716,7 +1716,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp,
entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, conn_state, adjusted_mode);
if (entry_setup_frames >= 0) {
- intel_dp->psr.entry_setup_frames = entry_setup_frames;
+ crtc_state->entry_setup_frames = entry_setup_frames;
} else {
crtc_state->no_psr_reason = "PSR setup timing not met";
drm_dbg_kms(display->drm,
@@ -1814,7 +1814,7 @@ static bool intel_psr_needs_wa_18037818876(struct intel_dp *intel_dp,
{
struct intel_display *display = to_intel_display(intel_dp);
- return (DISPLAY_VER(display) == 20 && intel_dp->psr.entry_setup_frames > 0 &&
+ return (DISPLAY_VER(display) == 20 && crtc_state->entry_setup_frames > 0 &&
!crtc_state->has_sel_update);
}
@@ -2190,6 +2190,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
intel_dp->psr.pkg_c_latency_used = crtc_state->pkg_c_latency_used;
intel_dp->psr.io_wake_lines = crtc_state->alpm_state.io_wake_lines;
intel_dp->psr.fast_wake_lines = crtc_state->alpm_state.fast_wake_lines;
+ intel_dp->psr.entry_setup_frames = crtc_state->entry_setup_frames;
if (!psr_interrupt_error_check(intel_dp))
return;
@@ -3112,6 +3113,8 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state,
* - Display WA #1136: skl, bxt
*/
if (intel_crtc_needs_modeset(new_crtc_state) ||
+ new_crtc_state->update_m_n ||
+ new_crtc_state->update_lrr ||
!new_crtc_state->has_psr ||
!new_crtc_state->active_planes ||
new_crtc_state->has_sel_update != psr->sel_update_enabled ||
diff --git a/drivers/gpu/drm/i915/i915_wait_util.h b/drivers/gpu/drm/i915/i915_wait_util.h
index 7376898e3bf8..e1ed7921ec70 100644
--- a/drivers/gpu/drm/i915/i915_wait_util.h
+++ b/drivers/gpu/drm/i915/i915_wait_util.h
@@ -25,9 +25,9 @@
might_sleep(); \
for (;;) { \
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
- OP; \
/* Guarantee COND check prior to timeout */ \
barrier(); \
+ OP; \
if (COND) { \
ret__ = 0; \
break; \
diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c
index f58bb66a6327..dbb6f5a8ded1 100644
--- a/drivers/gpu/drm/imagination/pvr_device.c
+++ b/drivers/gpu/drm/imagination/pvr_device.c
@@ -225,29 +225,12 @@ static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data)
}
if (pvr_dev->has_safety_events) {
- int err;
-
- /*
- * Ensure the GPU is powered on since some safety events (such
- * as ECC faults) can happen outside of job submissions, which
- * are otherwise the only time a power reference is held.
- */
- err = pvr_power_get(pvr_dev);
- if (err) {
- drm_err_ratelimited(drm_dev,
- "%s: could not take power reference (%d)\n",
- __func__, err);
- return ret;
- }
-
while (pvr_device_safety_irq_pending(pvr_dev)) {
pvr_device_safety_irq_clear(pvr_dev);
pvr_device_handle_safety_events(pvr_dev);
ret = IRQ_HANDLED;
}
-
- pvr_power_put(pvr_dev);
}
return ret;
diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c
index 7a8765c0c1ed..88fcce433d12 100644
--- a/drivers/gpu/drm/imagination/pvr_power.c
+++ b/drivers/gpu/drm/imagination/pvr_power.c
@@ -90,11 +90,11 @@ pvr_power_request_pwr_off(struct pvr_device *pvr_dev)
}
static int
-pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset)
+pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspend)
{
- if (!hard_reset) {
- int err;
+ int err;
+ if (!hard_reset) {
cancel_delayed_work_sync(&pvr_dev->watchdog.work);
err = pvr_power_request_idle(pvr_dev);
@@ -106,29 +106,47 @@ pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset)
return err;
}
- return pvr_fw_stop(pvr_dev);
+ if (rpm_suspend) {
+ /* This also waits for late processing of GPU or firmware IRQs in other cores */
+ disable_irq(pvr_dev->irq);
+ }
+
+ err = pvr_fw_stop(pvr_dev);
+ if (err && rpm_suspend)
+ enable_irq(pvr_dev->irq);
+
+ return err;
}
static int
-pvr_power_fw_enable(struct pvr_device *pvr_dev)
+pvr_power_fw_enable(struct pvr_device *pvr_dev, bool rpm_resume)
{
int err;
+ if (rpm_resume)
+ enable_irq(pvr_dev->irq);
+
err = pvr_fw_start(pvr_dev);
if (err)
- return err;
+ goto out;
err = pvr_wait_for_fw_boot(pvr_dev);
if (err) {
drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n");
pvr_fw_stop(pvr_dev);
- return err;
+ goto out;
}
queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work,
msecs_to_jiffies(WATCHDOG_TIME_MS));
return 0;
+
+out:
+ if (rpm_resume)
+ disable_irq(pvr_dev->irq);
+
+ return err;
}
bool
@@ -361,7 +379,7 @@ pvr_power_device_suspend(struct device *dev)
return -EIO;
if (pvr_dev->fw_dev.booted) {
- err = pvr_power_fw_disable(pvr_dev, false);
+ err = pvr_power_fw_disable(pvr_dev, false, true);
if (err)
goto err_drm_dev_exit;
}
@@ -391,7 +409,7 @@ pvr_power_device_resume(struct device *dev)
goto err_drm_dev_exit;
if (pvr_dev->fw_dev.booted) {
- err = pvr_power_fw_enable(pvr_dev);
+ err = pvr_power_fw_enable(pvr_dev, true);
if (err)
goto err_power_off;
}
@@ -510,7 +528,16 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
}
/* Disable IRQs for the duration of the reset. */
- disable_irq(pvr_dev->irq);
+ if (hard_reset) {
+ disable_irq(pvr_dev->irq);
+ } else {
+ /*
+ * Soft reset is triggered as a response to a FW command to the Host and is
+ * processed from the threaded IRQ handler. This code cannot (nor needs to)
+ * wait for any IRQ processing to complete.
+ */
+ disable_irq_nosync(pvr_dev->irq);
+ }
do {
if (hard_reset) {
@@ -518,7 +545,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
queues_disabled = true;
}
- err = pvr_power_fw_disable(pvr_dev, hard_reset);
+ err = pvr_power_fw_disable(pvr_dev, hard_reset, false);
if (!err) {
if (hard_reset) {
pvr_dev->fw_dev.booted = false;
@@ -541,7 +568,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
pvr_fw_irq_clear(pvr_dev);
- err = pvr_power_fw_enable(pvr_dev);
+ err = pvr_power_fw_enable(pvr_dev, false);
}
if (err && hard_reset)
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index a7c184b45bfa..5aa71fcdcfab 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -1235,6 +1235,11 @@ static int mtk_dsi_probe(struct platform_device *pdev)
dsi->host.ops = &mtk_dsi_ops;
dsi->host.dev = dev;
+
+ init_waitqueue_head(&dsi->irq_wait_queue);
+
+ platform_set_drvdata(pdev, dsi);
+
ret = mipi_dsi_host_register(&dsi->host);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to register DSI host\n");
@@ -1246,10 +1251,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n");
}
- init_waitqueue_head(&dsi->irq_wait_queue);
-
- platform_set_drvdata(pdev, dsi);
-
dsi->bridge.of_node = dev->of_node;
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index f2abaf1bda6a..57465f69c687 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -96,12 +96,17 @@ struct vmwgfx_hash_item {
struct vmw_res_func;
+struct vmw_bo;
+struct vmw_bo;
+struct vmw_resource_dirty;
+
/**
- * struct vmw-resource - base class for hardware resources
+ * struct vmw_resource - base class for hardware resources
*
* @kref: For refcounting.
* @dev_priv: Pointer to the device private for this resource. Immutable.
* @id: Device id. Protected by @dev_priv::resource_lock.
+ * @used_prio: Priority for this resource.
* @guest_memory_size: Guest memory buffer size. Immutable.
* @res_dirty: Resource contains data not yet in the guest memory buffer.
* Protected by resource reserved.
@@ -117,18 +122,16 @@ struct vmw_res_func;
* pin-count greater than zero. It is not on the resource LRU lists and its
* guest memory buffer is pinned. Hence it can't be evicted.
* @func: Method vtable for this resource. Immutable.
- * @mob_node; Node for the MOB guest memory rbtree. Protected by
+ * @mob_node: Node for the MOB guest memory rbtree. Protected by
* @guest_memory_bo reserved.
* @lru_head: List head for the LRU list. Protected by @dev_priv::resource_lock.
* @binding_head: List head for the context binding list. Protected by
* the @dev_priv::binding_mutex
+ * @dirty: resource's dirty tracker
* @res_free: The resource destructor.
* @hw_destroy: Callback to destroy the resource on the device, as part of
* resource destruction.
*/
-struct vmw_bo;
-struct vmw_bo;
-struct vmw_resource_dirty;
struct vmw_resource {
struct kref kref;
struct vmw_private *dev_priv;
@@ -196,8 +199,8 @@ struct vmw_surface_offset;
* @quality_level: Quality level.
* @autogen_filter: Filter for automatically generated mipmaps.
* @array_size: Number of array elements for a 1D/2D texture. For cubemap
- texture number of faces * array_size. This should be 0 for pre
- SM4 device.
+ * texture number of faces * array_size. This should be 0 for pre
+ * SM4 device.
* @buffer_byte_stride: Buffer byte stride.
* @num_sizes: Size of @sizes. For GB surface this should always be 1.
* @base_size: Surface dimension.
@@ -265,18 +268,24 @@ struct vmw_fifo_state {
struct vmw_res_cache_entry {
uint32_t handle;
struct vmw_resource *res;
+ /* private: */
void *private;
+ /* public: */
unsigned short valid_handle;
unsigned short valid;
};
/**
* enum vmw_dma_map_mode - indicate how to perform TTM page dma mappings.
+ * @vmw_dma_alloc_coherent: Use TTM coherent pages
+ * @vmw_dma_map_populate: Unmap from DMA just after unpopulate
+ * @vmw_dma_map_bind: Unmap from DMA just before unbind
*/
enum vmw_dma_map_mode {
- vmw_dma_alloc_coherent, /* Use TTM coherent pages */
- vmw_dma_map_populate, /* Unmap from DMA just after unpopulate */
- vmw_dma_map_bind, /* Unmap from DMA just before unbind */
+ vmw_dma_alloc_coherent,
+ vmw_dma_map_populate,
+ vmw_dma_map_bind,
+ /* private: */
vmw_dma_map_max
};
@@ -284,8 +293,11 @@ enum vmw_dma_map_mode {
* struct vmw_sg_table - Scatter/gather table for binding, with additional
* device-specific information.
*
+ * @mode: which page mapping mode to use
+ * @pages: Array of page pointers to the pages.
+ * @addrs: DMA addresses to the pages if coherent pages are used.
* @sgt: Pointer to a struct sg_table with binding information
- * @num_regions: Number of regions with device-address contiguous pages
+ * @num_pages: Number of @pages
*/
struct vmw_sg_table {
enum vmw_dma_map_mode mode;
@@ -353,6 +365,7 @@ struct vmw_ctx_validation_info;
* than from user-space
* @fp: If @kernel is false, points to the file of the client. Otherwise
* NULL
+ * @filp: DRM state for this file
* @cmd_bounce: Command bounce buffer used for command validation before
* copying to fifo space
* @cmd_bounce_size: Current command bounce buffer size
@@ -729,7 +742,7 @@ extern void vmw_svga_disable(struct vmw_private *dev_priv);
bool vmwgfx_supported(struct vmw_private *vmw);
-/**
+/*
* GMR utilities - vmwgfx_gmr.c
*/
@@ -739,7 +752,7 @@ extern int vmw_gmr_bind(struct vmw_private *dev_priv,
int gmr_id);
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
-/**
+/*
* User handles
*/
struct vmw_user_object {
@@ -759,7 +772,7 @@ void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size);
void vmw_user_object_unmap(struct vmw_user_object *uo);
bool vmw_user_object_is_mapped(struct vmw_user_object *uo);
-/**
+/*
* Resource utilities - vmwgfx_resource.c
*/
struct vmw_user_resource_conv;
@@ -819,7 +832,7 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
return !RB_EMPTY_NODE(&res->mob_node);
}
-/**
+/*
* GEM related functionality - vmwgfx_gem.c
*/
struct vmw_bo_params;
@@ -833,7 +846,7 @@ extern int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);
extern void vmw_debugfs_gem_init(struct vmw_private *vdev);
-/**
+/*
* Misc Ioctl functionality - vmwgfx_ioctl.c
*/
@@ -846,7 +859,7 @@ extern int vmw_present_ioctl(struct drm_device *dev, void *data,
extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-/**
+/*
* Fifo utilities - vmwgfx_fifo.c
*/
@@ -880,9 +893,11 @@ extern int vmw_cmd_flush(struct vmw_private *dev_priv,
/**
- * vmw_fifo_caps - Returns the capabilities of the FIFO command
+ * vmw_fifo_caps - Get the capabilities of the FIFO command
* queue or 0 if fifo memory isn't present.
* @dev_priv: The device private context
+ *
+ * Returns: capabilities of the FIFO command or %0 if fifo memory not present
*/
static inline uint32_t vmw_fifo_caps(const struct vmw_private *dev_priv)
{
@@ -893,9 +908,11 @@ static inline uint32_t vmw_fifo_caps(const struct vmw_private *dev_priv)
/**
- * vmw_is_cursor_bypass3_enabled - Returns TRUE iff Cursor Bypass 3
- * is enabled in the FIFO.
+ * vmw_is_cursor_bypass3_enabled - check Cursor Bypass 3 enabled setting
+ * in the FIFO.
* @dev_priv: The device private context
+ *
+ * Returns: %true iff Cursor Bypass 3 is enabled in the FIFO
*/
static inline bool
vmw_is_cursor_bypass3_enabled(const struct vmw_private *dev_priv)
@@ -903,7 +920,7 @@ vmw_is_cursor_bypass3_enabled(const struct vmw_private *dev_priv)
return (vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_CURSOR_BYPASS_3) != 0;
}
-/**
+/*
* TTM buffer object driver - vmwgfx_ttm_buffer.c
*/
@@ -927,7 +944,7 @@ extern void vmw_piter_start(struct vmw_piter *viter,
*
* @viter: Pointer to the iterator to advance.
*
- * Returns false if past the list of pages, true otherwise.
+ * Returns: false if past the list of pages, true otherwise.
*/
static inline bool vmw_piter_next(struct vmw_piter *viter)
{
@@ -939,7 +956,7 @@ static inline bool vmw_piter_next(struct vmw_piter *viter)
*
* @viter: Pointer to the iterator
*
- * Returns the DMA address of the page pointed to by @viter.
+ * Returns: the DMA address of the page pointed to by @viter.
*/
static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter)
{
@@ -951,14 +968,14 @@ static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter)
*
* @viter: Pointer to the iterator
*
- * Returns the DMA address of the page pointed to by @viter.
+ * Returns: the DMA address of the page pointed to by @viter.
*/
static inline struct page *vmw_piter_page(struct vmw_piter *viter)
{
return viter->pages[viter->i];
}
-/**
+/*
* Command submission - vmwgfx_execbuf.c
*/
@@ -993,7 +1010,7 @@ extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
int32_t out_fence_fd);
bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
-/**
+/*
* IRQs and wating - vmwgfx_irq.c
*/
@@ -1016,7 +1033,7 @@ bool vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag,
bool vmw_generic_waiter_remove(struct vmw_private *dev_priv,
u32 flag, int *waiter_count);
-/**
+/*
* Kernel modesetting - vmwgfx_kms.c
*/
@@ -1048,7 +1065,7 @@ extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
extern void vmw_resource_unpin(struct vmw_resource *res);
extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
-/**
+/*
* Overlay control - vmwgfx_overlay.c
*/
@@ -1063,20 +1080,20 @@ int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
-/**
+/*
* GMR Id manager
*/
int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type);
void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type);
-/**
+/*
* System memory manager
*/
int vmw_sys_man_init(struct vmw_private *dev_priv);
void vmw_sys_man_fini(struct vmw_private *dev_priv);
-/**
+/*
* Prime - vmwgfx_prime.c
*/
@@ -1292,7 +1309,7 @@ extern void vmw_cmdbuf_irqthread(struct vmw_cmdbuf_man *man);
* @line: The current line of the blit.
* @line_offset: Offset of the current line segment.
* @cpp: Bytes per pixel (granularity information).
- * @memcpy: Which memcpy function to use.
+ * @do_cpy: Which memcpy function to use.
*/
struct vmw_diff_cpy {
struct drm_rect rect;
@@ -1380,13 +1397,14 @@ vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf);
/**
* VMW_DEBUG_KMS - Debug output for kernel mode-setting
+ * @fmt: format string for the args
*
* This macro is for debugging vmwgfx mode-setting code.
*/
#define VMW_DEBUG_KMS(fmt, ...) \
DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__)
-/**
+/*
* Inline helper functions
*/
@@ -1417,11 +1435,13 @@ static inline void vmw_fifo_resource_dec(struct vmw_private *dev_priv)
/**
* vmw_fifo_mem_read - Perform a MMIO read from the fifo memory
- *
+ * @vmw: The device private structure
* @fifo_reg: The fifo register to read from
*
* This function is intended to be equivalent to ioread32() on
* memremap'd memory, but without byteswapping.
+ *
+ * Returns: the value read
*/
static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg)
{
@@ -1431,8 +1451,9 @@ static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg)
/**
* vmw_fifo_mem_write - Perform a MMIO write to volatile memory
- *
- * @addr: The fifo register to write to
+ * @vmw: The device private structure
+ * @fifo_reg: The fifo register to write to
+ * @value: The value to write
*
* This function is intended to be equivalent to iowrite32 on
* memremap'd memory, but without byteswapping.
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 55730e29d3ae..e7bddf840a79 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -771,7 +771,8 @@ err_out:
ret = vmw_bo_dirty_add(bo);
if (!ret && surface && surface->res.func->dirty_alloc) {
surface->res.coherent = true;
- ret = surface->res.func->dirty_alloc(&surface->res);
+ if (surface->res.dirty == NULL)
+ ret = surface->res.func->dirty_alloc(&surface->res);
}
ttm_bo_unreserve(&bo->tbo);
}
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index f3d15994ca1e..50c7b45c59e3 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -444,6 +444,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
(u64)(long)ctx,
true); /* prevent infinite recursions */
+ if (ret > size)
+ ret = size;
if (ret > 0)
memcpy(buf, dma_data, ret);
diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
index a1db3b3d0667..0fdc0968b9ef 100644
--- a/drivers/hid/hid-appletb-kbd.c
+++ b/drivers/hid/hid-appletb-kbd.c
@@ -476,7 +476,7 @@ static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
return 0;
}
-static int appletb_kbd_reset_resume(struct hid_device *hdev)
+static int appletb_kbd_resume(struct hid_device *hdev)
{
struct appletb_kbd *kbd = hid_get_drvdata(hdev);
@@ -500,7 +500,8 @@ static struct hid_driver appletb_kbd_hid_driver = {
.event = appletb_kbd_hid_event,
.input_configured = appletb_kbd_input_configured,
.suspend = pm_ptr(appletb_kbd_suspend),
- .reset_resume = pm_ptr(appletb_kbd_reset_resume),
+ .resume = pm_ptr(appletb_kbd_resume),
+ .reset_resume = pm_ptr(appletb_kbd_resume),
.driver.dev_groups = appletb_kbd_groups,
};
module_hid_driver(appletb_kbd_hid_driver);
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 687b785e2d0c..bc93b27f9b13 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1498,6 +1498,9 @@ static const struct hid_device_id asus_devices[] = {
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_XGM_2022),
+ },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_XGM_2023),
},
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 840a60113868..833df14ef68f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2057,9 +2057,10 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
rsize = max_buffer_size;
if (csize < rsize) {
- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
- csize, rsize);
- memset(cdata + csize, 0, rsize - csize);
+ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
+ report->id, rsize, csize);
+ ret = -EINVAL;
+ goto out;
}
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4ab7640b119a..afcee13bad61 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -229,6 +229,7 @@
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c
#define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
+#define USB_DEVICE_ID_ASUSTEK_XGM_2022 0x1970
#define USB_DEVICE_ID_ASUSTEK_XGM_2023 0x1a9a
#define USB_VENDOR_ID_ATEN 0x0557
@@ -454,8 +455,6 @@
#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
#define USB_DEVICE_ID_HP_X2 0x074d
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
-#define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
-#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
#define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81
#define USB_VENDOR_ID_ELECOM 0x056e
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d5308adb2894..9475b7e9da43 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -354,6 +354,7 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
#define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */
+#define HID_BATTERY_QUIRK_DYNAMIC (1 << 4) /* report present only after life signs */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -386,10 +387,6 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
HID_BATTERY_QUIRK_IGNORE },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
- HID_BATTERY_QUIRK_IGNORE },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
- HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
@@ -402,8 +399,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
* Elan HID touchscreens seem to all report a non present battery,
* set HID_BATTERY_QUIRK_IGNORE for all Elan I2C and USB HID devices.
*/
- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
{}
};
@@ -460,11 +457,14 @@ static int hidinput_get_battery_property(struct power_supply *psy,
int ret = 0;
switch (prop) {
- case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 1;
break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = dev->battery_present;
+ break;
+
case POWER_SUPPLY_PROP_CAPACITY:
if (dev->battery_status != HID_BATTERY_REPORTED &&
!dev->battery_avoid_query) {
@@ -577,6 +577,8 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
dev->battery_avoid_query = true;
+ dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
+
dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
if (IS_ERR(dev->battery)) {
error = PTR_ERR(dev->battery);
@@ -632,6 +634,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
return;
if (hidinput_update_battery_charge_status(dev, usage, value)) {
+ dev->battery_present = true;
power_supply_changed(dev->battery);
return;
}
@@ -647,6 +650,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
if (dev->battery_status != HID_BATTERY_REPORTED ||
capacity != dev->battery_capacity ||
ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
+ dev->battery_present = true;
dev->battery_capacity = capacity;
dev->battery_status = HID_BATTERY_REPORTED;
dev->battery_ratelimit_time =
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index d40932809ce1..d1dea7297712 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4487,10 +4487,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!ret)
ret = hidpp_ff_init(hidpp, &data);
- if (ret)
+ if (ret) {
hid_warn(hidpp->hid_dev,
"Unable to initialize force feedback support, errno %d\n",
ret);
+ ret = 0;
+ }
}
/*
@@ -4668,6 +4670,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
{ /* Slim Solar+ K980 Keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
+ { /* MX Master 4 mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
{}
};
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index b8a748bbf0fd..e82a3c4e5b44 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -526,12 +526,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
report->id);
} else {
+ /* The report ID in the request and the response should match */
+ if (report->id != buf[0]) {
+ hid_err(hdev, "Returned feature report did not match the request\n");
+ goto free;
+ }
+
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
size, 0);
if (ret)
dev_warn(&hdev->dev, "failed to report feature\n");
}
+free:
kfree(buf);
}
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
index f9fcb398673b..8075992e8732 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
@@ -127,6 +127,7 @@ int quicki2c_hid_probe(struct quicki2c_device *qcdev)
hid->product = le16_to_cpu(qcdev->dev_desc.product_id);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quicki2c-hid",
hid->vendor, hid->product);
+ strscpy(hid->phys, dev_name(qcdev->dev), sizeof(hid->phys));
ret = hid_add_device(hid);
if (ret) {
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
index 82c72bfa2795..91d5807b4a83 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
@@ -118,6 +118,7 @@ int quickspi_hid_probe(struct quickspi_device *qsdev)
hid->product = le16_to_cpu(qsdev->dev_desc.product_id);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quickspi-hid",
hid->vendor, hid->product);
+ strscpy(hid->phys, dev_name(qsdev->dev), sizeof(hid->phys));
ret = hid_add_device(hid);
if (ret) {
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 9b2c710f8da1..da1f0ea85625 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1208,10 +1208,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
switch (data[0]) {
case 0x04:
+ if (len < 32) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x04 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
fallthrough;
case 0x03:
+ if (i == 1 && len < 22) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x03 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
wacom_intuos_bt_process_data(wacom, data + i);
diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index c28aac0726de..fdffd4f002f6 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -314,15 +314,17 @@ int mshv_region_pin(struct mshv_mem_region *region)
ret = pin_user_pages_fast(userspace_addr, nr_pages,
FOLL_WRITE | FOLL_LONGTERM,
pages);
- if (ret < 0)
+ if (ret != nr_pages)
goto release_pages;
}
return 0;
release_pages:
+ if (ret > 0)
+ done_count += ret;
mshv_region_invalidate_pages(region, 0, done_count);
- return ret;
+ return ret < 0 ? ret : -ENOMEM;
}
static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 04c2a1910a8a..826798f1a8ec 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -190,7 +190,6 @@ struct hv_synic_pages {
};
struct mshv_root {
- struct hv_synic_pages __percpu *synic_pages;
spinlock_t pt_ht_lock;
DECLARE_HASHTABLE(pt_htable, MSHV_PARTITIONS_HASH_BITS);
struct hv_partition_property_vmm_capabilities vmm_caps;
@@ -249,8 +248,8 @@ int mshv_register_doorbell(u64 partition_id, doorbell_cb_t doorbell_cb,
void mshv_unregister_doorbell(u64 partition_id, int doorbell_portid);
void mshv_isr(void);
-int mshv_synic_init(unsigned int cpu);
-int mshv_synic_cleanup(unsigned int cpu);
+int mshv_synic_init(struct device *dev);
+void mshv_synic_exit(void);
static inline bool mshv_partition_encrypted(struct mshv_partition *partition)
{
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 82ff823ef0ca..6f42423f7faa 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -120,7 +120,6 @@ static u16 mshv_passthru_hvcalls[] = {
HVCALL_SET_VP_REGISTERS,
HVCALL_TRANSLATE_VIRTUAL_ADDRESS,
HVCALL_CLEAR_VIRTUAL_INTERRUPT,
- HVCALL_SCRUB_PARTITION,
HVCALL_REGISTER_INTERCEPT_RESULT,
HVCALL_ASSERT_VIRTUAL_INTERRUPT,
HVCALL_GET_GPA_PAGES_ACCESS_STATES,
@@ -1289,7 +1288,7 @@ err_out:
*/
static long
mshv_map_user_memory(struct mshv_partition *partition,
- struct mshv_user_mem_region mem)
+ struct mshv_user_mem_region *mem)
{
struct mshv_mem_region *region;
struct vm_area_struct *vma;
@@ -1297,12 +1296,12 @@ mshv_map_user_memory(struct mshv_partition *partition,
ulong mmio_pfn;
long ret;
- if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
- !access_ok((const void __user *)mem.userspace_addr, mem.size))
+ if (mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
+ !access_ok((const void __user *)mem->userspace_addr, mem->size))
return -EINVAL;
mmap_read_lock(current->mm);
- vma = vma_lookup(current->mm, mem.userspace_addr);
+ vma = vma_lookup(current->mm, mem->userspace_addr);
is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0;
mmio_pfn = is_mmio ? vma->vm_pgoff : 0;
mmap_read_unlock(current->mm);
@@ -1310,7 +1309,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
if (!vma)
return -EINVAL;
- ret = mshv_partition_create_region(partition, &mem, &region,
+ ret = mshv_partition_create_region(partition, mem, &region,
is_mmio);
if (ret)
return ret;
@@ -1348,32 +1347,32 @@ mshv_map_user_memory(struct mshv_partition *partition,
return 0;
errout:
- vfree(region);
+ mshv_region_put(region);
return ret;
}
/* Called for unmapping both the guest ram and the mmio space */
static long
mshv_unmap_user_memory(struct mshv_partition *partition,
- struct mshv_user_mem_region mem)
+ struct mshv_user_mem_region *mem)
{
struct mshv_mem_region *region;
- if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
+ if (!(mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
return -EINVAL;
spin_lock(&partition->pt_mem_regions_lock);
- region = mshv_partition_region_by_gfn(partition, mem.guest_pfn);
+ region = mshv_partition_region_by_gfn(partition, mem->guest_pfn);
if (!region) {
spin_unlock(&partition->pt_mem_regions_lock);
return -ENOENT;
}
/* Paranoia check */
- if (region->start_uaddr != mem.userspace_addr ||
- region->start_gfn != mem.guest_pfn ||
- region->nr_pages != HVPFN_DOWN(mem.size)) {
+ if (region->start_uaddr != mem->userspace_addr ||
+ region->start_gfn != mem->guest_pfn ||
+ region->nr_pages != HVPFN_DOWN(mem->size)) {
spin_unlock(&partition->pt_mem_regions_lock);
return -EINVAL;
}
@@ -1404,9 +1403,9 @@ mshv_partition_ioctl_set_memory(struct mshv_partition *partition,
return -EINVAL;
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))
- return mshv_unmap_user_memory(partition, mem);
+ return mshv_unmap_user_memory(partition, &mem);
- return mshv_map_user_memory(partition, mem);
+ return mshv_map_user_memory(partition, &mem);
}
static long
@@ -2064,7 +2063,6 @@ mshv_dev_release(struct inode *inode, struct file *filp)
return 0;
}
-static int mshv_cpuhp_online;
static int mshv_root_sched_online;
static const char *scheduler_type_to_string(enum hv_scheduler_type type)
@@ -2249,27 +2247,6 @@ root_scheduler_deinit(void)
free_percpu(root_scheduler_output);
}
-static int mshv_reboot_notify(struct notifier_block *nb,
- unsigned long code, void *unused)
-{
- cpuhp_remove_state(mshv_cpuhp_online);
- return 0;
-}
-
-struct notifier_block mshv_reboot_nb = {
- .notifier_call = mshv_reboot_notify,
-};
-
-static void mshv_root_partition_exit(void)
-{
- unregister_reboot_notifier(&mshv_reboot_nb);
-}
-
-static int __init mshv_root_partition_init(struct device *dev)
-{
- return register_reboot_notifier(&mshv_reboot_nb);
-}
-
static int __init mshv_init_vmm_caps(struct device *dev)
{
int ret;
@@ -2314,39 +2291,21 @@ static int __init mshv_parent_partition_init(void)
MSHV_HV_MAX_VERSION);
}
- mshv_root.synic_pages = alloc_percpu(struct hv_synic_pages);
- if (!mshv_root.synic_pages) {
- dev_err(dev, "Failed to allocate percpu synic page\n");
- ret = -ENOMEM;
+ ret = mshv_synic_init(dev);
+ if (ret)
goto device_deregister;
- }
-
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
- mshv_synic_init,
- mshv_synic_cleanup);
- if (ret < 0) {
- dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
- goto free_synic_pages;
- }
-
- mshv_cpuhp_online = ret;
ret = mshv_init_vmm_caps(dev);
if (ret)
- goto remove_cpu_state;
+ goto synic_cleanup;
ret = mshv_retrieve_scheduler_type(dev);
if (ret)
- goto remove_cpu_state;
-
- if (hv_root_partition())
- ret = mshv_root_partition_init(dev);
- if (ret)
- goto remove_cpu_state;
+ goto synic_cleanup;
ret = root_scheduler_init(dev);
if (ret)
- goto exit_partition;
+ goto synic_cleanup;
ret = mshv_debugfs_init();
if (ret)
@@ -2367,13 +2326,8 @@ exit_debugfs:
mshv_debugfs_exit();
deinit_root_scheduler:
root_scheduler_deinit();
-exit_partition:
- if (hv_root_partition())
- mshv_root_partition_exit();
-remove_cpu_state:
- cpuhp_remove_state(mshv_cpuhp_online);
-free_synic_pages:
- free_percpu(mshv_root.synic_pages);
+synic_cleanup:
+ mshv_synic_exit();
device_deregister:
misc_deregister(&mshv_dev);
return ret;
@@ -2387,10 +2341,7 @@ static void __exit mshv_parent_partition_exit(void)
misc_deregister(&mshv_dev);
mshv_irqfd_wq_cleanup();
root_scheduler_deinit();
- if (hv_root_partition())
- mshv_root_partition_exit();
- cpuhp_remove_state(mshv_cpuhp_online);
- free_percpu(mshv_root.synic_pages);
+ mshv_synic_exit();
}
module_init(mshv_parent_partition_init);
diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index 216065e21d28..43f1bcbbf2d3 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -10,13 +10,22 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/random.h>
+#include <linux/cpuhotplug.h>
+#include <linux/reboot.h>
#include <asm/mshyperv.h>
+#include <linux/acpi.h>
#include "mshv_eventfd.h"
#include "mshv.h"
+static int synic_cpuhp_online;
+static struct hv_synic_pages __percpu *synic_pages;
+static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */
+static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */
+
static u32 synic_event_ring_get_queued_port(u32 sint_index)
{
struct hv_synic_event_ring_page **event_ring_page;
@@ -26,7 +35,7 @@ static u32 synic_event_ring_get_queued_port(u32 sint_index)
u32 message;
u8 tail;
- spages = this_cpu_ptr(mshv_root.synic_pages);
+ spages = this_cpu_ptr(synic_pages);
event_ring_page = &spages->synic_event_ring_page;
synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail);
@@ -393,7 +402,7 @@ unlock_out:
void mshv_isr(void)
{
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_message *msg;
bool handled;
@@ -437,25 +446,21 @@ void mshv_isr(void)
if (msg->header.message_flags.msg_pending)
hv_set_non_nested_msr(HV_MSR_EOM, 0);
-#ifdef HYPERVISOR_CALLBACK_VECTOR
- add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR);
-#endif
+ add_interrupt_randomness(mshv_sint_vector);
} else {
pr_warn_once("%s: unknown message type 0x%x\n", __func__,
msg->header.message_type);
}
}
-int mshv_synic_init(unsigned int cpu)
+static int mshv_synic_cpu_init(unsigned int cpu)
{
union hv_synic_simp simp;
union hv_synic_siefp siefp;
union hv_synic_sirbp sirbp;
-#ifdef HYPERVISOR_CALLBACK_VECTOR
union hv_synic_sint sint;
-#endif
union hv_synic_scontrol sctrl;
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_synic_event_flags_page **event_flags_page =
&spages->synic_event_flags_page;
@@ -496,10 +501,12 @@ int mshv_synic_init(unsigned int cpu)
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
-#ifdef HYPERVISOR_CALLBACK_VECTOR
+ if (mshv_sint_irq != -1)
+ enable_percpu_irq(mshv_sint_irq, 0);
+
/* Enable intercepts */
sint.as_uint64 = 0;
- sint.vector = HYPERVISOR_CALLBACK_VECTOR;
+ sint.vector = mshv_sint_vector;
sint.masked = false;
sint.auto_eoi = hv_recommend_using_aeoi();
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
@@ -507,13 +514,12 @@ int mshv_synic_init(unsigned int cpu)
/* Doorbell SINT */
sint.as_uint64 = 0;
- sint.vector = HYPERVISOR_CALLBACK_VECTOR;
+ sint.vector = mshv_sint_vector;
sint.masked = false;
sint.as_intercept = 1;
sint.auto_eoi = hv_recommend_using_aeoi();
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
sint.as_uint64);
-#endif
/* Enable global synic bit */
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
@@ -542,14 +548,14 @@ cleanup:
return -EFAULT;
}
-int mshv_synic_cleanup(unsigned int cpu)
+static int mshv_synic_cpu_exit(unsigned int cpu)
{
union hv_synic_sint sint;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
union hv_synic_sirbp sirbp;
union hv_synic_scontrol sctrl;
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_synic_event_flags_page **event_flags_page =
&spages->synic_event_flags_page;
@@ -568,6 +574,9 @@ int mshv_synic_cleanup(unsigned int cpu)
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
sint.as_uint64);
+ if (mshv_sint_irq != -1)
+ disable_percpu_irq(mshv_sint_irq);
+
/* Disable Synic's event ring page */
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
sirbp.sirbp_enabled = false;
@@ -663,3 +672,152 @@ mshv_unregister_doorbell(u64 partition_id, int doorbell_portid)
mshv_portid_free(doorbell_portid);
}
+
+static int mshv_synic_reboot_notify(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+ if (!hv_root_partition())
+ return 0;
+
+ cpuhp_remove_state(synic_cpuhp_online);
+ return 0;
+}
+
+static struct notifier_block mshv_synic_reboot_nb = {
+ .notifier_call = mshv_synic_reboot_notify,
+};
+
+#ifndef HYPERVISOR_CALLBACK_VECTOR
+static DEFINE_PER_CPU(long, mshv_evt);
+
+static irqreturn_t mshv_percpu_isr(int irq, void *dev_id)
+{
+ mshv_isr();
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_ACPI
+static int __init mshv_acpi_setup_sint_irq(void)
+{
+ return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE,
+ ACPI_ACTIVE_HIGH);
+}
+
+static void mshv_acpi_cleanup_sint_irq(void)
+{
+ acpi_unregister_gsi(mshv_sint_vector);
+}
+#else
+static int __init mshv_acpi_setup_sint_irq(void)
+{
+ return -ENODEV;
+}
+
+static void mshv_acpi_cleanup_sint_irq(void)
+{
+}
+#endif
+
+static int __init mshv_sint_vector_setup(void)
+{
+ int ret;
+ struct hv_register_assoc reg = {
+ .name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID,
+ };
+ union hv_input_vtl input_vtl = { 0 };
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
+ 1, input_vtl, &reg);
+ if (ret || !reg.value.reg64)
+ return -ENODEV;
+
+ mshv_sint_vector = reg.value.reg64;
+ ret = mshv_acpi_setup_sint_irq();
+ if (ret < 0) {
+ pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n",
+ mshv_sint_vector, ret);
+ goto out_fail;
+ }
+
+ mshv_sint_irq = ret;
+
+ ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV",
+ &mshv_evt);
+ if (ret)
+ goto out_unregister;
+
+ return 0;
+
+out_unregister:
+ mshv_acpi_cleanup_sint_irq();
+out_fail:
+ return ret;
+}
+
+static void mshv_sint_vector_cleanup(void)
+{
+ free_percpu_irq(mshv_sint_irq, &mshv_evt);
+ mshv_acpi_cleanup_sint_irq();
+}
+#else /* !HYPERVISOR_CALLBACK_VECTOR */
+static int __init mshv_sint_vector_setup(void)
+{
+ mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR;
+ return 0;
+}
+
+static void mshv_sint_vector_cleanup(void)
+{
+}
+#endif /* HYPERVISOR_CALLBACK_VECTOR */
+
+int __init mshv_synic_init(struct device *dev)
+{
+ int ret = 0;
+
+ ret = mshv_sint_vector_setup();
+ if (ret)
+ return ret;
+
+ synic_pages = alloc_percpu(struct hv_synic_pages);
+ if (!synic_pages) {
+ dev_err(dev, "Failed to allocate percpu synic page\n");
+ ret = -ENOMEM;
+ goto sint_vector_cleanup;
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
+ mshv_synic_cpu_init,
+ mshv_synic_cpu_exit);
+ if (ret < 0) {
+ dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
+ goto free_synic_pages;
+ }
+
+ synic_cpuhp_online = ret;
+
+ ret = register_reboot_notifier(&mshv_synic_reboot_nb);
+ if (ret)
+ goto remove_cpuhp_state;
+
+ return 0;
+
+remove_cpuhp_state:
+ cpuhp_remove_state(synic_cpuhp_online);
+free_synic_pages:
+ free_percpu(synic_pages);
+sint_vector_cleanup:
+ mshv_sint_vector_cleanup();
+ return ret;
+}
+
+void mshv_synic_exit(void)
+{
+ unregister_reboot_notifier(&mshv_synic_reboot_nb);
+ cpuhp_remove_state(synic_cpuhp_online);
+ free_percpu(synic_pages);
+ mshv_sint_vector_cleanup();
+}
diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c
index 8b2c965480e3..7888afe8dafd 100644
--- a/drivers/hwmon/adm1177.c
+++ b/drivers/hwmon/adm1177.c
@@ -10,6 +10,8 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
@@ -33,7 +35,7 @@
struct adm1177_state {
struct i2c_client *client;
u32 r_sense_uohm;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
bool vrange_high;
};
@@ -48,7 +50,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
}
static int adm1177_write_alert_thr(struct adm1177_state *st,
- u32 alert_threshold_ua)
+ u64 alert_threshold_ua)
{
u64 val;
int ret;
@@ -91,8 +93,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
*val = div_u64((105840000ull * dummy),
4096 * st->r_sense_uohm);
return 0;
- case hwmon_curr_max_alarm:
- *val = st->alert_threshold_ua;
+ case hwmon_curr_max:
+ *val = div_u64(st->alert_threshold_ua, 1000);
return 0;
default:
return -EOPNOTSUPP;
@@ -126,9 +128,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
switch (type) {
case hwmon_curr:
switch (attr) {
- case hwmon_curr_max_alarm:
- adm1177_write_alert_thr(st, val);
- return 0;
+ case hwmon_curr_max:
+ val = clamp_val(val, 0,
+ div_u64(105840000ULL, st->r_sense_uohm));
+ return adm1177_write_alert_thr(st, (u64)val * 1000);
default:
return -EOPNOTSUPP;
}
@@ -156,7 +159,7 @@ static umode_t adm1177_is_visible(const void *data,
if (st->r_sense_uohm)
return 0444;
return 0;
- case hwmon_curr_max_alarm:
+ case hwmon_curr_max:
if (st->r_sense_uohm)
return 0644;
return 0;
@@ -170,7 +173,7 @@ static umode_t adm1177_is_visible(const void *data,
static const struct hwmon_channel_info * const adm1177_info[] = {
HWMON_CHANNEL_INFO(curr,
- HWMON_C_INPUT | HWMON_C_MAX_ALARM),
+ HWMON_C_INPUT | HWMON_C_MAX),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT),
NULL
@@ -192,7 +195,8 @@ static int adm1177_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm1177_state *st;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
+ u32 prop;
int ret;
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
@@ -208,22 +212,26 @@ static int adm1177_probe(struct i2c_client *client)
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&st->r_sense_uohm))
st->r_sense_uohm = 0;
- if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
- &alert_threshold_ua)) {
- if (st->r_sense_uohm)
- /*
- * set maximum default value from datasheet based on
- * shunt-resistor
- */
- alert_threshold_ua = div_u64(105840000000,
- st->r_sense_uohm);
- else
- alert_threshold_ua = 0;
+ if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
+ &prop)) {
+ alert_threshold_ua = prop;
+ } else if (st->r_sense_uohm) {
+ /*
+ * set maximum default value from datasheet based on
+ * shunt-resistor
+ */
+ alert_threshold_ua = div_u64(105840000000ULL,
+ st->r_sense_uohm);
+ } else {
+ alert_threshold_ua = 0;
}
st->vrange_high = device_property_read_bool(dev,
"adi,vrange-high-enable");
- if (alert_threshold_ua && st->r_sense_uohm)
- adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (alert_threshold_ua && st->r_sense_uohm) {
+ ret = adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (ret)
+ return ret;
+ }
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
ADM1177_CMD_I_CONT |
diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c
index b7bb325c3ad9..01590dfa55e6 100644
--- a/drivers/hwmon/axi-fan-control.c
+++ b/drivers/hwmon/axi-fan-control.c
@@ -507,7 +507,7 @@ static int axi_fan_control_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL,
axi_fan_control_irq_handler,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
- pdev->driver_override, ctl);
+ NULL, ctl);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to request an irq\n");
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 9a3c515efe2e..163d31f17bd4 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -232,7 +232,7 @@ static int max6639_read_fan(struct device *dev, u32 attr, int channel,
static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
{
/* Decrement the PPR value and shift left by 6 to match the register format */
- return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
+ return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), --ppr << 6);
}
static int max6639_write_fan(struct device *dev, u32 attr, int channel,
@@ -524,8 +524,8 @@ static int max6639_probe_child_from_dt(struct i2c_client *client,
{
struct device *dev = &client->dev;
- u32 i;
- int err, val;
+ u32 i, val;
+ int err;
err = of_property_read_u32(child, "reg", &i);
if (err) {
@@ -540,8 +540,8 @@ static int max6639_probe_child_from_dt(struct i2c_client *client,
err = of_property_read_u32(child, "pulses-per-revolution", &val);
if (!err) {
- if (val < 1 || val > 5) {
- dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child);
+ if (val < 1 || val > 4) {
+ dev_err(dev, "invalid pulses-per-revolution %u of %pOFn\n", val, child);
return -EINVAL;
}
data->ppr[i] = val;
diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c
index b2fc936851e1..457089c561b4 100644
--- a/drivers/hwmon/peci/cputemp.c
+++ b/drivers/hwmon/peci/cputemp.c
@@ -131,7 +131,7 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type
*val = priv->temp.target.tjmax;
break;
case crit_hyst_type:
- *val = priv->temp.target.tjmax - priv->temp.target.tcontrol;
+ *val = priv->temp.target.tcontrol;
break;
default:
ret = -EOPNOTSUPP;
@@ -319,7 +319,7 @@ static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type
{
const struct peci_cputemp *priv = data;
- if (channel > CPUTEMP_CHANNEL_NUMS)
+ if (channel >= CPUTEMP_CHANNEL_NUMS)
return 0;
if (channel < channel_core)
diff --git a/drivers/hwmon/pmbus/hac300s.c b/drivers/hwmon/pmbus/hac300s.c
index 0a1d52cae91e..a073db1cfe2e 100644
--- a/drivers/hwmon/pmbus/hac300s.c
+++ b/drivers/hwmon/pmbus/hac300s.c
@@ -58,6 +58,8 @@ static int hac300s_read_word_data(struct i2c_client *client, int page,
case PMBUS_MFR_VOUT_MIN:
case PMBUS_READ_VOUT:
rv = pmbus_read_word_data(client, page, phase, reg);
+ if (rv < 0)
+ return rv;
return FIELD_GET(LINEAR11_MANTISSA_MASK, rv);
default:
return -ENODATA;
diff --git a/drivers/hwmon/pmbus/ina233.c b/drivers/hwmon/pmbus/ina233.c
index dde1e1678394..7aebd854763a 100644
--- a/drivers/hwmon/pmbus/ina233.c
+++ b/drivers/hwmon/pmbus/ina233.c
@@ -67,10 +67,13 @@ static int ina233_read_word_data(struct i2c_client *client, int page,
switch (reg) {
case PMBUS_VIRT_READ_VMON:
ret = pmbus_read_word_data(client, 0, 0xff, MFR_READ_VSHUNT);
+ if (ret < 0)
+ return ret;
/* Adjust returned value to match VIN coefficients */
/* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
- ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
+ ret = clamp_val(DIV_ROUND_CLOSEST((s16)ret * 25, 12500),
+ S16_MIN, S16_MAX) & 0xffff;
break;
default:
ret = -ENODATA;
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c
index 97b61836f53a..3e3a887aad05 100644
--- a/drivers/hwmon/pmbus/isl68137.c
+++ b/drivers/hwmon/pmbus/isl68137.c
@@ -96,10 +96,21 @@ static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
int page,
char *buf)
{
- int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+ int val;
- return sprintf(buf, "%d\n",
- (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0);
+ val = pmbus_lock_interruptible(client);
+ if (val)
+ return val;
+
+ val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+
+ pmbus_unlock(client);
+
+ if (val < 0)
+ return val;
+
+ return sysfs_emit(buf, "%d\n",
+ (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS);
}
static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
@@ -115,6 +126,10 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
op_val = result ? ISL68137_VOUT_AVS : 0;
+ rc = pmbus_lock_interruptible(client);
+ if (rc)
+ return rc;
+
/*
* Writes to VOUT setpoint over AVSBus will persist after the VRM is
* switched to PMBus control. Switching back to AVSBus control
@@ -126,17 +141,20 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
rc = pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_COMMAND);
if (rc < 0)
- return rc;
+ goto unlock;
rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND,
rc);
if (rc < 0)
- return rc;
+ goto unlock;
}
rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
ISL68137_VOUT_AVS, op_val);
+unlock:
+ pmbus_unlock(client);
+
return (rc < 0) ? rc : count;
}
diff --git a/drivers/hwmon/pmbus/mp2869.c b/drivers/hwmon/pmbus/mp2869.c
index cc69a1e91dfe..4647892e5112 100644
--- a/drivers/hwmon/pmbus/mp2869.c
+++ b/drivers/hwmon/pmbus/mp2869.c
@@ -165,7 +165,7 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct mp2869_data *data = to_mp2869_data(info);
- int ret;
+ int ret, mfr;
switch (reg) {
case PMBUS_VOUT_MODE:
@@ -188,11 +188,14 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(2, 2)) |
FIELD_PREP(GENMASK(2, 2),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
case PMBUS_STATUS_TEMPERATURE:
/*
@@ -207,15 +210,16 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(7, 6)) |
FIELD_PREP(GENMASK(6, 6),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC))) |
+ FIELD_GET(GENMASK(1, 1), mfr)) |
FIELD_PREP(GENMASK(7, 7),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
default:
ret = -ENODATA;
@@ -230,7 +234,7 @@ static int mp2869_read_word_data(struct i2c_client *client, int page, int phase,
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct mp2869_data *data = to_mp2869_data(info);
- int ret;
+ int ret, mfr;
switch (reg) {
case PMBUS_STATUS_WORD:
@@ -246,11 +250,14 @@ static int mp2869_read_word_data(struct i2c_client *client, int page, int phase,
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(2, 2)) |
FIELD_PREP(GENMASK(2, 2),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
case PMBUS_READ_VIN:
/*
diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index c31982d85196..d0bc47b12cb0 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -313,6 +313,8 @@ static int mp2973_read_word_data(struct i2c_client *client, int page,
case PMBUS_STATUS_WORD:
/* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */
ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
ret ^= PB_STATUS_POWER_GOOD_N;
break;
case PMBUS_OT_FAULT_LIMIT:
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index be6d05def115..572be3ebc03d 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -6,6 +6,7 @@
* Copyright (c) 2012 Guenter Roeck
*/
+#include <linux/atomic.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dcache.h>
@@ -21,8 +22,8 @@
#include <linux/pmbus.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/of.h>
#include <linux/thermal.h>
+#include <linux/workqueue.h>
#include "pmbus.h"
/*
@@ -112,6 +113,11 @@ struct pmbus_data {
struct mutex update_lock;
+#if IS_ENABLED(CONFIG_REGULATOR)
+ atomic_t regulator_events[PMBUS_PAGES];
+ struct work_struct regulator_notify_work;
+#endif
+
bool has_status_word; /* device uses STATUS_WORD register */
int (*read_status)(struct i2c_client *client, int page);
@@ -1209,6 +1215,12 @@ static ssize_t pmbus_show_boolean(struct device *dev,
return sysfs_emit(buf, "%d\n", val);
}
+static ssize_t pmbus_show_zero(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sysfs_emit(buf, "0\n");
+}
+
static ssize_t pmbus_show_sensor(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -1407,7 +1419,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
int reg,
enum pmbus_sensor_classes class,
bool update, bool readonly,
- bool convert)
+ bool writeonly, bool convert)
{
struct pmbus_sensor *sensor;
struct device_attribute *a;
@@ -1436,7 +1448,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
sensor->data = -ENODATA;
pmbus_dev_attr_init(a, sensor->name,
readonly ? 0444 : 0644,
- pmbus_show_sensor, pmbus_set_sensor);
+ writeonly ? pmbus_show_zero : pmbus_show_sensor,
+ pmbus_set_sensor);
if (pmbus_add_attribute(data, &a->attr))
return NULL;
@@ -1495,8 +1508,10 @@ static int pmbus_add_label(struct pmbus_data *data,
struct pmbus_limit_attr {
u16 reg; /* Limit register */
u16 sbit; /* Alarm attribute status bit */
- bool update; /* True if register needs updates */
- bool low; /* True if low limit; for limits with compare functions only */
+ bool readonly:1; /* True if the attribute is read-only */
+ bool writeonly:1; /* True if the attribute is write-only */
+ bool update:1; /* True if register needs updates */
+ bool low:1; /* True if low limit; for limits with compare functions only */
const char *attr; /* Attribute name */
const char *alarm; /* Alarm attribute name */
};
@@ -1511,9 +1526,9 @@ struct pmbus_sensor_attr {
u8 nlimit; /* # of limit registers */
enum pmbus_sensor_classes class;/* sensor class */
const char *label; /* sensor label */
- bool paged; /* true if paged sensor */
- bool update; /* true if update needed */
- bool compare; /* true if compare function needed */
+ bool paged:1; /* true if paged sensor */
+ bool update:1; /* true if update needed */
+ bool compare:1; /* true if compare function needed */
u32 func; /* sensor mask */
u32 sfunc; /* sensor status mask */
int sreg; /* status register */
@@ -1544,7 +1559,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
curr = pmbus_add_sensor(data, name, l->attr, index,
page, 0xff, l->reg, attr->class,
attr->update || l->update,
- false, true);
+ l->readonly, l->writeonly, true);
if (!curr)
return -ENOMEM;
if (l->sbit && (info->func[page] & attr->sfunc)) {
@@ -1584,7 +1599,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
return ret;
}
base = pmbus_add_sensor(data, name, "input", index, page, phase,
- attr->reg, attr->class, true, true, true);
+ attr->reg, attr->class, true, true, false, true);
if (!base)
return -ENOMEM;
/* No limit and alarm attributes for phase specific sensors */
@@ -1707,23 +1722,29 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_VIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_VIN_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_VIN_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VIN_MIN,
+ .readonly = true,
.attr = "rated_min",
}, {
.reg = PMBUS_MFR_VIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1776,23 +1797,29 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_VOUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_VOUT_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_VOUT_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VOUT_MIN,
+ .readonly = true,
.attr = "rated_min",
}, {
.reg = PMBUS_MFR_VOUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1852,20 +1879,25 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_IIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_IIN_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_IIN_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1889,20 +1921,25 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_IOUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_IOUT_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_IOUT_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IOUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1943,20 +1980,25 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_PIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_PIN_MIN,
.update = true,
+ .readonly = true,
.attr = "input_lowest",
}, {
.reg = PMBUS_VIRT_READ_PIN_MAX,
.update = true,
+ .readonly = true,
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_PIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1980,20 +2022,25 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_POUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_POUT_MIN,
.update = true,
+ .readonly = true,
.attr = "input_lowest",
}, {
.reg = PMBUS_VIRT_READ_POUT_MAX,
.update = true,
+ .readonly = true,
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_POUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_POUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2049,18 +2096,23 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_VIRT_READ_TEMP_MIN,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_TEMP_AVG,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_TEMP_MAX,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_1,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2090,18 +2142,23 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MIN,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_TEMP2_AVG,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MAX,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_2,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2131,6 +2188,7 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_MFR_MAX_TEMP_3,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2214,7 +2272,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
sensor = pmbus_add_sensor(data, "fan", "target", index, page,
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
- false, false, true);
+ false, false, false, true);
if (!sensor)
return -ENOMEM;
@@ -2225,14 +2283,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
- false, false, true);
+ false, false, false, true);
if (!sensor)
return -ENOMEM;
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
- true, false, false);
+ true, false, false, false);
if (!sensor)
return -ENOMEM;
@@ -2274,7 +2332,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
if (pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
- PSC_FAN, true, true, true) == NULL)
+ PSC_FAN, true, true, false, true) == NULL)
return -ENOMEM;
/* Fan control */
@@ -3176,12 +3234,19 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
.class = PSC_VOLTAGE_OUT,
.convert = true,
};
+ int ret;
+ mutex_lock(&data->update_lock);
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
- if (s.data < 0)
- return s.data;
+ if (s.data < 0) {
+ ret = s.data;
+ goto unlock;
+ }
- return (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
+ ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
@@ -3198,16 +3263,22 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
};
int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
int low, high;
+ int ret;
*selector = 0;
+ mutex_lock(&data->update_lock);
low = pmbus_regulator_get_low_margin(client, s.page);
- if (low < 0)
- return low;
+ if (low < 0) {
+ ret = low;
+ goto unlock;
+ }
high = pmbus_regulator_get_high_margin(client, s.page);
- if (high < 0)
- return high;
+ if (high < 0) {
+ ret = high;
+ goto unlock;
+ }
/* Make sure we are within margins */
if (low > val)
@@ -3217,7 +3288,10 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
val = pmbus_data2reg(data, &s, val);
- return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+ ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
@@ -3227,6 +3301,7 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
struct i2c_client *client = to_i2c_client(dev->parent);
struct pmbus_data *data = i2c_get_clientdata(client);
int val, low, high;
+ int ret;
if (data->flags & PMBUS_VOUT_PROTECTED)
return 0;
@@ -3239,18 +3314,29 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
val = DIV_ROUND_CLOSEST(rdev->desc->min_uV +
(rdev->desc->uV_step * selector), 1000); /* convert to mV */
+ mutex_lock(&data->update_lock);
+
low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
- if (low < 0)
- return low;
+ if (low < 0) {
+ ret = low;
+ goto unlock;
+ }
high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
- if (high < 0)
- return high;
+ if (high < 0) {
+ ret = high;
+ goto unlock;
+ }
- if (val >= low && val <= high)
- return val * 1000; /* unit is uV */
+ if (val >= low && val <= high) {
+ ret = val * 1000; /* unit is uV */
+ goto unlock;
+ }
- return 0;
+ ret = 0;
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
const struct regulator_ops pmbus_regulator_ops = {
@@ -3281,12 +3367,42 @@ int pmbus_regulator_init_cb(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS");
+static void pmbus_regulator_notify_work_cancel(void *data)
+{
+ struct pmbus_data *pdata = data;
+
+ cancel_work_sync(&pdata->regulator_notify_work);
+}
+
+static void pmbus_regulator_notify_worker(struct work_struct *work)
+{
+ struct pmbus_data *data =
+ container_of(work, struct pmbus_data, regulator_notify_work);
+ int i, j;
+
+ for (i = 0; i < data->info->pages; i++) {
+ int event;
+
+ event = atomic_xchg(&data->regulator_events[i], 0);
+ if (!event)
+ continue;
+
+ for (j = 0; j < data->info->num_regulators; j++) {
+ if (i == rdev_get_id(data->rdevs[j])) {
+ regulator_notifier_call_chain(data->rdevs[j],
+ event, NULL);
+ break;
+ }
+ }
+ }
+}
+
static int pmbus_regulator_register(struct pmbus_data *data)
{
struct device *dev = data->dev;
const struct pmbus_driver_info *info = data->info;
const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
- int i;
+ int i, ret;
data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators,
GFP_KERNEL);
@@ -3310,19 +3426,19 @@ static int pmbus_regulator_register(struct pmbus_data *data)
info->reg_desc[i].name);
}
+ INIT_WORK(&data->regulator_notify_work, pmbus_regulator_notify_worker);
+
+ ret = devm_add_action_or_reset(dev, pmbus_regulator_notify_work_cancel, data);
+ if (ret)
+ return ret;
+
return 0;
}
static void pmbus_regulator_notify(struct pmbus_data *data, int page, int event)
{
- int j;
-
- for (j = 0; j < data->info->num_regulators; j++) {
- if (page == rdev_get_id(data->rdevs[j])) {
- regulator_notifier_call_chain(data->rdevs[j], event, NULL);
- break;
- }
- }
+ atomic_or(event, &data->regulator_events[page]);
+ schedule_work(&data->regulator_notify_work);
}
#else
static int pmbus_regulator_register(struct pmbus_data *data)
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e11d50750e63..7cb6b9b864a7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1213,6 +1213,8 @@ config I2C_TEGRA
tristate "NVIDIA Tegra internal I2C controller"
depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
# COMPILE_TEST needs architectures with readsX()/writesX() primitives
+ depends on PINCTRL
+ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
help
If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs
diff --git a/drivers/i2c/busses/i2c-cp2615.c b/drivers/i2c/busses/i2c-cp2615.c
index e2d7cd2390fc..8212875700e1 100644
--- a/drivers/i2c/busses/i2c-cp2615.c
+++ b/drivers/i2c/busses/i2c-cp2615.c
@@ -298,6 +298,9 @@ cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
if (!adap)
return -ENOMEM;
+ if (!usbdev->serial)
+ return -EINVAL;
+
strscpy(adap->name, usbdev->serial, sizeof(adap->name));
adap->owner = THIS_MODULE;
adap->dev.parent = &usbif->dev;
diff --git a/drivers/i2c/busses/i2c-designware-amdisp.c b/drivers/i2c/busses/i2c-designware-amdisp.c
index c48728ad9f6f..9f0ec0fae6f2 100644
--- a/drivers/i2c/busses/i2c-designware-amdisp.c
+++ b/drivers/i2c/busses/i2c-designware-amdisp.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/soc/amd/isp4_misc.h>
@@ -76,22 +77,20 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
device_enable_async_suspend(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
+ dev_pm_genpd_resume(&pdev->dev);
ret = i2c_dw_probe(isp_i2c_dev);
if (ret) {
dev_err_probe(&pdev->dev, ret, "i2c_dw_probe failed\n");
goto error_release_rpm;
}
-
- pm_runtime_put_sync(&pdev->dev);
+ dev_pm_genpd_suspend(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
return 0;
error_release_rpm:
amd_isp_dw_i2c_plat_pm_cleanup(isp_i2c_dev);
- pm_runtime_put_sync(&pdev->dev);
return ret;
}
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 82c87e04ac6f..b2dc5ae1d0e4 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -729,6 +729,7 @@ static int fsi_i2c_probe(struct fsi_device *fsi_dev)
rc = i2c_add_adapter(&port->adapter);
if (rc < 0) {
dev_err(dev, "Failed to register adapter: %d\n", rc);
+ of_node_put(np);
kfree(port);
continue;
}
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 85f554044cf1..452d120a210b 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1018,8 +1018,9 @@ static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx)
return 0;
}
-static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
+static inline enum imx_i2c_state i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
{
+ enum imx_i2c_state next_state = IMX_I2C_STATE_READ_CONTINUE;
unsigned int temp;
if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) {
@@ -1033,18 +1034,20 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- } else {
- /*
- * For i2c master receiver repeat restart operation like:
- * read -> repeat MSTA -> read/write
- * The controller must set MTX before read the last byte in
- * the first read operation, otherwise the first read cost
- * one extra clock cycle.
- */
- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- temp |= I2CR_MTX;
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ return IMX_I2C_STATE_DONE;
}
+ /*
+ * For i2c master receiver repeat restart operation like:
+ * read -> repeat MSTA -> read/write
+ * The controller must set MTX before read the last byte in
+ * the first read operation, otherwise the first read cost
+ * one extra clock cycle.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_MTX;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ next_state = IMX_I2C_STATE_DONE;
} else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) {
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
@@ -1052,6 +1055,7 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
}
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ return next_state;
}
static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
@@ -1088,11 +1092,9 @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned i
break;
case IMX_I2C_STATE_READ_CONTINUE:
- i2c_imx_isr_read_continue(i2c_imx);
- if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) {
- i2c_imx->state = IMX_I2C_STATE_DONE;
+ i2c_imx->state = i2c_imx_isr_read_continue(i2c_imx);
+ if (i2c_imx->state == IMX_I2C_STATE_DONE)
wake_up(&i2c_imx->queue);
- }
break;
case IMX_I2C_STATE_READ_BLOCK_DATA:
@@ -1490,6 +1492,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
bool is_lastmsg)
{
int block_data = msgs->flags & I2C_M_RECV_LEN;
+ int ret = 0;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
@@ -1522,10 +1525,20 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__);
return -ETIMEDOUT;
}
- if (!i2c_imx->stopped)
- return i2c_imx_bus_busy(i2c_imx, 0, false);
+ if (i2c_imx->is_lastmsg) {
+ if (!i2c_imx->stopped)
+ ret = i2c_imx_bus_busy(i2c_imx, 0, false);
+ /*
+ * Only read the last byte of the last message after the bus is
+ * not busy. Else the controller generates another clock which
+ * might confuse devices.
+ */
+ if (!ret)
+ i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx,
+ IMX_I2C_I2DR);
+ }
- return 0;
+ return ret;
}
static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 09af3b3625f1..f55840b2eb9a 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -268,6 +268,7 @@ struct pxa_i2c {
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_default;
struct pinctrl_state *pinctrl_recovery;
+ bool reset_before_xfer;
};
#define _IBMR(i2c) ((i2c)->reg_ibmr)
@@ -1144,6 +1145,11 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap,
{
struct pxa_i2c *i2c = adap->algo_data;
+ if (i2c->reset_before_xfer) {
+ i2c_pxa_reset(i2c);
+ i2c->reset_before_xfer = false;
+ }
+
return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_xfer);
}
@@ -1521,7 +1527,16 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
}
- i2c_pxa_reset(i2c);
+ /*
+ * Skip reset on Armada 3700 when recovery is used to avoid
+ * controller hang due to the pinctrl state changes done by
+ * the generic recovery initialization code. The reset will
+ * be performed later, prior to the first transfer.
+ */
+ if (i2c_type == REGS_A3700 && i2c->adap.bus_recovery_info)
+ i2c->reset_before_xfer = true;
+ else
+ i2c_pxa_reset(i2c);
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index bec619b9af4e..4eaeb395d5db 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -2047,8 +2047,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
*
* VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
* be used for atomic transfers. ACPI device is not IRQ safe also.
+ *
+ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
+ * state transitions during runtime PM require mutexes.
*/
- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
+ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
pm_runtime_irq_safe(i2c_dev->dev);
pm_runtime_enable(i2c_dev->dev);
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index fc45c384833f..4fafe393a48c 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -608,14 +608,29 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num,
if (rdma_rw_io_needs_mr(qp->device, port_num, dir, sg_cnt)) {
ret = rdma_rw_init_mr_wrs(ctx, qp, port_num, sg, sg_cnt,
sg_offset, remote_addr, rkey, dir);
- } else if (sg_cnt > 1) {
+ /*
+ * If MR init succeeded or failed for a reason other
+ * than pool exhaustion, that result is final.
+ *
+ * Pool exhaustion (-EAGAIN) from the max_sgl_rd
+ * optimization is recoverable: fall back to
+ * direct SGE posting. iWARP and force_mr require
+ * MRs unconditionally, so -EAGAIN is terminal.
+ */
+ if (ret != -EAGAIN ||
+ rdma_protocol_iwarp(qp->device, port_num) ||
+ unlikely(rdma_rw_force_mr))
+ goto out;
+ }
+
+ if (sg_cnt > 1)
ret = rdma_rw_init_map_wrs(ctx, qp, sg, sg_cnt, sg_offset,
remote_addr, rkey, dir);
- } else {
+ else
ret = rdma_rw_init_single_wr(ctx, qp, sg, sg_offset,
remote_addr, rkey, dir);
- }
+out:
if (ret < 0)
goto out_unmap_sg;
return ret;
@@ -686,14 +701,16 @@ int rdma_rw_ctx_init_bvec(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
return ret;
/*
- * IOVA mapping not available. Check if MR registration provides
- * better performance than multiple SGE entries.
+ * IOVA not available; fall back to the map_wrs path, which maps
+ * each bvec as a direct SGE. This is always correct: the MR path
+ * is a throughput optimization, not a correctness requirement.
+ * (iWARP, which does require MRs, is handled by the check above.)
+ *
+ * The rdma_rw_io_needs_mr() gate is not used here because nr_bvec
+ * is a raw page count that overstates DMA entry demand -- the bvec
+ * caller has no post-DMA-coalescing segment count, and feeding the
+ * inflated count into the MR path exhausts the pool on RDMA READs.
*/
- if (rdma_rw_io_needs_mr(dev, port_num, dir, nr_bvec))
- return rdma_rw_init_mr_wrs_bvec(ctx, qp, port_num, bvecs,
- nr_bvec, &iter, remote_addr,
- rkey, dir);
-
return rdma_rw_init_map_wrs_bvec(ctx, qp, bvecs, nr_bvec, &iter,
remote_addr, rkey, dir);
}
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index cff4fcca2c34..edc34c69f0f2 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -55,7 +55,8 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
if (dirty)
ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt,
- DMA_BIDIRECTIONAL, 0);
+ DMA_BIDIRECTIONAL,
+ DMA_ATTR_REQUIRE_COHERENT);
for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) {
unpin_user_page_range_dirty_lock(sg_page(sg),
@@ -169,7 +170,7 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
unsigned long lock_limit;
unsigned long new_pinned;
unsigned long cur_base;
- unsigned long dma_attr = 0;
+ unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT;
struct mm_struct *mm;
unsigned long npages;
int pinned, ret;
diff --git a/drivers/infiniband/hw/bng_re/bng_dev.c b/drivers/infiniband/hw/bng_re/bng_dev.c
index d34b5f88cd40..71a7ca2196ad 100644
--- a/drivers/infiniband/hw/bng_re/bng_dev.c
+++ b/drivers/infiniband/hw/bng_re/bng_dev.c
@@ -210,7 +210,7 @@ static int bng_re_stats_ctx_alloc(struct bng_re_dev *rdev)
return rc;
}
-static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
+static int bng_re_query_hwrm_version(struct bng_re_dev *rdev)
{
struct bnge_auxr_dev *aux_dev = rdev->aux_dev;
struct hwrm_ver_get_output ver_get_resp = {};
@@ -230,7 +230,7 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
if (rc) {
ibdev_err(&rdev->ibdev, "Failed to query HW version, rc = 0x%x",
rc);
- return;
+ return rc;
}
cctx = rdev->chip_ctx;
@@ -244,6 +244,8 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
if (!cctx->hwrm_cmd_max_timeout)
cctx->hwrm_cmd_max_timeout = BNG_ROCE_FW_MAX_TIMEOUT;
+
+ return 0;
}
static void bng_re_dev_uninit(struct bng_re_dev *rdev)
@@ -306,13 +308,15 @@ static int bng_re_dev_init(struct bng_re_dev *rdev)
goto msix_ctx_fail;
}
- bng_re_query_hwrm_version(rdev);
+ rc = bng_re_query_hwrm_version(rdev);
+ if (rc)
+ goto destroy_chip_ctx;
rc = bng_re_alloc_fw_channel(&rdev->bng_res, &rdev->rcfw);
if (rc) {
ibdev_err(&rdev->ibdev,
"Failed to allocate RCFW Channel: %#x\n", rc);
- goto alloc_fw_chl_fail;
+ goto destroy_chip_ctx;
}
/* Allocate nq record memory */
@@ -391,7 +395,7 @@ free_rcfw:
kfree(rdev->nqr);
nq_alloc_fail:
bng_re_free_rcfw_channel(&rdev->rcfw);
-alloc_fw_chl_fail:
+destroy_chip_ctx:
bng_re_destroy_chip_ctx(rdev);
msix_ctx_fail:
bnge_unregister_dev(rdev->aux_dev);
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index 229b0ad3b0cb..e97b5f0d7003 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include <linux/log2.h>
@@ -310,23 +310,19 @@ static inline struct efa_comp_ctx *efa_com_get_comp_ctx_by_cmd_id(struct efa_com
return &aq->comp_ctx[ctx_id];
}
-static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
- struct efa_admin_aq_entry *cmd,
- size_t cmd_size_in_bytes,
- struct efa_admin_acq_entry *comp,
- size_t comp_size_in_bytes)
+static void __efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
+ struct efa_comp_ctx *comp_ctx,
+ struct efa_admin_aq_entry *cmd,
+ size_t cmd_size_in_bytes,
+ struct efa_admin_acq_entry *comp,
+ size_t comp_size_in_bytes)
{
struct efa_admin_aq_entry *aqe;
- struct efa_comp_ctx *comp_ctx;
u16 queue_size_mask;
u16 cmd_id;
u16 ctx_id;
u16 pi;
- comp_ctx = efa_com_alloc_comp_ctx(aq);
- if (!comp_ctx)
- return ERR_PTR(-EINVAL);
-
queue_size_mask = aq->depth - 1;
pi = aq->sq.pc & queue_size_mask;
ctx_id = efa_com_get_comp_ctx_id(aq, comp_ctx);
@@ -360,8 +356,6 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu
/* barrier not needed in case of writel */
writel(aq->sq.pc, aq->sq.db_addr);
-
- return comp_ctx;
}
static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq)
@@ -394,28 +388,25 @@ static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq)
return 0;
}
-static struct efa_comp_ctx *efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
- struct efa_admin_aq_entry *cmd,
- size_t cmd_size_in_bytes,
- struct efa_admin_acq_entry *comp,
- size_t comp_size_in_bytes)
+static int efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
+ struct efa_comp_ctx *comp_ctx,
+ struct efa_admin_aq_entry *cmd,
+ size_t cmd_size_in_bytes,
+ struct efa_admin_acq_entry *comp,
+ size_t comp_size_in_bytes)
{
- struct efa_comp_ctx *comp_ctx;
-
spin_lock(&aq->sq.lock);
if (!test_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state)) {
ibdev_err_ratelimited(aq->efa_dev, "Admin queue is closed\n");
spin_unlock(&aq->sq.lock);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
- comp_ctx = __efa_com_submit_admin_cmd(aq, cmd, cmd_size_in_bytes, comp,
- comp_size_in_bytes);
+ __efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size_in_bytes, comp,
+ comp_size_in_bytes);
spin_unlock(&aq->sq.lock);
- if (IS_ERR(comp_ctx))
- clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- return comp_ctx;
+ return 0;
}
static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq,
@@ -512,7 +503,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
{
unsigned long timeout;
unsigned long flags;
- int err;
timeout = jiffies + usecs_to_jiffies(aq->completion_timeout);
@@ -532,24 +522,20 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
atomic64_inc(&aq->stats.no_completion);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
msleep(aq->poll_interval);
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_dealloc_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *comp_ctx,
struct efa_com_admin_queue *aq)
{
unsigned long flags;
- int err;
wait_for_completion_timeout(&comp_ctx->wait_event,
usecs_to_jiffies(aq->completion_timeout));
@@ -585,14 +571,11 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com
aq->cq.cc);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_dealloc_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
/*
@@ -642,30 +625,39 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq,
ibdev_dbg(aq->efa_dev, "%s (opcode %d)\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
cmd->aq_common_descriptor.opcode);
- comp_ctx = efa_com_submit_admin_cmd(aq, cmd, cmd_size, comp, comp_size);
- if (IS_ERR(comp_ctx)) {
+
+ comp_ctx = efa_com_alloc_comp_ctx(aq);
+ if (!comp_ctx) {
+ clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
+ up(&aq->avail_cmds);
+ return -EINVAL;
+ }
+
+ err = efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size, comp, comp_size);
+ if (err) {
ibdev_err_ratelimited(
aq->efa_dev,
- "Failed to submit command %s (opcode %u) err %pe\n",
+ "Failed to submit command %s (opcode %u) err %d\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
- cmd->aq_common_descriptor.opcode, comp_ctx);
+ cmd->aq_common_descriptor.opcode, err);
+ efa_com_dealloc_comp_ctx(aq, comp_ctx);
up(&aq->avail_cmds);
atomic64_inc(&aq->stats.cmd_err);
- return PTR_ERR(comp_ctx);
+ return err;
}
err = efa_com_wait_and_process_admin_cq(comp_ctx, aq);
if (err) {
ibdev_err_ratelimited(
aq->efa_dev,
- "Failed to process command %s (opcode %u) comp_status %d err %d\n",
+ "Failed to process command %s (opcode %u) err %d\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
- cmd->aq_common_descriptor.opcode,
- comp_ctx->user_cqe->acq_common_descriptor.status, err);
+ cmd->aq_common_descriptor.opcode, err);
atomic64_inc(&aq->stats.cmd_err);
}
+ efa_com_dealloc_comp_ctx(aq, comp_ctx);
up(&aq->avail_cmds);
return err;
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 4842931f5316..a5671da3db64 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -508,6 +508,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
{
const struct ib_global_route *grh;
enum rdma_network_type net;
+ u8 smac[ETH_ALEN];
u16 vlan;
int rc;
@@ -518,7 +519,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
grh = rdma_ah_read_grh(attr);
- rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, &hdr->eth.smac_h[0]);
+ rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, smac);
if (rc)
return rc;
@@ -536,6 +537,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
if (rc)
return rc;
+ ether_addr_copy(hdr->eth.smac_h, smac);
ether_addr_copy(hdr->eth.dmac_h, attr->roce.dmac);
if (net == RDMA_NETWORK_IPV4) {
diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c
index 3d084d4ff577..91c0e7298283 100644
--- a/drivers/infiniband/hw/irdma/cm.c
+++ b/drivers/infiniband/hw/irdma/cm.c
@@ -2241,11 +2241,12 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
int oldarpindex;
int arpindex;
struct net_device *netdev = iwdev->netdev;
+ int ret;
/* create an hte and cm_node for this instance */
cm_node = kzalloc_obj(*cm_node, GFP_ATOMIC);
if (!cm_node)
- return NULL;
+ return ERR_PTR(-ENOMEM);
/* set our node specific transport info */
cm_node->ipv4 = cm_info->ipv4;
@@ -2348,8 +2349,10 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
arpindex = -EINVAL;
}
- if (arpindex < 0)
+ if (arpindex < 0) {
+ ret = -EINVAL;
goto err;
+ }
ether_addr_copy(cm_node->rem_mac,
iwdev->rf->arp_table[arpindex].mac_addr);
@@ -2360,7 +2363,7 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
err:
kfree(cm_node);
- return NULL;
+ return ERR_PTR(ret);
}
static void irdma_destroy_connection(struct irdma_cm_node *cm_node)
@@ -3021,8 +3024,8 @@ static int irdma_create_cm_node(struct irdma_cm_core *cm_core,
/* create a CM connection node */
cm_node = irdma_make_cm_node(cm_core, iwdev, cm_info, NULL);
- if (!cm_node)
- return -ENOMEM;
+ if (IS_ERR(cm_node))
+ return PTR_ERR(cm_node);
/* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1;
@@ -3219,9 +3222,9 @@ void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf)
cm_info.cm_id = listener->cm_id;
cm_node = irdma_make_cm_node(cm_core, iwdev, &cm_info,
listener);
- if (!cm_node) {
+ if (IS_ERR(cm_node)) {
ibdev_dbg(&cm_core->iwdev->ibdev,
- "CM: allocate node failed\n");
+ "CM: allocate node failed ret=%ld\n", PTR_ERR(cm_node));
refcount_dec(&listener->refcnt);
return;
}
@@ -4239,21 +4242,21 @@ static void irdma_cm_event_handler(struct work_struct *work)
irdma_cm_event_reset(event);
break;
case IRDMA_CM_EVENT_CONNECTED:
- if (!event->cm_node->cm_id ||
- event->cm_node->state != IRDMA_CM_STATE_OFFLOADED)
+ if (!cm_node->cm_id ||
+ cm_node->state != IRDMA_CM_STATE_OFFLOADED)
break;
irdma_cm_event_connected(event);
break;
case IRDMA_CM_EVENT_MPA_REJECT:
- if (!event->cm_node->cm_id ||
+ if (!cm_node->cm_id ||
cm_node->state == IRDMA_CM_STATE_OFFLOADED)
break;
irdma_send_cm_event(cm_node, cm_node->cm_id,
IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED);
break;
case IRDMA_CM_EVENT_ABORTED:
- if (!event->cm_node->cm_id ||
- event->cm_node->state == IRDMA_CM_STATE_OFFLOADED)
+ if (!cm_node->cm_id ||
+ cm_node->state == IRDMA_CM_STATE_OFFLOADED)
break;
irdma_event_connect_error(event);
break;
@@ -4263,7 +4266,7 @@ static void irdma_cm_event_handler(struct work_struct *work)
break;
}
- irdma_rem_ref_cm_node(event->cm_node);
+ irdma_rem_ref_cm_node(cm_node);
kfree(event);
}
diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c
index ac3721a5747a..4718acf6c6fd 100644
--- a/drivers/infiniband/hw/irdma/uk.c
+++ b/drivers/infiniband/hw/irdma/uk.c
@@ -1438,7 +1438,7 @@ exit:
* irdma_round_up_wq - return round up qp wq depth
* @wqdepth: wq depth in quanta to round up
*/
-static int irdma_round_up_wq(u32 wqdepth)
+static u64 irdma_round_up_wq(u64 wqdepth)
{
int scount = 1;
@@ -1491,15 +1491,16 @@ void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge,
int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift,
u32 *sqdepth)
{
- u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift;
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)sq_size << shift) + IRDMA_SQ_RSVD);
- *sqdepth = irdma_round_up_wq((sq_size << shift) + IRDMA_SQ_RSVD);
-
- if (*sqdepth < min_size)
- *sqdepth = min_size;
- else if (*sqdepth > uk_attrs->max_hw_wq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_wq_quanta)
return -EINVAL;
+ *sqdepth = hw_quanta;
return 0;
}
@@ -1513,15 +1514,16 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift,
int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift,
u32 *rqdepth)
{
- u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift;
-
- *rqdepth = irdma_round_up_wq((rq_size << shift) + IRDMA_RQ_RSVD);
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)rq_size << shift) + IRDMA_RQ_RSVD);
- if (*rqdepth < min_size)
- *rqdepth = min_size;
- else if (*rqdepth > uk_attrs->max_hw_rq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_rq_quanta)
return -EINVAL;
+ *rqdepth = hw_quanta;
return 0;
}
@@ -1535,13 +1537,16 @@ int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift,
int irdma_get_srqdepth(struct irdma_uk_attrs *uk_attrs, u32 srq_size, u8 shift,
u32 *srqdepth)
{
- *srqdepth = irdma_round_up_wq((srq_size << shift) + IRDMA_RQ_RSVD);
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)srq_size << shift) + IRDMA_RQ_RSVD);
- if (*srqdepth < ((u32)uk_attrs->min_hw_wq_size << shift))
- *srqdepth = uk_attrs->min_hw_wq_size << shift;
- else if (*srqdepth > uk_attrs->max_hw_srq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_srq_quanta)
return -EINVAL;
+ *srqdepth = hw_quanta;
return 0;
}
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index ab8c5284d4be..495e5daff4b4 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -2322,8 +2322,6 @@ void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp)
struct irdma_qp *qp = sc_qp->qp_uk.back_qp;
struct ib_qp_attr attr;
- if (qp->iwdev->rf->reset)
- return;
attr.qp_state = IB_QPS_ERR;
if (rdma_protocol_roce(qp->ibqp.device, 1))
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index 7251cd7a2147..95f590c10c05 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -558,7 +558,8 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
}
irdma_qp_rem_ref(&iwqp->ibqp);
- wait_for_completion(&iwqp->free_qp);
+ if (!iwdev->rf->reset)
+ wait_for_completion(&iwqp->free_qp);
irdma_free_lsmm_rsrc(iwqp);
irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
@@ -1105,6 +1106,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,
spin_lock_init(&iwqp->sc_qp.pfpdu.lock);
iwqp->sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
rf->qp_table[qp_num] = iwqp;
+ init_completion(&iwqp->free_qp);
if (udata) {
/* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
@@ -1129,7 +1131,6 @@ static int irdma_create_qp(struct ib_qp *ibqp,
}
}
- init_completion(&iwqp->free_qp);
return 0;
error:
@@ -1462,8 +1463,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
ctx_info->remote_atomics_en = true;
}
- wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
-
ibdev_dbg(&iwdev->ibdev,
"VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n",
__builtin_return_address(0), ibqp->qp_num, attr->qp_state,
@@ -1540,6 +1539,7 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
case IB_QPS_ERR:
case IB_QPS_RESET:
if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
if (ib_copy_from_udata(&ureq, udata,
@@ -1745,6 +1745,7 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
case IB_QPS_ERR:
case IB_QPS_RESET:
if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
if (ib_copy_from_udata(&ureq, udata,
@@ -3723,6 +3724,7 @@ static int irdma_rereg_mr_trans(struct irdma_mr *iwmr, u64 start, u64 len,
err:
ib_umem_release(region);
+ iwmr->region = NULL;
return err;
}
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 81c4d7733872..760d5f4623b5 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2909,8 +2909,21 @@ static struct iommu_domain blocked_domain = {
static struct protection_domain identity_domain;
+static int amd_iommu_identity_attach(struct iommu_domain *dom, struct device *dev,
+ struct iommu_domain *old)
+{
+ /*
+ * Don't allow attaching a device to the identity domain if SNP is
+ * enabled.
+ */
+ if (amd_iommu_snp_en)
+ return -EINVAL;
+
+ return amd_iommu_attach_device(dom, dev, old);
+}
+
static const struct iommu_domain_ops identity_domain_ops = {
- .attach_dev = amd_iommu_attach_device,
+ .attach_dev = amd_iommu_identity_attach,
};
void amd_iommu_init_identity_domain(void)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 5dac64be61bb..94d514169642 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1211,7 +1211,7 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
*/
if (dev_use_swiotlb(dev, size, dir) &&
iova_unaligned(iovad, phys, size)) {
- if (attrs & DMA_ATTR_MMIO)
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
return DMA_MAPPING_ERROR;
phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs);
@@ -1223,7 +1223,8 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
arch_sync_dma_for_device(phys, size, dir);
iova = __iommu_dma_map(dev, phys, size, prot, dma_mask);
- if (iova == DMA_MAPPING_ERROR && !(attrs & DMA_ATTR_MMIO))
+ if (iova == DMA_MAPPING_ERROR &&
+ !(attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)))
swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs);
return iova;
}
@@ -1233,7 +1234,7 @@ void iommu_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
{
phys_addr_t phys;
- if (attrs & DMA_ATTR_MMIO) {
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) {
__iommu_dma_unmap(dev, dma_handle, size);
return;
}
@@ -1945,9 +1946,21 @@ int dma_iova_link(struct device *dev, struct dma_iova_state *state,
if (WARN_ON_ONCE(iova_start_pad && offset > 0))
return -EIO;
+ /*
+ * DMA_IOVA_USE_SWIOTLB is set on state after some entry
+ * took SWIOTLB path, which we were supposed to prevent
+ * for DMA_ATTR_REQUIRE_COHERENT attribute.
+ */
+ if (WARN_ON_ONCE((state->__size & DMA_IOVA_USE_SWIOTLB) &&
+ (attrs & DMA_ATTR_REQUIRE_COHERENT)))
+ return -EOPNOTSUPP;
+
+ if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT))
+ return -EOPNOTSUPP;
+
if (dev_use_swiotlb(dev, size, dir) &&
iova_unaligned(iovad, phys, size)) {
- if (attrs & DMA_ATTR_MMIO)
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
return -EPERM;
return iommu_dma_iova_link_swiotlb(dev, state, phys, offset,
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index d68c06025cac..69222dbd2af0 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1314,7 +1314,6 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
if (fault & DMA_FSTS_ITE) {
head = readl(iommu->reg + DMAR_IQH_REG);
head = ((head >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
- head |= 1;
tail = readl(iommu->reg + DMAR_IQT_REG);
tail = ((tail >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
@@ -1331,7 +1330,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
do {
if (qi->desc_status[head] == QI_IN_USE)
qi->desc_status[head] = QI_ABORT;
- head = (head - 2 + QI_LENGTH) % QI_LENGTH;
+ head = (head - 1 + QI_LENGTH) % QI_LENGTH;
} while (head != tail);
/*
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index fea10acd4f02..57cd1db7207a 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -164,9 +164,12 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
if (IS_ERR(dev_pasid))
return PTR_ERR(dev_pasid);
- ret = iopf_for_domain_replace(domain, old, dev);
- if (ret)
- goto out_remove_dev_pasid;
+ /* SVA with non-IOMMU/PRI IOPF handling is allowed. */
+ if (info->pri_supported) {
+ ret = iopf_for_domain_replace(domain, old, dev);
+ if (ret)
+ goto out_remove_dev_pasid;
+ }
/* Setup the pasid table: */
sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
@@ -181,7 +184,8 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
return 0;
out_unwind_iopf:
- iopf_for_domain_replace(old, domain, dev);
+ if (info->pri_supported)
+ iopf_for_domain_replace(old, domain, dev);
out_remove_dev_pasid:
domain_remove_dev_pasid(domain, dev, pasid);
return ret;
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index 07d64908a05f..bc7c7232a43e 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -182,13 +182,13 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
if (--domain->users == 0) {
list_del(&domain->next);
- iommu_domain_free(domain);
- }
+ if (list_empty(&iommu_mm->sva_domains)) {
+ list_del(&iommu_mm->mm_list_elm);
+ if (list_empty(&iommu_sva_mms))
+ iommu_sva_present = false;
+ }
- if (list_empty(&iommu_mm->sva_domains)) {
- list_del(&iommu_mm->mm_list_elm);
- if (list_empty(&iommu_sva_mms))
- iommu_sva_present = false;
+ iommu_domain_free(domain);
}
mutex_unlock(&iommu_sva_lock);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 35db51780954..50718ab810a4 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1213,7 +1213,11 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
if (addr == end)
goto map_end;
- phys_addr = iommu_iova_to_phys(domain, addr);
+ /*
+ * Return address by iommu_iova_to_phys for 0 is
+ * ambiguous. Offset to address 1 if addr is 0.
+ */
+ phys_addr = iommu_iova_to_phys(domain, addr ? addr : 1);
if (!phys_addr) {
map_size += pg_size;
continue;
diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c
index 83f31ea657b7..181320528a47 100644
--- a/drivers/irqchip/irq-qcom-mpm.c
+++ b/drivers/irqchip/irq-qcom-mpm.c
@@ -306,6 +306,8 @@ static int mpm_pd_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
return ret;
+ mbox_client_txdone(priv->mbox_chan, 0);
+
return 0;
}
@@ -434,6 +436,7 @@ static int qcom_mpm_probe(struct platform_device *pdev, struct device_node *pare
}
priv->mbox_client.dev = dev;
+ priv->mbox_client.knows_txdone = true;
priv->mbox_chan = mbox_request_channel(&priv->mbox_client, 0);
if (IS_ERR(priv->mbox_chan)) {
ret = PTR_ERR(priv->mbox_chan);
diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index da2bc43a0e12..03e93b061edd 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -621,7 +621,7 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
return 0;
pm_put:
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
return ret;
}
diff --git a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
index 5c74c561ce31..612f3972f7af 100644
--- a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
+++ b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
@@ -250,6 +250,7 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev)
rc = riscv_acpi_get_gsi_info(fwnode, &priv->gsi_base, &id,
&nr_irqs, NULL);
if (rc) {
+ mbox_free_channel(priv->chan);
dev_err(dev, "failed to find GSI mapping\n");
return rc;
}
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index aa4dd7e7cf5a..8e25f970fd12 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -3080,8 +3080,6 @@ static int ccs_init_state(struct v4l2_subdev *sd,
struct v4l2_rect *crop =
v4l2_subdev_state_get_crop(sd_state, pad);
- guard(mutex)(&sensor->mutex);
-
ccs_get_native_size(ssd, crop);
fmt->width = crop->width;
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
index c7c7d4a86c6b..13e77648807c 100644
--- a/drivers/media/mc/mc-request.c
+++ b/drivers/media/mc/mc-request.c
@@ -192,6 +192,8 @@ static long media_request_ioctl_reinit(struct media_request *req)
struct media_device *mdev = req->mdev;
unsigned long flags;
+ mutex_lock(&mdev->req_queue_mutex);
+
spin_lock_irqsave(&req->lock, flags);
if (req->state != MEDIA_REQUEST_STATE_IDLE &&
req->state != MEDIA_REQUEST_STATE_COMPLETE) {
@@ -199,6 +201,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s not in idle or complete state, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
if (req->access_count) {
@@ -206,6 +209,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s is being accessed, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
req->state = MEDIA_REQUEST_STATE_CLEANING;
@@ -216,6 +220,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
spin_lock_irqsave(&req->lock, flags);
req->state = MEDIA_REQUEST_STATE_IDLE;
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return 0;
}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 28267ee30190..3119f3bc9f98 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -500,11 +500,15 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
+ } else {
+ run->ext_sps_st_rps = NULL;
}
if (ctx->has_sps_lt_rps) {
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
+ } else {
+ run->ext_sps_lt_rps = NULL;
}
rkvdec_run_preamble(ctx, &run->base);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
index 97f1efde2e47..fb4f849d7366 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -130,7 +130,7 @@ struct rkvdec_h264_ctx {
struct vdpu383_regs_h26x regs;
};
-static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb)
+static noinline_for_stack void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb)
{
pps->top_field_order_cnt0 = dpb[0].top_field_order_cnt;
pps->bot_field_order_cnt0 = dpb[0].bottom_field_order_cnt;
@@ -166,6 +166,31 @@ static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_d
pps->bot_field_order_cnt15 = dpb[15].bottom_field_order_cnt;
}
+static noinline_for_stack void set_dec_params(struct rkvdec_pps *pps, const struct v4l2_ctrl_h264_decode_params *dec_params)
+{
+ const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+
+ for (int i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ pps->is_longterm |= (1 << i);
+ pps->ref_field_flags |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
+ pps->ref_colmv_use_flag |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
+ pps->ref_topfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
+ pps->ref_botfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
+ }
+ pps->pic_field_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
+ pps->pic_associated_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
+
+ pps->cur_top_field = dec_params->top_field_order_cnt;
+ pps->cur_bot_field = dec_params->bottom_field_order_cnt;
+}
+
static void assemble_hw_pps(struct rkvdec_ctx *ctx,
struct rkvdec_h264_run *run)
{
@@ -177,7 +202,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
struct rkvdec_sps_pps *hw_ps;
u32 pic_width, pic_height;
- u32 i;
/*
* HW read the SPS/PPS information from PPS packet index by PPS id.
@@ -261,28 +285,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
set_field_order_cnt(&hw_ps->pps, dpb);
+ set_dec_params(&hw_ps->pps, dec_params);
- for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
- hw_ps->pps.is_longterm |= (1 << i);
-
- hw_ps->pps.ref_field_flags |=
- (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
- hw_ps->pps.ref_colmv_use_flag |=
- (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
- hw_ps->pps.ref_topfield_used |=
- (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
- hw_ps->pps.ref_botfield_used |=
- (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
- }
-
- hw_ps->pps.pic_field_flag =
- !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
- hw_ps->pps.pic_associated_flag =
- !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
-
- hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
- hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
}
static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index e4cdd2122873..2751f5396ee8 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -893,7 +893,8 @@ out_update_last:
update_ctx_last_info(vp9_ctx);
}
-static void rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx)
+static noinline_for_stack void
+rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx)
{
struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
struct rkvdec_vp9_intra_frame_symbol_counts *intra_cnts = vp9_ctx->count_tbl.cpu;
diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig
index e798ec00b189..bf2ac092fbb3 100644
--- a/drivers/media/platform/synopsys/Kconfig
+++ b/drivers/media/platform/synopsys/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_DW_MIPI_CSI2RX
depends on VIDEO_DEV
depends on V4L_PLATFORM_DRIVERS
depends on PM && COMMON_CLK
+ select GENERIC_PHY_MIPI_DPHY
select MEDIA_CONTROLLER
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 170346ae1a59..4d96171a650b 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -301,7 +301,7 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
case DW_MIPI_CSI2RX_PAD_SINK:
- if (code->index > csi2->formats_num)
+ if (code->index >= csi2->formats_num)
return -EINVAL;
code->code = csi2->formats[code->index].code;
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index 6f8e43b7f157..fa4224de4b99 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -343,7 +343,7 @@ const struct hantro_variant imx8mq_vpu_variant = {
.num_regs = ARRAY_SIZE(imx8mq_reg_names)
};
-static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+static const struct of_device_id imx8mq_vpu_shared_resources[] = {
{ .compatible = "nxp,imx8mq-vpu-g1", },
{ .compatible = "nxp,imx8mq-vpu-g2", },
{ /* sentinel */ }
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 40c76c051da2..f6c8e3223796 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1751,7 +1751,8 @@ static void uvc_video_complete(struct urb *urb)
/*
* Free transfer buffers.
*/
-static void uvc_free_urb_buffers(struct uvc_streaming *stream)
+static void uvc_free_urb_buffers(struct uvc_streaming *stream,
+ unsigned int size)
{
struct usb_device *udev = stream->dev->udev;
struct uvc_urb *uvc_urb;
@@ -1760,7 +1761,7 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
if (!uvc_urb->buffer)
continue;
- usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer,
+ usb_free_noncoherent(udev, size, uvc_urb->buffer,
uvc_stream_dir(stream), uvc_urb->sgt);
uvc_urb->buffer = NULL;
uvc_urb->sgt = NULL;
@@ -1820,7 +1821,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
if (!uvc_alloc_urb_buffer(stream, uvc_urb, urb_size,
gfp_flags)) {
- uvc_free_urb_buffers(stream);
+ uvc_free_urb_buffers(stream, urb_size);
break;
}
@@ -1868,7 +1869,7 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream,
}
if (free_buffers)
- uvc_free_urb_buffers(stream);
+ uvc_free_urb_buffers(stream, stream->urb_size);
}
/*
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 37d33d4a363d..a2b650f4ec3c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -3082,13 +3082,14 @@ static long __video_do_ioctl(struct file *file,
}
/*
- * We need to serialize streamon/off with queueing new requests.
+ * We need to serialize streamon/off/reqbufs with queueing new requests.
* These ioctls may trigger the cancellation of a streaming
* operation, and that should not be mixed with queueing a new
* request at the same time.
*/
if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
- (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
+ (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF ||
+ cmd == VIDIOC_REQBUFS)) {
req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;
if (mutex_lock_interruptible(req_queue_lock))
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index b0f91cc9e40e..6e4084407662 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -68,6 +68,9 @@
#define GLI_9750_MISC_TX1_DLY_VALUE 0x5
#define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26)
+#define SDHCI_GLI_9750_GM_BURST_SIZE 0x510
+#define SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT GENMASK(17, 16)
+
#define SDHCI_GLI_9750_TUNING_CONTROL 0x540
#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4)
#define GLI_9750_TUNING_CONTROL_EN_ON 0x1
@@ -345,10 +348,16 @@ static void gli_set_9750(struct sdhci_host *host)
u32 misc_value;
u32 parameter_value;
u32 control_value;
+ u32 burst_value;
u16 ctrl2;
gl9750_wt_on(host);
+ /* clear R_OSRC_Lmt to avoid DMA write corruption */
+ burst_value = sdhci_readl(host, SDHCI_GLI_9750_GM_BURST_SIZE);
+ burst_value &= ~SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT;
+ sdhci_writel(host, burst_value, SDHCI_GLI_9750_GM_BURST_SIZE);
+
driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ac7e11f37af7..fec9329e1edb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4532,8 +4532,15 @@ int sdhci_setup_host(struct sdhci_host *host)
* their platform code before calling sdhci_add_host(), and we
* won't assume 8-bit width for hosts without that CAP.
*/
- if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
+ if (host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA) {
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
+ if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400)
+ host->caps1 &= ~SDHCI_SUPPORT_HS400;
+ mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
+ mmc->caps &= ~(MMC_CAP_DDR | MMC_CAP_UHS);
+ } else {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ }
if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
mmc->caps &= ~MMC_CAP_CMD23;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 0427d76f45d0..5b9dadd5405e 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2350,14 +2350,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < ctrl->max_oob; i += 4)
oob_reg_write(ctrl, i, 0xffffffff);
- if (mtd->oops_panic_write)
+ if (mtd->oops_panic_write) {
/* switch to interrupt polling and PIO mode */
disable_ctrl_irqs(ctrl);
-
- if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
+ } else if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize,
CMD_PROGRAM_PAGE))
-
ret = -EIO;
goto out;
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 99135ec23010..d53b35a8b3cb 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -3133,7 +3133,7 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
sizeof(*cdns_ctrl->cdma_desc),
&cdns_ctrl->dma_cdma_desc,
GFP_KERNEL);
- if (!cdns_ctrl->dma_cdma_desc)
+ if (!cdns_ctrl->cdma_desc)
return -ENOMEM;
cdns_ctrl->buf_size = SZ_16K;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 38429363251c..dfd8361bdd36 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4737,11 +4737,16 @@ static void nand_shutdown(struct mtd_info *mtd)
static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.lock_area)
return -ENOTSUPP;
- return chip->ops.lock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.lock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/**
@@ -4753,11 +4758,16 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.unlock_area)
return -ENOTSUPP;
- return chip->ops.unlock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.unlock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/* Set default functions */
diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c
index 947fd86ac5fa..f2c65eb7a8d9 100644
--- a/drivers/mtd/nand/raw/pl35x-nand-controller.c
+++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c
@@ -862,6 +862,9 @@ static int pl35x_nfc_setup_interface(struct nand_chip *chip, int cs,
PL35X_SMC_NAND_TAR_CYCLES(tmgs.t_ar) |
PL35X_SMC_NAND_TRR_CYCLES(tmgs.t_rr);
+ writel(plnand->timings, nfc->conf_regs + PL35X_SMC_CYCLES);
+ pl35x_smc_update_regs(nfc);
+
return 0;
}
diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c
index 558905160ddb..bf162c44eafe 100644
--- a/drivers/mtd/parsers/redboot.c
+++ b/drivers/mtd/parsers/redboot.c
@@ -270,9 +270,9 @@ nogood:
strcpy(names, fl->img->name);
#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
- if (!memcmp(names, "RedBoot", 8) ||
- !memcmp(names, "RedBoot config", 15) ||
- !memcmp(names, "FIS directory", 14)) {
+ if (!strcmp(names, "RedBoot") ||
+ !strcmp(names, "RedBoot config") ||
+ !strcmp(names, "FIS directory")) {
parts[i].mask_flags = MTD_WRITEABLE;
}
#endif
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 8ffeb41c3e08..1eee519c01e5 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2345,15 +2345,15 @@ int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
}
/**
- * spi_nor_spimem_check_op - check if the operation is supported
- * by controller
+ * spi_nor_spimem_check_read_pp_op - check if a read or a page program operation is
+ * supported by controller
*@nor: pointer to a 'struct spi_nor'
*@op: pointer to op template to be checked
*
* Returns 0 if operation is supported, -EOPNOTSUPP otherwise.
*/
-static int spi_nor_spimem_check_op(struct spi_nor *nor,
- struct spi_mem_op *op)
+static int spi_nor_spimem_check_read_pp_op(struct spi_nor *nor,
+ struct spi_mem_op *op)
{
/*
* First test with 4 address bytes. The opcode itself might
@@ -2396,7 +2396,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
if (spi_nor_protocol_is_dtr(nor->read_proto))
op.dummy.nbytes *= 2;
- return spi_nor_spimem_check_op(nor, &op);
+ return spi_nor_spimem_check_read_pp_op(nor, &op);
}
/**
@@ -2414,7 +2414,7 @@ static int spi_nor_spimem_check_pp(struct spi_nor *nor,
spi_nor_spimem_setup_op(nor, &op, pp->proto);
- return spi_nor_spimem_check_op(nor, &op);
+ return spi_nor_spimem_check_read_pp_op(nor, &op);
}
/**
@@ -2466,7 +2466,7 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
- if (spi_nor_spimem_check_op(nor, &op))
+ if (!spi_mem_supports_op(nor->spimem, &op))
nor->flags |= SNOR_F_NO_READ_CR;
}
}
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 8adbec7c5084..8967b65f6d84 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -34,11 +34,17 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
for (; hash_index != RLB_NULL_INDEX;
hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
- seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
- &client_info->ip_src,
- &client_info->ip_dst,
- &client_info->mac_dst,
- client_info->slave->dev->name);
+ if (client_info->slave)
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst,
+ client_info->slave->dev->name);
+ else
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst);
}
spin_unlock_bh(&bond->mode_lock);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 707419270ebf..33f414d03ab9 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1530,9 +1530,11 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
return ret;
}
-static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int bond_header_parse(const struct sk_buff *skb,
+ const struct net_device *dev,
+ unsigned char *haddr)
{
- struct bonding *bond = netdev_priv(skb->dev);
+ struct bonding *bond = netdev_priv(dev);
const struct header_ops *slave_ops;
struct slave *slave;
int ret = 0;
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
if (slave) {
slave_ops = READ_ONCE(slave->dev->header_ops);
if (slave_ops && slave_ops->parse)
- ret = slave_ops->parse(skb, haddr);
+ ret = slave_ops->parse(skb, slave->dev, haddr);
}
rcu_read_unlock();
return ret;
diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
index 0498198a4696..766d455950f5 100644
--- a/drivers/net/can/dev/netlink.c
+++ b/drivers/net/can/dev/netlink.c
@@ -601,7 +601,9 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
/* We need synchronization with dev->stop() */
ASSERT_RTNL();
- can_ctrlmode_changelink(dev, data, extack);
+ err = can_ctrlmode_changelink(dev, data, extack);
+ if (err)
+ return err;
if (data[IFLA_CAN_BITTIMING]) {
struct can_bittiming bt;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index bb7782582f40..0d0190ae094a 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1225,7 +1225,11 @@ static int mcp251x_open(struct net_device *net)
}
mutex_lock(&priv->mcp_lock);
- mcp251x_power_enable(priv->transceiver, 1);
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret));
+ goto out_close_candev;
+ }
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -1272,6 +1276,7 @@ out_free_irq:
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
+out_close_candev:
close_candev(net);
mutex_unlock(&priv->mcp_lock);
if (release_irq)
@@ -1516,11 +1521,25 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
+ int ret = 0;
- if (priv->after_suspend & AFTER_SUSPEND_POWER)
- mcp251x_power_enable(priv->power, 1);
- if (priv->after_suspend & AFTER_SUSPEND_UP)
- mcp251x_power_enable(priv->transceiver, 1);
+ if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+ ret = mcp251x_power_enable(priv->power, 1);
+ if (ret) {
+ dev_err(dev, "failed to restore power: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(dev, "failed to restore transceiver power: %pe\n", ERR_PTR(ret));
+ if (priv->after_suspend & AFTER_SUSPEND_POWER)
+ mcp251x_power_enable(priv->power, 0);
+ return ret;
+ }
+ }
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
queue_work(priv->wq, &priv->restart_work);
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 960685596093..de3efa3ce9a7 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -980,15 +980,19 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("%s: failed to software reset switch\n", __func__);
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
}
bcm_sf2_crossbar_setup(priv);
ret = bcm_sf2_cfp_resume(ds);
- if (ret)
+ if (ret) {
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
-
+ }
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, true);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 62bcbbbe2a95..56cf9a926a83 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -3083,7 +3083,6 @@ static void airoha_remove(struct platform_device *pdev)
if (!port)
continue;
- airoha_dev_stop(port->dev);
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 42dbe8f93231..5724f8f2defd 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -227,7 +227,9 @@ static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr,
if (!dev)
return -ENODEV;
+ rcu_read_lock();
err = dev_fill_forward_path(dev, addr, &stack);
+ rcu_read_unlock();
if (err)
return err;
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index cd7dddeb91dd..9787c1857e13 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -25,7 +25,7 @@ config B44
select SSB
select MII
select PHYLIB
- select FIXED_PHY if BCM47XX
+ select FIXED_PHY
help
If you have a network (Ethernet) controller of this type, say Y
or M here.
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
index aa6d8606849f..972474893a6b 100644
--- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
@@ -1152,12 +1152,6 @@ void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en)
}
}
-static void bcmasp_wol_irq_destroy(struct bcmasp_priv *priv)
-{
- if (priv->wol_irq > 0)
- free_irq(priv->wol_irq, priv);
-}
-
static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en)
{
u32 reg, phy_lpi_overwrite;
@@ -1255,7 +1249,7 @@ static int bcmasp_probe(struct platform_device *pdev)
if (priv->irq <= 0)
return -EINVAL;
- priv->clk = devm_clk_get_optional_enabled(dev, "sw_asp");
+ priv->clk = devm_clk_get_optional(dev, "sw_asp");
if (IS_ERR(priv->clk))
return dev_err_probe(dev, PTR_ERR(priv->clk),
"failed to request clock\n");
@@ -1283,6 +1277,10 @@ static int bcmasp_probe(struct platform_device *pdev)
bcmasp_set_pdata(priv, pdata);
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to start clock\n");
+
/* Enable all clocks to ensure successful probing */
bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
@@ -1294,8 +1292,10 @@ static int bcmasp_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, priv->irq, bcmasp_isr, 0,
pdev->name, priv);
- if (ret)
- return dev_err_probe(dev, ret, "failed to request ASP interrupt: %d", ret);
+ if (ret) {
+ dev_err(dev, "Failed to request ASP interrupt: %d", ret);
+ goto err_clock_disable;
+ }
/* Register mdio child nodes */
of_platform_populate(dev->of_node, bcmasp_mdio_of_match, NULL, dev);
@@ -1307,13 +1307,17 @@ static int bcmasp_probe(struct platform_device *pdev)
priv->mda_filters = devm_kcalloc(dev, priv->num_mda_filters,
sizeof(*priv->mda_filters), GFP_KERNEL);
- if (!priv->mda_filters)
- return -ENOMEM;
+ if (!priv->mda_filters) {
+ ret = -ENOMEM;
+ goto err_clock_disable;
+ }
priv->net_filters = devm_kcalloc(dev, priv->num_net_filters,
sizeof(*priv->net_filters), GFP_KERNEL);
- if (!priv->net_filters)
- return -ENOMEM;
+ if (!priv->net_filters) {
+ ret = -ENOMEM;
+ goto err_clock_disable;
+ }
bcmasp_core_init_filters(priv);
@@ -1322,7 +1326,8 @@ static int bcmasp_probe(struct platform_device *pdev)
ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports");
if (!ports_node) {
dev_warn(dev, "No ports found\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_clock_disable;
}
i = 0;
@@ -1344,8 +1349,6 @@ static int bcmasp_probe(struct platform_device *pdev)
*/
bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
- clk_disable_unprepare(priv->clk);
-
/* Now do the registration of the network ports which will take care
* of managing the clock properly.
*/
@@ -1358,13 +1361,16 @@ static int bcmasp_probe(struct platform_device *pdev)
count++;
}
+ clk_disable_unprepare(priv->clk);
+
dev_info(dev, "Initialized %d port(s)\n", count);
return ret;
err_cleanup:
- bcmasp_wol_irq_destroy(priv);
bcmasp_remove_intfs(priv);
+err_clock_disable:
+ clk_disable_unprepare(priv->clk);
return ret;
}
@@ -1376,7 +1382,6 @@ static void bcmasp_remove(struct platform_device *pdev)
if (!priv)
return;
- bcmasp_wol_irq_destroy(priv);
bcmasp_remove_intfs(priv);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index c426a41c3663..0751c0e4581a 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -2929,6 +2929,8 @@ static int bnxt_async_event_process(struct bnxt *bp,
u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2);
+ if (type >= ARRAY_SIZE(bp->bs_trace))
+ goto async_event_process_exit;
bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
goto async_event_process_exit;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 9a41b9e0423c..a97d651130df 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2146,7 +2146,7 @@ enum board_idx {
};
#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc)
-#define BNXT_TRACE_MAX 11
+#define BNXT_TRACE_MAX (DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE + 1)
struct bnxt_bs_trace_info {
u8 *magic_byte;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 8fb551288298..96d5d4f7f51f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -123,7 +123,7 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
& RBUF_STATUS_WOL)) {
retries++;
- if (retries > 5) {
+ if (retries > 50) {
netdev_crit(dev, "polling wol mode timeout\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 2328fce33644..21a5dd342724 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -17029,6 +17029,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
return err;
}
+static int tg3_is_default_mac_address(u8 *addr)
+{
+ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
+
+ return ether_addr_equal(default_mac_address, addr);
+}
+
static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
{
u32 hi, lo, mac_offset;
@@ -17102,6 +17109,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
if (!is_valid_ether_addr(addr))
return -EINVAL;
+
+ if (tg3_is_default_mac_address(addr))
+ return device_get_mac_address(&tp->pdev->dev, addr);
+
return 0;
}
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index f290d608b409..99e7d5cf3786 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -1071,7 +1071,7 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budge
}
if (tx_skb->skb) {
- napi_consume_skb(tx_skb->skb, budget);
+ dev_consume_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
}
@@ -2669,6 +2669,14 @@ static void macb_init_tieoff(struct macb *bp)
desc->ctrl = 0;
}
+static void gem_init_rx_ring(struct macb_queue *queue)
+{
+ queue->rx_tail = 0;
+ queue->rx_prepared_head = 0;
+
+ gem_rx_refill(queue);
+}
+
static void gem_init_rings(struct macb *bp)
{
struct macb_queue *queue;
@@ -2686,10 +2694,7 @@ static void gem_init_rings(struct macb *bp)
queue->tx_head = 0;
queue->tx_tail = 0;
- queue->rx_tail = 0;
- queue->rx_prepared_head = 0;
-
- gem_rx_refill(queue);
+ gem_init_rx_ring(queue);
}
macb_init_tieoff(bp);
@@ -3219,7 +3224,7 @@ static void gem_get_ethtool_stats(struct net_device *dev,
spin_lock_irq(&bp->stats_lock);
gem_update_stats(bp);
memcpy(data, &bp->ethtool_stats, sizeof(u64)
- * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES));
+ * (GEM_STATS_LEN + QUEUE_STATS_LEN * bp->num_queues));
spin_unlock_irq(&bp->stats_lock);
}
@@ -3978,6 +3983,9 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
struct macb *bp = netdev_priv(netdev);
int ret;
+ if (!(netdev->hw_features & NETIF_F_NTUPLE))
+ return -EOPNOTSUPP;
+
switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS:
if ((cmd->fs.location >= bp->max_tuples)
@@ -5768,9 +5776,9 @@ static int __maybe_unused macb_suspend(struct device *dev)
struct macb_queue *queue;
struct in_device *idev;
unsigned long flags;
+ u32 tmp, ifa_local;
unsigned int q;
int err;
- u32 tmp;
if (!device_may_wakeup(&bp->dev->dev))
phy_exit(bp->phy);
@@ -5779,14 +5787,21 @@ static int __maybe_unused macb_suspend(struct device *dev)
return 0;
if (bp->wol & MACB_WOL_ENABLED) {
- /* Check for IP address in WOL ARP mode */
- idev = __in_dev_get_rcu(bp->dev);
- if (idev)
- ifa = rcu_dereference(idev->ifa_list);
- if ((bp->wolopts & WAKE_ARP) && !ifa) {
- netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n");
- return -EOPNOTSUPP;
+ if (bp->wolopts & WAKE_ARP) {
+ /* Check for IP address in WOL ARP mode */
+ rcu_read_lock();
+ idev = __in_dev_get_rcu(bp->dev);
+ if (idev)
+ ifa = rcu_dereference(idev->ifa_list);
+ if (!ifa) {
+ rcu_read_unlock();
+ netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n");
+ return -EOPNOTSUPP;
+ }
+ ifa_local = be32_to_cpu(ifa->ifa_local);
+ rcu_read_unlock();
}
+
spin_lock_irqsave(&bp->lock, flags);
/* Disable Tx and Rx engines before disabling the queues,
@@ -5825,8 +5840,9 @@ static int __maybe_unused macb_suspend(struct device *dev)
if (bp->wolopts & WAKE_ARP) {
tmp |= MACB_BIT(ARP);
/* write IP address into register */
- tmp |= MACB_BFEXT(IP, be32_to_cpu(ifa->ifa_local));
+ tmp |= MACB_BFEXT(IP, ifa_local);
}
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Change interrupt handler and
* Enable WoL IRQ on queue 0
@@ -5839,11 +5855,12 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, GEM_BIT(WOL));
gem_writel(bp, WOL, tmp);
+ spin_unlock_irqrestore(&bp->lock, flags);
} else {
err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt,
IRQF_SHARED, netdev->name, bp->queues);
@@ -5851,13 +5868,13 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, MACB_BIT(WOL));
macb_writel(bp, WOL, tmp);
+ spin_unlock_irqrestore(&bp->lock, flags);
}
- spin_unlock_irqrestore(&bp->lock, flags);
enable_irq_wake(bp->queues[0].irq);
}
@@ -5924,6 +5941,8 @@ static int __maybe_unused macb_resume(struct device *dev)
queue_readl(bp->queues, ISR);
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(bp->queues, ISR, -1);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
/* Replace interrupt handler on queue 0 */
devm_free_irq(dev, bp->queues[0].irq, bp->queues);
err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
@@ -5932,10 +5951,8 @@ static int __maybe_unused macb_resume(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
- spin_unlock_irqrestore(&bp->lock, flags);
disable_irq_wake(bp->queues[0].irq);
@@ -5947,8 +5964,18 @@ static int __maybe_unused macb_resume(struct device *dev)
rtnl_unlock();
}
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
+ macb_init_buffers(bp);
+
for (q = 0, queue = bp->queues; q < bp->num_queues;
++q, ++queue) {
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
+ if (macb_is_gem(bp))
+ gem_init_rx_ring(queue);
+ else
+ macb_init_rx_ring(queue);
+ }
+
napi_enable(&queue->napi_rx);
napi_enable(&queue->napi_tx);
}
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index c9e77819196e..d91f7b1aa39c 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -357,8 +357,10 @@ void gem_ptp_remove(struct net_device *ndev)
{
struct macb *bp = netdev_priv(ndev);
- if (bp->ptp_clock)
+ if (bp->ptp_clock) {
ptp_clock_unregister(bp->ptp_clock);
+ bp->ptp_clock = NULL;
+ }
gem_ptp_clear_timer(bp);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index fed89d4f1e1d..2fe140ddebb2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -813,6 +813,8 @@ static void enetc_get_ringparam(struct net_device *ndev,
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ ring->rx_max_pending = priv->rx_bd_count;
+ ring->tx_max_pending = priv->tx_bd_count;
ring->rx_pending = priv->rx_bd_count;
ring->tx_pending = priv->tx_bd_count;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index ab67c709d5a0..1cd1f3f2930a 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -313,14 +313,13 @@ static int iavf_get_sset_count(struct net_device *netdev, int sset)
{
/* Report the maximum number queues, even if not every queue is
* currently configured. Since allocation of queues is in pairs,
- * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set
- * at device creation and never changes.
+ * use netdev->num_tx_queues * 2. The num_tx_queues is set at
+ * device creation and never changes.
*/
if (sset == ETH_SS_STATS)
return IAVF_STATS_LEN +
- (IAVF_QUEUE_STATS_LEN * 2 *
- netdev->real_num_tx_queues);
+ (IAVF_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues);
else
return -EINVAL;
}
@@ -345,19 +344,19 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
rcu_read_lock();
- /* As num_active_queues describe both tx and rx queues, we can use
- * it to iterate over rings' stats.
+ /* Use num_tx_queues to report stats for the maximum number of queues.
+ * Queues beyond num_active_queues will report zero.
*/
- for (i = 0; i < adapter->num_active_queues; i++) {
- struct iavf_ring *ring;
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ struct iavf_ring *tx_ring = NULL, *rx_ring = NULL;
- /* Tx rings stats */
- ring = &adapter->tx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ if (i < adapter->num_active_queues) {
+ tx_ring = &adapter->tx_rings[i];
+ rx_ring = &adapter->rx_rings[i];
+ }
- /* Rx rings stats */
- ring = &adapter->rx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ iavf_add_queue_stats(&data, tx_ring);
+ iavf_add_queue_stats(&data, rx_ring);
}
rcu_read_unlock();
}
@@ -376,9 +375,9 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
iavf_add_stat_strings(&data, iavf_gstrings_stats);
/* Queues are always allocated in pairs, so we just use
- * real_num_tx_queues for both Tx and Rx queues.
+ * num_tx_queues for both Tx and Rx queues.
*/
- for (i = 0; i < netdev->real_num_tx_queues; i++) {
+ for (i = 0; i < netdev->num_tx_queues; i++) {
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
"tx", i);
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 7925ee152c76..dad001abc908 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -757,10 +757,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
- /* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed.
- * We can safely only change the state here.
+ /* Re-add the filter since we cannot tell whether the
+ * pending delete has already been processed by the PF.
+ * A duplicate add is harmless.
*/
- f->state = IAVF_VLAN_ACTIVE;
+ f->state = IAVF_VLAN_ADD;
+ iavf_schedule_aq_request(adapter,
+ IAVF_FLAG_AQ_ADD_VLAN_FILTER);
}
clearout:
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 2b2b22af42be..eb3a48330cc1 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -840,6 +840,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid)
}
/**
+ * ice_get_max_txq - return the maximum number of Tx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Tx queues
+ */
+static inline int ice_get_max_txq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
+}
+
+/**
+ * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Rx queues
+ */
+static inline int ice_get_max_rxq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
+}
+
+/**
* ice_get_main_vsi - Get the PF VSI
* @pf: PF instance
*
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 301947d53ede..e6a20af6f63d 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1930,6 +1930,17 @@ __ice_get_ethtool_stats(struct net_device *netdev,
int i = 0;
char *p;
+ if (ice_is_port_repr_netdev(netdev)) {
+ ice_update_eth_stats(vsi);
+
+ for (j = 0; j < ICE_VSI_STATS_LEN; j++) {
+ p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset;
+ data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ return;
+ }
+
ice_update_pf_stats(pf);
ice_update_vsi_stats(vsi);
@@ -1939,9 +1950,6 @@ __ice_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
- if (ice_is_port_repr_netdev(netdev))
- return;
-
/* populate per queue stats */
rcu_read_lock();
@@ -3774,24 +3782,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
}
/**
- * ice_get_max_txq - return the maximum number of Tx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_txq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
-}
-
-/**
- * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_rxq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
-}
-
-/**
* ice_get_combined_cnt - return the current number of combined channels
* @vsi: PF VSI pointer
*
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index e7308e381e2f..3c36e3641b9e 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4699,8 +4699,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
- netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
- vsi->alloc_rxq);
+ netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back),
+ ice_get_max_rxq(vsi->back));
if (!netdev)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c
index 90f99443a922..096566c697f4 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.c
+++ b/drivers/net/ethernet/intel/ice/ice_repr.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice.h"
+#include "ice_lib.h"
#include "ice_eswitch.h"
#include "devlink/devlink.h"
#include "devlink/port.h"
@@ -67,7 +68,7 @@ ice_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
return;
vsi = repr->src_vsi;
- ice_update_vsi_stats(vsi);
+ ice_update_eth_stats(vsi);
eth_stats = &vsi->eth_stats;
stats->tx_packets = eth_stats->tx_unicast + eth_stats->tx_broadcast +
@@ -315,7 +316,7 @@ ice_repr_reg_netdev(struct net_device *netdev, const struct net_device_ops *ops)
static int ice_repr_ready_vf(struct ice_repr *repr)
{
- return !ice_check_vf_ready_for_cfg(repr->vf);
+ return ice_check_vf_ready_for_cfg(repr->vf);
}
static int ice_repr_ready_sf(struct ice_repr *repr)
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index b206fba092c8..ec1b75f039bb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -1066,7 +1066,7 @@ bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val);
int idpf_idc_init(struct idpf_adapter *adapter);
int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
enum iidc_function_type ftype);
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info);
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter);
void idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info *vdev_info);
void idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info *cdev_info);
void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index bd4785fb8d3e..7e4f4ac92653 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -470,10 +470,11 @@ err_privd_alloc:
/**
* idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s)
- * @cdev_info: IDC core device info pointer
+ * @adapter: driver private data structure
*/
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter)
{
+ struct iidc_rdma_core_dev_info *cdev_info = adapter->cdev_info;
struct iidc_rdma_priv_dev_info *privd;
if (!cdev_info)
@@ -485,6 +486,7 @@ void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
kfree(privd->mapped_mem_regions);
kfree(privd);
kfree(cdev_info);
+ adapter->cdev_info = NULL;
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 252259993022..f6b3b15364ff 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1860,13 +1860,13 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport,
idpf_queue_assign(HSPLIT_EN, q, hs);
idpf_queue_assign(RSC_EN, q, rsc);
- bufq_set->num_refillqs = num_rxq;
bufq_set->refillqs = kcalloc(num_rxq, swq_size,
GFP_KERNEL);
if (!bufq_set->refillqs) {
err = -ENOMEM;
goto err_alloc;
}
+ bufq_set->num_refillqs = num_rxq;
for (unsigned int k = 0; k < bufq_set->num_refillqs; k++) {
struct idpf_sw_queue *refillq =
&bufq_set->refillqs[k];
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index d5a877e1fef8..113ecfc16dd7 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -3668,7 +3668,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
idpf_ptp_release(adapter);
idpf_deinit_task(adapter);
- idpf_idc_deinit_core_aux_device(adapter->cdev_info);
+ idpf_idc_deinit_core_aux_device(adapter);
idpf_rel_rx_pt_lkup(adapter);
idpf_intr_rel(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index a427f05814c1..17236813965d 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -781,6 +781,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void igc_ptp_tx_hang(struct igc_adapter *adapter);
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter,
+ u16 queue_id);
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index b2e8d0c0f827..72bc5128d8b8 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -264,6 +264,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
/* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
+
+ /* Clear any lingering XSK TX timestamp requests */
+ if (test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags)) {
+ struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
+
+ igc_ptp_clear_xsk_tx_tstamp_queue(adapter, tx_ring->queue_index);
+ }
}
/**
@@ -1730,11 +1737,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
- if (skb->len < 17) {
- if (skb_padto(skb, 17))
- return NETDEV_TX_OK;
- skb->len = 17;
- }
+ if (skb_put_padto(skb, 17))
+ return NETDEV_TX_OK;
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
}
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 44ee19386766..3d6b2264164a 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -577,6 +577,39 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
+/**
+ * igc_ptp_clear_xsk_tx_tstamp_queue - Clear pending XSK TX timestamps for a queue
+ * @adapter: Board private structure
+ * @queue_id: TX queue index to clear timestamps for
+ *
+ * Iterates over all TX timestamp registers and releases any pending
+ * timestamp requests associated with the given TX queue. This is
+ * called when an XDP pool is being disabled to ensure no stale
+ * timestamp references remain.
+ */
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter, u16 queue_id)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
+
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+ if (tstamp->buffer_type != IGC_TX_BUFFER_TYPE_XSK)
+ continue;
+ if (tstamp->xsk_queue_index != queue_id)
+ continue;
+ if (!tstamp->xsk_tx_buffer)
+ continue;
+
+ igc_ptp_free_tx_buffer(adapter, tstamp);
+ }
+
+ spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
+}
+
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/libie/fwlog.c b/drivers/net/ethernet/intel/libie/fwlog.c
index 4d0c8370386b..96bba57c8a5b 100644
--- a/drivers/net/ethernet/intel/libie/fwlog.c
+++ b/drivers/net/ethernet/intel/libie/fwlog.c
@@ -433,17 +433,21 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
if (module < 0) {
dev_info(dev, "unknown module\n");
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
cnt = sscanf(cmd_buf, "%s", user_val);
- if (cnt != 1)
- return -EINVAL;
+ if (cnt != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
if (log_level < 0) {
dev_info(dev, "unknown log level '%s'\n", user_val);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
@@ -458,6 +462,9 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
fwlog->cfg.module_entries[i].log_level = log_level;
}
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtos16(user_val, 0, &nr_messages);
- if (ret)
- return ret;
+ if (ret) {
+ count = ret;
+ goto free_cmd_buf;
+ }
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
fwlog->cfg.log_resolution = nr_messages;
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtobool(user_val, &enable);
if (ret)
@@ -624,6 +641,8 @@ enable_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
index = sysfs_match_string(libie_fwlog_log_size, user_val);
if (index < 0) {
@@ -712,6 +733,8 @@ log_size_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index d1b8650cb4b4..f442b874bb59 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -5016,7 +5016,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
if (priv->percpu_pools)
numbufs = port->nrxqs * 2;
- if (change_percpu)
+ if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, false);
for (i = 0; i < numbufs; i++)
@@ -5041,7 +5041,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
mvpp2_open(port->dev);
}
- if (change_percpu)
+ if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, true);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
index f8eaaf37963b..abcbd38db9db 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits;
u32 rx_mapped_id;
+ u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
};
struct mlx5_accel_pol_xfrm_attrs {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
index 33344e00719b..05faad5083d9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
@@ -310,10 +310,11 @@ static void mlx5e_ipsec_aso_update(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_aso_query(sa_entry, data);
}
-static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
- u32 mode_param)
+static void
+mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
+ u32 mode_param,
+ struct mlx5_accel_esp_xfrm_attrs *attrs)
{
- struct mlx5_accel_esp_xfrm_attrs attrs = {};
struct mlx5_wqe_aso_ctrl_seg data = {};
if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) {
@@ -323,18 +324,7 @@ static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
sa_entry->esn_state.overlap = 1;
}
- mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
-
- /* It is safe to execute the modify below unlocked since the only flows
- * that could affect this HW object, are create, destroy and this work.
- *
- * Creation flow can't co-exist with this modify work, the destruction
- * flow would cancel this work, and this work is a single entity that
- * can't conflict with it self.
- */
- spin_unlock_bh(&sa_entry->x->lock);
- mlx5_accel_esp_modify_xfrm(sa_entry, &attrs);
- spin_lock_bh(&sa_entry->x->lock);
+ mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, attrs);
data.data_offset_condition_operand =
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
@@ -370,20 +360,18 @@ static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
{
struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
- struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
- struct mlx5e_ipsec_aso *aso = ipsec->aso;
bool soft_arm, hard_arm;
u64 hard_cnt;
lockdep_assert_held(&sa_entry->x->lock);
- soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm);
- hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm);
+ soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
+ hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
if (!soft_arm && !hard_arm)
/* It is not lifetime event */
return;
- hard_cnt = MLX5_GET(ipsec_aso, aso->ctx, remove_flow_pkt_cnt);
+ hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
if (!hard_cnt || hard_arm) {
/* It is possible to see packet counter equal to zero without
* hard limit event armed. Such situation can be if packet
@@ -453,11 +441,11 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
struct mlx5e_ipsec_work *work =
container_of(_work, struct mlx5e_ipsec_work, work);
struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
+ struct mlx5_accel_esp_xfrm_attrs tmp = {};
struct mlx5_accel_esp_xfrm_attrs *attrs;
- struct mlx5e_ipsec_aso *aso;
+ bool need_modify = false;
int ret;
- aso = sa_entry->ipsec->aso;
attrs = &sa_entry->attrs;
spin_lock_bh(&sa_entry->x->lock);
@@ -465,18 +453,22 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
if (ret)
goto unlock;
+ if (attrs->lft.soft_packet_limit != XFRM_INF)
+ mlx5e_ipsec_handle_limits(sa_entry);
+
if (attrs->replay_esn.trigger &&
- !MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
- u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
+ !MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
+ u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
+ mode_parameter);
- mlx5e_ipsec_update_esn_state(sa_entry, mode_param);
+ mlx5e_ipsec_update_esn_state(sa_entry, mode_param, &tmp);
+ need_modify = true;
}
- if (attrs->lft.soft_packet_limit != XFRM_INF)
- mlx5e_ipsec_handle_limits(sa_entry);
-
unlock:
spin_unlock_bh(&sa_entry->x->lock);
+ if (need_modify)
+ mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
kfree(work);
}
@@ -629,6 +621,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
/* We are in atomic context */
udelay(10);
} while (ret && time_is_after_jiffies(expires));
+ if (!ret)
+ memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
spin_unlock_bh(&aso->lock);
return ret;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
index 26178d0bac92..faccc60fc93a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
@@ -1489,24 +1489,24 @@ out:
return err;
}
-static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
+static u32 mlx5_esw_qos_lag_link_speed_get(struct mlx5_core_dev *mdev,
+ bool take_rtnl)
{
struct ethtool_link_ksettings lksettings;
struct net_device *slave, *master;
u32 speed = SPEED_UNKNOWN;
- /* Lock ensures a stable reference to master and slave netdevice
- * while port speed of master is queried.
- */
- ASSERT_RTNL();
-
slave = mlx5_uplink_netdev_get(mdev);
if (!slave)
goto out;
+ if (take_rtnl)
+ rtnl_lock();
master = netdev_master_upper_dev_get(slave);
if (master && !__ethtool_get_link_ksettings(master, &lksettings))
speed = lksettings.base.speed;
+ if (take_rtnl)
+ rtnl_unlock();
out:
mlx5_uplink_netdev_put(mdev, slave);
@@ -1514,20 +1514,15 @@ out:
}
static int mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev *mdev, u32 *link_speed_max,
- bool hold_rtnl_lock, struct netlink_ext_ack *extack)
+ bool take_rtnl,
+ struct netlink_ext_ack *extack)
{
int err;
if (!mlx5_lag_is_active(mdev))
goto skip_lag;
- if (hold_rtnl_lock)
- rtnl_lock();
-
- *link_speed_max = mlx5_esw_qos_lag_link_speed_get_locked(mdev);
-
- if (hold_rtnl_lock)
- rtnl_unlock();
+ *link_speed_max = mlx5_esw_qos_lag_link_speed_get(mdev, take_rtnl);
if (*link_speed_max != (u32)SPEED_UNKNOWN)
return 0;
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index a3845edf0e48..f0b5dd752f08 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -3053,6 +3053,11 @@ static void lan743x_phylink_mac_link_up(struct phylink_config *config,
else if (speed == SPEED_100)
mac_cr |= MAC_CR_CFG_L_;
+ if (duplex == DUPLEX_FULL)
+ mac_cr |= MAC_CR_DPX_;
+ else
+ mac_cr &= ~MAC_CR_DPX_;
+
lan743x_csr_write(adapter, MAC_CR, mac_cr);
lan743x_ptp_update_latency(adapter, speed);
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index ba3467f1e2ea..48a9acea4ab6 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -814,9 +814,6 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
gc->max_num_cqs = 0;
}
- kfree(hwc->caller_ctx);
- hwc->caller_ctx = NULL;
-
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);
@@ -826,6 +823,9 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
if (hwc->cq)
mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
+ kfree(hwc->caller_ctx);
+ hwc->caller_ctx = NULL;
+
mana_gd_free_res_map(&hwc->inflight_msg_res);
hwc->num_inflight_msg = 0;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 9017e806ecda..dca62fb9a3a9 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -3425,6 +3425,7 @@ static int add_adev(struct gdma_dev *gd, const char *name)
struct auxiliary_device *adev;
struct mana_adev *madev;
int ret;
+ int id;
madev = kzalloc_obj(*madev);
if (!madev)
@@ -3434,7 +3435,8 @@ static int add_adev(struct gdma_dev *gd, const char *name)
ret = mana_adev_idx_alloc();
if (ret < 0)
goto idx_fail;
- adev->id = ret;
+ id = ret;
+ adev->id = id;
adev->name = name;
adev->dev.parent = gd->gdma_context->dev;
@@ -3460,7 +3462,7 @@ add_fail:
auxiliary_device_uninit(adev);
init_fail:
- mana_adev_idx_free(adev->id);
+ mana_adev_idx_free(id);
idx_fail:
kfree(madev);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 8d040e611d5a..637e635bbf03 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1719,13 +1719,18 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
if (ether_addr_equal(netdev->dev_addr, mac))
return 0;
- err = ionic_program_mac(lif, mac);
- if (err < 0)
- return err;
+ /* Only program macs for virtual functions to avoid losing the permanent
+ * Mac across warm reset/reboot.
+ */
+ if (lif->ionic->pdev->is_virtfn) {
+ err = ionic_program_mac(lif, mac);
+ if (err < 0)
+ return err;
- if (err > 0)
- netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
- __func__);
+ if (err > 0)
+ netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
+ __func__);
+ }
err = eth_prepare_mac_addr_change(netdev, addr);
if (err)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index 0cf9dfe0fa36..fd4e7622f123 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -962,7 +962,6 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
pkt_len -= 4;
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
psdata = cppi5_hdesc_get_psdata(desc_rx);
- k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
count++;
xsk_buff_set_size(xdp, pkt_len);
xsk_buff_dma_sync_for_cpu(xdp);
@@ -988,6 +987,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
emac_dispatch_skb_zc(emac, xdp, psdata);
xsk_buff_free(xdp);
}
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
}
if (xdp_status & ICSSG_XDP_REDIR)
@@ -1057,7 +1057,6 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
/* firmware adds 4 CRC bytes, strip them */
pkt_len -= 4;
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
- k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
/* if allocation fails we drop the packet but push the
* descriptor back to the ring with old page to prevent a stall
@@ -1075,6 +1074,11 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
*xdp_state = emac_run_xdp(emac, &xdp, &pkt_len);
+ if (*xdp_state == ICSSG_XDP_CONSUMED) {
+ page_pool_recycle_direct(pool, page);
+ goto requeue;
+ }
+
if (*xdp_state != ICSSG_XDP_PASS)
goto requeue;
headroom = xdp.data - xdp.data_hard_start;
@@ -1110,6 +1114,7 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
ndev->stats.rx_packets++;
requeue:
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
/* queue another RX DMA */
ret = prueth_dma_rx_push_mapped(emac, &emac->rx_chns, new_page,
PRUETH_MAX_PKT_SIZE);
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 5ec028a00c62..3645ebde049a 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -109,8 +109,11 @@ static int nsim_forward_skb(struct net_device *tx_dev,
int ret;
ret = __dev_forward_skb(rx_dev, skb);
- if (ret)
+ if (ret) {
+ if (psp_ext)
+ __skb_ext_put(psp_ext);
return ret;
+ }
nsim_psp_handle_ext(skb, psp_ext);
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index b7282f5c9632..120aeb539d9f 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -2058,6 +2058,68 @@ static const struct ethtool_ops team_ethtool_ops = {
* rt netlink interface
***********************/
+/* For tx path we need a linkup && enabled port and for parse any port
+ * suffices.
+ */
+static struct team_port *team_header_port_get_rcu(struct team *team,
+ bool txable)
+{
+ struct team_port *port;
+
+ list_for_each_entry_rcu(port, &team->port_list, list) {
+ if (!txable || team_port_txable(port))
+ return port;
+ }
+
+ return NULL;
+}
+
+static int team_header_create(struct sk_buff *skb, struct net_device *team_dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
+{
+ struct team *team = netdev_priv(team_dev);
+ const struct header_ops *port_ops;
+ struct team_port *port;
+ int ret = 0;
+
+ rcu_read_lock();
+ port = team_header_port_get_rcu(team, true);
+ if (port) {
+ port_ops = READ_ONCE(port->dev->header_ops);
+ if (port_ops && port_ops->create)
+ ret = port_ops->create(skb, port->dev,
+ type, daddr, saddr, len);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static int team_header_parse(const struct sk_buff *skb,
+ const struct net_device *team_dev,
+ unsigned char *haddr)
+{
+ struct team *team = netdev_priv(team_dev);
+ const struct header_ops *port_ops;
+ struct team_port *port;
+ int ret = 0;
+
+ rcu_read_lock();
+ port = team_header_port_get_rcu(team, false);
+ if (port) {
+ port_ops = READ_ONCE(port->dev->header_ops);
+ if (port_ops && port_ops->parse)
+ ret = port_ops->parse(skb, port->dev, haddr);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static const struct header_ops team_header_ops = {
+ .create = team_header_create,
+ .parse = team_header_parse,
+};
+
static void team_setup_by_port(struct net_device *dev,
struct net_device *port_dev)
{
@@ -2066,7 +2128,8 @@ static void team_setup_by_port(struct net_device *dev,
if (port_dev->type == ARPHRD_ETHER)
dev->header_ops = team->header_ops_cache;
else
- dev->header_ops = port_dev->header_ops;
+ dev->header_ops = port_dev->header_ops ?
+ &team_header_ops : NULL;
dev->type = port_dev->type;
dev->hard_header_len = port_dev->hard_header_len;
dev->needed_headroom = port_dev->needed_headroom;
diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
index a5f93b6c4482..fa5cab9d3e55 100644
--- a/drivers/net/tun_vnet.h
+++ b/drivers/net/tun_vnet.h
@@ -244,7 +244,7 @@ tun_vnet_hdr_tnl_from_skb(unsigned int flags,
if (virtio_net_hdr_tnl_from_skb(skb, tnl_hdr, has_tnl_offload,
tun_vnet_is_little_endian(flags),
- vlan_hlen, true)) {
+ vlan_hlen, true, false)) {
struct virtio_net_hdr_v1 *hdr = &tnl_hdr->hash_hdr.hdr;
struct skb_shared_info *sinfo = skb_shinfo(skb);
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index cbffa9ae1bb6..dd53f413c38f 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -1395,14 +1395,14 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
SFR_MEDIUM_STATUS_MODE, 2, &reg16);
- aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
- WOL_CFG_SIZE, &wol_cfg);
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write_cmd_nopm(dev, AQ_WOL_CFG, 0, 0,
+ WOL_CFG_SIZE, &wol_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
} else {
aqc111_data->phy_cfg |= AQ_LOW_POWER;
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
/* Disable RX path */
aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7057c6c0cfc6..bb9929727eb9 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1656,6 +1656,7 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp16 *ndp16;
int ret = -EINVAL;
+ size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1675,8 +1676,8 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe16));
ret--; /* we process NDP entries except for the last one */
- if ((sizeof(struct usb_cdc_ncm_ndp16) +
- ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
+ ndp_len = struct_size_t(struct usb_cdc_ncm_ndp16, dpe16, ret);
+ if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}
@@ -1692,6 +1693,7 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp32 *ndp32;
int ret = -EINVAL;
+ size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1711,8 +1713,8 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe32));
ret--; /* we process NDP entries except for the last one */
- if ((sizeof(struct usb_cdc_ncm_ndp32) +
- ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
+ ndp_len = struct_size_t(struct usb_cdc_ncm_ndp32, dpe32, ret);
+ if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 72d6a9c6a5a2..ab2108ee206a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3267,8 +3267,12 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
struct virtio_net_hdr_v1_hash_tunnel *hdr;
int num_sg;
unsigned hdr_len = vi->hdr_len;
+ bool feature_hdrlen;
bool can_push;
+ feature_hdrlen = virtio_has_feature(vi->vdev,
+ VIRTIO_NET_F_GUEST_HDRLEN);
+
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
/* Make sure it's safe to cast between formats */
@@ -3288,7 +3292,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl,
virtio_is_little_endian(vi->vdev), 0,
- false))
+ false, feature_hdrlen))
return -EPROTO;
if (vi->mergeable_rx_bufs)
@@ -3351,6 +3355,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Don't wait up for transmitted skbs to be freed. */
if (!use_napi) {
skb_orphan(skb);
+ skb_dst_drop(skb);
nf_reset_ct(skb);
}
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 121e51ce1bc0..8b27d8cc086a 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1006,7 +1006,7 @@ static void ath_scan_send_probe(struct ath_softc *sc,
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
- goto error;
+ return;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
if (ath_tx_start(sc->hw, skb, &txctl))
@@ -1119,10 +1119,8 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
- dev_kfree_skb_any(skb);
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
return false;
- }
break;
default:
return false;
diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c
index ff9176cdee3d..63b0447e55c1 100644
--- a/drivers/net/wireless/mediatek/mt76/scan.c
+++ b/drivers/net/wireless/mediatek/mt76/scan.c
@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_lock();
- if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
- ieee80211_free_txskb(phy->hw, skb);
+ if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
goto out;
- }
info = IEEE80211_SKB_CB(skb);
if (req->no_cck)
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 6241866d39df..75cfbcfb7626 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -210,7 +210,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (skb_headroom(skb) < (total_len - skb->len) &&
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
wl1271_free_tx_id(wl, id);
- return -EAGAIN;
+ return -ENOMEM;
}
desc = skb_push(skb, total_len - skb->len);
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index e89173f91637..1b6e55eb81a2 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -3021,7 +3021,6 @@ static void hw_scan_work(struct work_struct *work)
hwsim->tmp_chan->band,
NULL)) {
rcu_read_unlock();
- kfree_skb(probe);
continue;
}
@@ -6489,7 +6488,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
struct cfg80211_pmsr_capabilities *pmsr_capa;
- pmsr_capa = kmalloc_obj(*pmsr_capa);
+ pmsr_capa = kzalloc_obj(*pmsr_capa);
if (!pmsr_capa) {
ret = -ENOMEM;
goto out_free;
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 6a5ce8ff91f0..b3d34433bd14 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *phy_id,
{
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
- gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
- gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index bd9621d3f73c..45b7d756e39a 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -486,14 +486,15 @@ EXPORT_SYMBOL_GPL(nd_synchronize);
static void nd_async_device_register(void *d, async_cookie_t cookie)
{
struct device *dev = d;
+ struct device *parent = dev->parent;
if (device_add(dev) != 0) {
dev_err(dev, "%s: failed\n", __func__);
put_device(dev);
}
put_device(dev);
- if (dev->parent)
- put_device(dev->parent);
+ if (parent)
+ put_device(parent);
}
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 582938b7b4f1..33548935765e 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -894,6 +894,11 @@ static void pci_epf_test_bar_subrange_setup(struct pci_epf_test *epf_test,
dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret);
bar->submap = old_submap;
bar->num_submap = old_nsub;
+ ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar);
+ if (ret)
+ dev_warn(&epf->dev, "Failed to restore the original BAR mapping: %d\n",
+ ret);
+
kfree(submap);
goto err;
}
diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 6f7dea6746e0..97cff5b8ca88 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -268,6 +268,48 @@ err_power_off:
}
EXPORT_SYMBOL_GPL(pci_pwrctrl_power_on_devices);
+/*
+ * Check whether the pwrctrl device really needs to be created or not. The
+ * pwrctrl device will only be created if the node satisfies below requirements:
+ *
+ * 1. Presence of compatible property with "pci" prefix to match against the
+ * pwrctrl driver (AND)
+ * 2. At least one of the power supplies defined in the devicetree node of the
+ * device (OR) in the remote endpoint parent node to indicate pwrctrl
+ * requirement.
+ */
+static bool pci_pwrctrl_is_required(struct device_node *np)
+{
+ struct device_node *endpoint;
+ const char *compat;
+ int ret;
+
+ ret = of_property_read_string(np, "compatible", &compat);
+ if (ret < 0)
+ return false;
+
+ if (!strstarts(compat, "pci"))
+ return false;
+
+ if (of_pci_supply_present(np))
+ return true;
+
+ if (of_graph_is_present(np)) {
+ for_each_endpoint_of_node(np, endpoint) {
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_port_parent(endpoint);
+ if (remote) {
+ if (of_pci_supply_present(remote)) {
+ of_node_put(endpoint);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
static int pci_pwrctrl_create_device(struct device_node *np,
struct device *parent)
{
@@ -287,19 +329,7 @@ static int pci_pwrctrl_create_device(struct device_node *np,
return 0;
}
- /*
- * Sanity check to make sure that the node has the compatible property
- * to allow driver binding.
- */
- if (!of_property_present(np, "compatible"))
- return 0;
-
- /*
- * Check whether the pwrctrl device really needs to be created or not.
- * This is decided based on at least one of the power supplies defined
- * in the devicetree node of the device or the graph property.
- */
- if (!of_pci_supply_present(np) && !of_graph_is_present(np)) {
+ if (!pci_pwrctrl_is_required(np)) {
dev_dbg(parent, "Skipping OF node: %s\n", np->name);
return 0;
}
diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
index 0d0377283c37..c7e4beec160a 100644
--- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
+++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
@@ -68,13 +68,6 @@ static int pwrseq_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl)
return pwrseq_power_off(pwrseq->pwrseq);
}
-static void devm_pwrseq_pwrctrl_power_off(void *data)
-{
- struct pwrseq_pwrctrl *pwrseq = data;
-
- pwrseq_pwrctrl_power_off(&pwrseq->pwrctrl);
-}
-
static int pwrseq_pwrctrl_probe(struct platform_device *pdev)
{
const struct pwrseq_pwrctrl_pdata *pdata;
@@ -101,11 +94,6 @@ static int pwrseq_pwrctrl_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq),
"Failed to get the power sequencer\n");
- ret = devm_add_action_or_reset(dev, devm_pwrseq_pwrctrl_power_off,
- pwrseq);
- if (ret)
- return ret;
-
pwrseq->pwrctrl.power_on = pwrseq_pwrctrl_power_on;
pwrseq->pwrctrl.power_off = pwrseq_pwrctrl_power_off;
diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c
index 082af81efe25..b87639253ae2 100644
--- a/drivers/pci/pwrctrl/slot.c
+++ b/drivers/pci/pwrctrl/slot.c
@@ -63,7 +63,6 @@ static void devm_slot_pwrctrl_release(void *data)
{
struct slot_pwrctrl *slot = data;
- slot_pwrctrl_power_off(&slot->pwrctrl);
regulator_bulk_free(slot->num_supplies, slot->supplies);
}
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 02467dfd4fb0..1875d5b784f6 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -6,7 +6,7 @@
menu "PHY Subsystem"
config PHY_COMMON_PROPS
- bool
+ bool "PHY common properties" if KUNIT_ALL_TESTS
help
This parses properties common between generic PHYs and Ethernet PHYs.
@@ -16,8 +16,7 @@ config PHY_COMMON_PROPS
config PHY_COMMON_PROPS_TEST
tristate "KUnit tests for PHY common props" if !KUNIT_ALL_TESTS
- select PHY_COMMON_PROPS
- depends on KUNIT
+ depends on KUNIT && PHY_COMMON_PROPS
default KUNIT_ALL_TESTS
help
This builds KUnit tests for the PHY common property API.
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 2b0fd95ba62f..63427fc34e26 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1069,6 +1069,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
lane = &priv->lane[i];
+ if (!lane->phy)
+ continue;
mutex_lock(&lane->phy->mutex);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index df138a5442eb..771bc7c2ab50 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -990,6 +990,7 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e),
@@ -999,13 +1000,11 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = {
};
static const struct qmp_phy_init_tbl sm8650_ufsphy_g4_pcs[] = {
- QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
};
static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = {
- QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d),
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
index 342061380012..9215d0b223b2 100644
--- a/drivers/phy/spacemit/phy-k1-usb2.c
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -48,6 +48,9 @@
#define PHY_CLK_HSTXP_EN BIT(3) /* clock hstxp enable */
#define PHY_HSTXP_MODE BIT(4) /* 0: force en_txp to be 1; 1: no force */
+#define PHY_K1_HS_HOST_DISC 0x40
+#define PHY_K1_HS_HOST_DISC_CLR BIT(0)
+
#define PHY_PLL_DIV_CFG 0x98
#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
@@ -142,9 +145,20 @@ static int spacemit_usb2phy_exit(struct phy *phy)
return 0;
}
+static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
+{
+ struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
+
+ regmap_update_bits(sphy->regmap_base, PHY_K1_HS_HOST_DISC,
+ PHY_K1_HS_HOST_DISC_CLR, PHY_K1_HS_HOST_DISC_CLR);
+
+ return 0;
+}
+
static const struct phy_ops spacemit_usb2phy_ops = {
.init = spacemit_usb2phy_init,
.exit = spacemit_usb2phy_exit,
+ .disconnect = spacemit_usb2phy_disconnect,
.owner = THIS_MODULE,
};
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 6e9ecb88dc8b..6b584706b913 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1425,6 +1425,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
dev_err(dev,
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
__func__, subnode->name, ret);
+ of_node_put(serdes);
return ret;
}
of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes);
@@ -1439,6 +1440,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
}
}
+ of_node_put(serdes);
return 0;
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index d6a46fe0cda8..3f518dce6d23 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1135,9 +1135,12 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto chip_error;
}
- ret = mtk_eint_init(pctl, pdev);
- if (ret)
- goto chip_error;
+ /* Only initialize EINT if we have EINT pins */
+ if (data->eint_hw.ap_num > 0) {
+ ret = mtk_eint_init(pctl, pdev);
+ if (ret)
+ goto chip_error;
+ }
return 0;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 83f940fe30b2..d02d42513ebb 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -723,6 +723,21 @@ static const struct pinconf_ops pmic_gpio_pinconf_ops = {
.pin_config_group_dbg_show = pmic_gpio_config_dbg_show,
};
+static int pmic_gpio_get_direction(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
+ struct pmic_gpio_pad *pad;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ if (!pad->is_enabled || pad->analog_pass ||
+ (!pad->input_enabled && !pad->output_enabled))
+ return -EINVAL;
+
+ /* Make sure the state is aligned on what pmic_gpio_get() returns */
+ return pad->input_enabled ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+}
+
static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
struct pmic_gpio_state *state = gpiochip_get_data(chip);
@@ -801,6 +816,7 @@ static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
}
static const struct gpio_chip pmic_gpio_gpio_template = {
+ .get_direction = pmic_gpio_get_direction,
.direction_input = pmic_gpio_direction_input,
.direction_output = pmic_gpio_direction_output,
.get = pmic_gpio_get,
diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c
index bc8b9b9ad05b..d2949e4dbaf7 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza1.c
@@ -589,7 +589,7 @@ static inline unsigned int rza1_get_bit(struct rza1_port *port,
{
void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
- return ioread16(mem) & BIT(bit);
+ return !!(ioread16(mem) & BIT(bit));
}
/**
diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
index 9949108a35bb..5927744c7a96 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
@@ -85,7 +85,7 @@ struct rzt2h_pinctrl {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM);
- spinlock_t lock; /* lock read/write registers */
+ raw_spinlock_t lock; /* lock read/write registers */
struct mutex mutex; /* serialize adding groups and functions */
bool safety_port_enabled;
atomic_t wakeup_path;
@@ -145,7 +145,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
u64 reg64;
u16 reg16;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
/* Set pin to 'Non-use (Hi-Z input protection)' */
reg16 = rzt2h_pinctrl_readw(pctrl, port, PM(port));
@@ -474,7 +474,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
/* Select GPIO mode in PMC Register */
rzt2h_pinctrl_set_gpio_en(pctrl, port, bit, true);
@@ -487,7 +487,7 @@ static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port,
{
u16 reg;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
reg &= ~PM_PIN_MASK(bit);
@@ -509,7 +509,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) {
/*
@@ -547,7 +547,7 @@ static int rzt2h_gpio_set(struct gpio_chip *chip, unsigned int offset,
u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
u8 reg;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
reg = rzt2h_pinctrl_readb(pctrl, port, P(port));
if (value)
@@ -833,6 +833,7 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
if (ret)
return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n");
+ of_node_put(of_args.np);
if (of_args.args[0] != 0 || of_args.args[1] != 0 ||
of_args.args[2] != pctrl->data->n_port_pins)
return dev_err_probe(dev, -EINVAL,
@@ -964,7 +965,7 @@ static int rzt2h_pinctrl_probe(struct platform_device *pdev)
if (ret)
return ret;
- spin_lock_init(&pctrl->lock);
+ raw_spin_lock_init(&pctrl->lock);
mutex_init(&pctrl->mutex);
platform_set_drvdata(pdev, pctrl);
diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig
index 5f67e1ee66dd..d6a171523012 100644
--- a/drivers/pinctrl/stm32/Kconfig
+++ b/drivers/pinctrl/stm32/Kconfig
@@ -65,6 +65,7 @@ config PINCTRL_STM32_HDP
select PINMUX
select GENERIC_PINCONF
select GPIOLIB
+ select GPIO_GENERIC
help
The Hardware Debug Port allows the observation of internal signals.
It uses configurable multiplexer to route signals in a dedicated observation register.
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index c990b6118172..d3042e0c9712 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -157,6 +157,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
const char *pin_name,
const char *func_name)
{
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
int i;
for (i = 0; i < pctl->desc->npins; i++) {
@@ -168,7 +169,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
while (func->name) {
if (!strcmp(func->name, func_name) &&
(!func->variant ||
- func->variant & pctl->variant))
+ func->variant & variant))
return func;
func++;
@@ -209,6 +210,8 @@ sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl,
const u16 pin_num,
const u8 muxval)
{
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
+
for (unsigned int i = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func = pin->functions;
@@ -216,7 +219,7 @@ sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl,
if (pin->pin.number != pin_num)
continue;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
while (func->name) {
@@ -1089,6 +1092,9 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
{
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
struct sunxi_desc_function *func;
+ unsigned int offset;
+ u32 reg, shift, mask;
+ u8 disabled_mux, muxval;
int ret;
func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
@@ -1096,8 +1102,21 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
if (!func)
return -EINVAL;
- ret = gpiochip_lock_as_irq(pctl->chip,
- pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
+ offset = pctl->irq_array[d->hwirq] - pctl->desc->pin_base;
+ sunxi_mux_reg(pctl, offset, &reg, &shift, &mask);
+ muxval = (readl(pctl->membase + reg) & mask) >> shift;
+
+ /* Change muxing to GPIO INPUT mode if at reset value */
+ if (pctl->flags & SUNXI_PINCTRL_NEW_REG_LAYOUT)
+ disabled_mux = SUN4I_FUNC_DISABLED_NEW;
+ else
+ disabled_mux = SUN4I_FUNC_DISABLED_OLD;
+
+ if (muxval == disabled_mux)
+ sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq],
+ SUN4I_FUNC_INPUT);
+
+ ret = gpiochip_lock_as_irq(pctl->chip, offset);
if (ret) {
dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
@@ -1338,6 +1357,7 @@ static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
static int sunxi_pinctrl_build_state(struct platform_device *pdev)
{
struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
void *ptr;
int i;
@@ -1362,7 +1382,7 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
group->name = pin->pin.name;
@@ -1387,11 +1407,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
- if (func->variant && !(pctl->variant & func->variant))
+ if (func->variant && !(variant & func->variant))
continue;
/* Create interrupt mapping while we're at it */
@@ -1419,14 +1439,14 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
struct sunxi_pinctrl_function *func_item;
const char **func_grp;
- if (func->variant && !(pctl->variant & func->variant))
+ if (func->variant && !(variant & func->variant))
continue;
func_item = sunxi_pinctrl_find_function_by_name(pctl,
@@ -1568,7 +1588,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
pctl->dev = &pdev->dev;
pctl->desc = desc;
- pctl->variant = flags & SUNXI_PINCTRL_VARIANT_MASK;
+ pctl->flags = flags;
if (flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) {
pctl->bank_mem_size = D1_BANK_MEM_SIZE;
pctl->pull_regs_offset = D1_PULL_REGS_OFFSET;
@@ -1604,8 +1624,9 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
pins[pin_idx++] = pin->pin;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index ad26e4de16a8..0daf7600e2fb 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -86,6 +86,8 @@
#define SUN4I_FUNC_INPUT 0
#define SUN4I_FUNC_IRQ 6
+#define SUN4I_FUNC_DISABLED_OLD 7
+#define SUN4I_FUNC_DISABLED_NEW 15
#define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0)
#define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8)
@@ -174,7 +176,7 @@ struct sunxi_pinctrl {
unsigned *irq_array;
raw_spinlock_t lock;
struct pinctrl_dev *pctl_dev;
- unsigned long variant;
+ unsigned long flags;
u32 bank_mem_size;
u32 pull_regs_offset;
u32 dlevel_field_width;
diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c
index fa7b3bda688a..bee271a4fda1 100644
--- a/drivers/platform/olpc/olpc-xo175-ec.c
+++ b/drivers/platform/olpc/olpc-xo175-ec.c
@@ -482,7 +482,7 @@ static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp,
dev_dbg(dev, "CMD %x, %zd bytes expected\n", cmd, resp_len);
if (inlen > 5) {
- dev_err(dev, "command len %zd too big!\n", resp_len);
+ dev_err(dev, "command len %zd too big!\n", inlen);
return -EOVERFLOW;
}
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 19f82c1d3090..631ffc0978d1 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -117,7 +117,7 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms
}
if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) {
- dev_err(sock->dev, "Message ID 0x%X failure : SMU tmeout (status = 0x%X)\n",
+ dev_err(sock->dev, "Message ID 0x%X failure : SMU timeout (status = 0x%X)\n",
msg->msg_id, mbox_status);
return -ETIMEDOUT;
} else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) {
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index 208f6fe16168..569743746347 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -1082,6 +1082,20 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA503QM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_max = 80,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GA503QR"),
},
.driver_data = &(struct power_data) {
@@ -1520,6 +1534,35 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GZ302EA"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 60,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_def = 75,
+ .ppt_pl2_sppt_max = 92,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_def = 86,
+ .ppt_pl3_fppt_max = 93,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_def = 52,
+ .ppt_pl2_sppt_max = 92,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_def = 71,
+ .ppt_pl3_fppt_max = 93,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G513I"),
},
.driver_data = &(struct power_data) {
@@ -1598,6 +1641,40 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G614FP"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_max = 120,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_def = 140,
+ .ppt_pl2_sppt_max = 165,
+ .ppt_pl3_fppt_min = 65,
+ .ppt_pl3_fppt_def = 140,
+ .ppt_pl3_fppt_max = 165,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_tgp_min = 50,
+ .nv_tgp_max = 100,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 75,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G614J"),
},
.driver_data = &(struct power_data) {
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index a38a65f5c550..b4677c5bba5b 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -548,7 +548,7 @@ static const struct dmi_system_id asus_quirks[] = {
.callback = dmi_matched,
.ident = "ASUS ROG Z13",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"),
},
.driver_data = &quirk_asus_z13,
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 68ede7e5757a..988a0acc9622 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -120,6 +120,13 @@ static const struct thermal_profile_params omen_v1_thermal_params = {
.ec_tp_offset = HP_VICTUS_S_EC_THERMAL_PROFILE_OFFSET,
};
+static const struct thermal_profile_params omen_v1_legacy_thermal_params = {
+ .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE,
+ .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
+ .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
+ .ec_tp_offset = HP_OMEN_EC_THERMAL_PROFILE_OFFSET,
+};
+
/*
* A generic pointer for the currently-active board's thermal profile
* parameters.
@@ -176,6 +183,10 @@ static const char * const victus_thermal_profile_boards[] = {
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") },
+ .driver_data = (void *)&omen_v1_legacy_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAB") },
.driver_data = (void *)&omen_v1_thermal_params,
},
@@ -184,6 +195,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCA") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCD") },
.driver_data = (void *)&omen_v1_thermal_params,
},
@@ -196,6 +211,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") },
.driver_data = (void *)&omen_v1_thermal_params,
},
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 95c405c8bac0..2ddd8af8c1ce 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -438,6 +438,14 @@ static int intel_hid_pl_suspend_handler(struct device *device)
return 0;
}
+static int intel_hid_pl_freeze_handler(struct device *device)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(device);
+
+ priv->wakeup_mode = false;
+ return intel_hid_pl_suspend_handler(device);
+}
+
static int intel_hid_pl_resume_handler(struct device *device)
{
intel_hid_pm_complete(device);
@@ -452,7 +460,7 @@ static int intel_hid_pl_resume_handler(struct device *device)
static const struct dev_pm_ops intel_hid_pl_pm_ops = {
.prepare = intel_hid_pm_prepare,
.complete = intel_hid_pm_complete,
- .freeze = intel_hid_pl_suspend_handler,
+ .freeze = intel_hid_pl_freeze_handler,
.thaw = intel_hid_pl_resume_handler,
.restore = intel_hid_pl_resume_handler,
.suspend = intel_hid_pl_suspend_handler,
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
index b8cdaa233ea9..e238c3105c78 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
@@ -558,6 +558,9 @@ static bool disable_dynamic_sst_features(void)
{
u64 value;
+ if (!static_cpu_has(X86_FEATURE_HWP))
+ return true;
+
rdmsrq(MSR_PM_ENABLE, value);
return !(value & 0x1);
}
@@ -869,7 +872,7 @@ static int isst_if_get_perf_level(void __user *argp)
_read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET,
SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
_read_pp_info("locked", perf_level.locked, SST_PP_STATUS_OFFSET,
- SST_PP_LOCK_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
+ SST_PP_LOCK_START, SST_PP_LOCK_WIDTH, SST_MUL_FACTOR_NONE)
_read_pp_info("feature_state", perf_level.feature_state, SST_PP_STATUS_OFFSET,
SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE)
perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1));
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c
index 381836d29a96..c7fe7e3c9f17 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.c
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.c
@@ -31,8 +31,6 @@
#define LWMI_GZ_METHOD_ID_SMARTFAN_SET 44
#define LWMI_GZ_METHOD_ID_SMARTFAN_GET 45
-static BLOCKING_NOTIFIER_HEAD(gz_chain_head);
-
struct lwmi_gz_priv {
enum thermal_mode current_mode;
struct notifier_block event_nb;
diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c
index 0450202bbee2..eee87a300532 100644
--- a/drivers/pmdomain/bcm/bcm2835-power.c
+++ b/drivers/pmdomain/bcm/bcm2835-power.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mfd/bcm2835-pm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -153,7 +154,6 @@ struct bcm2835_power {
static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
{
void __iomem *base = power->asb;
- u64 start;
u32 val;
switch (reg) {
@@ -166,8 +166,6 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
break;
}
- start = ktime_get_ns();
-
/* Enable the module's async AXI bridges. */
if (enable) {
val = readl(base + reg) & ~ASB_REQ_STOP;
@@ -176,11 +174,9 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
}
writel(PM_PASSWORD | val, base + reg);
- while (!!(readl(base + reg) & ASB_ACK) == enable) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000)
- return -ETIMEDOUT;
- }
+ if (readl_poll_timeout_atomic(base + reg, val,
+ !!(val & ASB_ACK) != enable, 0, 5))
+ return -ETIMEDOUT;
return 0;
}
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index f64f24d520dd..e2800aa1bc59 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -1203,7 +1203,7 @@ static int scpsys_probe(struct platform_device *pdev)
scpsys->soc_data = soc;
scpsys->pd_data.domains = scpsys->domains;
- scpsys->pd_data.num_domains = soc->num_domains;
+ scpsys->pd_data.num_domains = num_domains;
parent = dev->parent;
if (!parent) {
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 1eebc2602187..0666be6b0e88 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1428,6 +1428,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
static int mpam_restore_mbwu_state(void *_ris)
{
int i;
+ u64 val;
struct mon_read mwbu_arg;
struct mpam_msc_ris *ris = _ris;
struct mpam_class *class = ris->vmsc->comp->class;
@@ -1437,6 +1438,7 @@ static int mpam_restore_mbwu_state(void *_ris)
mwbu_arg.ris = ris;
mwbu_arg.ctx = &ris->mbwu_state[i].cfg;
mwbu_arg.type = mpam_msmon_choose_counter(class);
+ mwbu_arg.val = &val;
__ris_msmon_read(&mwbu_arg);
}
diff --git a/drivers/resctrl/test_mpam_devices.c b/drivers/resctrl/test_mpam_devices.c
index 3e8d564a0c64..31871f519729 100644
--- a/drivers/resctrl/test_mpam_devices.c
+++ b/drivers/resctrl/test_mpam_devices.c
@@ -322,9 +322,17 @@ static void test_mpam_enable_merge_features(struct kunit *test)
mutex_unlock(&mpam_list_lock);
}
+static void __test_mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
+{
+ /* Avoid warnings when running with CONFIG_DEBUG_PREEMPT */
+ guard(preempt)();
+
+ mpam_reset_msc_bitmap(msc, reg, wd);
+}
+
static void test_mpam_reset_msc_bitmap(struct kunit *test)
{
- char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
+ char __iomem *buf = (__force char __iomem *)kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
struct mpam_msc fake_msc = {};
u32 *test_result;
@@ -339,33 +347,33 @@ static void test_mpam_reset_msc_bitmap(struct kunit *test)
mutex_init(&fake_msc.part_sel_lock);
mutex_lock(&fake_msc.part_sel_lock);
- test_result = (u32 *)(buf + MPAMCFG_CPBM);
+ test_result = (__force u32 *)(buf + MPAMCFG_CPBM);
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0);
KUNIT_EXPECT_EQ(test, test_result[0], 0);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1);
KUNIT_EXPECT_EQ(test, test_result[0], 1);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffff);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff);
KUNIT_EXPECT_EQ(test, test_result[1], 1);
test_result[0] = 0;
diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
index 32bc268c9149..05dd9b4a02df 100644
--- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c
+++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
@@ -136,6 +136,9 @@ static int rzg2l_usbphy_ctrl_set_pwrrdy(struct regmap_field *pwrrdy,
{
u32 val = power_on ? 0 : 1;
+ if (!pwrrdy)
+ return 0;
+
/* The initialization path guarantees that the mask is 1 bit long. */
return regmap_field_update_bits(pwrrdy, 1, val);
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index a20fce04fe79..3dd2adda195e 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4966,7 +4966,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
switch (mad_status) {
case IBMVFC_MAD_SUCCESS:
ibmvfc_dbg(vhost, "Discover Targets succeeded\n");
- vhost->num_targets = be32_to_cpu(rsp->num_written);
+ vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written),
+ max_targets);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
break;
case IBMVFC_MAD_FAILED:
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 12124f9d5ccd..13412702188e 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1734,7 +1734,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
break;
default:
- if (channel < shost->max_channel) {
+ if (channel <= shost->max_channel) {
res = scsi_scan_host_selected(shost, channel, id, lun,
SCSI_SCAN_MANUAL);
} else {
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 8e1686358e25..4c348645b04e 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -215,7 +215,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
unsigned char *type_ptr = ses_dev->page1_types;
unsigned char *desc_ptr = ses_dev->page2 + 8;
- if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0)
+ if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len))
return NULL;
for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 9aa7218b4e8d..1ed6be6e85d2 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1535,10 +1535,8 @@ static int of_qcom_slim_ngd_register(struct device *parent,
ngd->id = id;
ngd->pdev->dev.parent = parent;
- ret = driver_set_override(&ngd->pdev->dev,
- &ngd->pdev->driver_override,
- QCOM_SLIM_NGD_DRV_NAME,
- strlen(QCOM_SLIM_NGD_DRV_NAME));
+ ret = device_set_driver_override(&ngd->pdev->dev,
+ QCOM_SLIM_NGD_DRV_NAME);
if (ret) {
platform_device_put(ngd->pdev);
kfree(ngd);
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 411381f1a1c4..9ddafcb18f1c 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1827,6 +1827,8 @@ EXPORT_SYMBOL(qman_create_fq);
void qman_destroy_fq(struct qman_fq *fq)
{
+ int leaked;
+
/*
* We don't need to lock the FQ as it is a pre-condition that the FQ be
* quiesced. Instead, run some checks.
@@ -1834,11 +1836,29 @@ void qman_destroy_fq(struct qman_fq *fq)
switch (fq->state) {
case qman_fq_state_parked:
case qman_fq_state_oos:
- if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
- qman_release_fqid(fq->fqid);
+ /*
+ * There's a race condition here on releasing the fqid,
+ * setting the fq_table to NULL, and freeing the fqid.
+ * To prevent it, this order should be respected:
+ */
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) {
+ leaked = qman_shutdown_fq(fq->fqid);
+ if (leaked)
+ pr_debug("FQID %d leaked\n", fq->fqid);
+ }
DPAA_ASSERT(fq_table[fq->idx]);
fq_table[fq->idx] = NULL;
+
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID) && !leaked) {
+ /*
+ * fq_table[fq->idx] should be set to null before
+ * freeing fq->fqid otherwise it could by allocated by
+ * qman_alloc_fqid() while still being !NULL
+ */
+ smp_wmb();
+ gen_pool_free(qm_fqalloc, fq->fqid | DPAA_GENALLOC_OFF, 1);
+ }
return;
default:
break;
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
index c4587b32a59b..672adff8e35f 100644
--- a/drivers/soc/fsl/qe/qmc.c
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -1790,8 +1790,8 @@ static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev)
return -EINVAL;
qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0));
qmc->dpram = devm_ioremap_resource(qmc->dev, res);
- if (IS_ERR(qmc->scc_pram))
- return PTR_ERR(qmc->scc_pram);
+ if (IS_ERR(qmc->dpram))
+ return PTR_ERR(qmc->dpram);
return 0;
}
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 8e7ae3cb92ff..10b2fc39da66 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -142,8 +142,10 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
sys_controller->flash = of_get_mtd_device_by_node(np);
of_node_put(np);
- if (IS_ERR(sys_controller->flash))
- return dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
+ if (IS_ERR(sys_controller->flash)) {
+ ret = dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
+ goto out_free;
+ }
no_flash:
sys_controller->client.dev = dev;
@@ -155,8 +157,7 @@ no_flash:
if (IS_ERR(sys_controller->chan)) {
ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan),
"Failed to get mbox channel\n");
- kfree(sys_controller);
- return ret;
+ goto out_free;
}
init_completion(&sys_controller->c);
@@ -174,6 +175,10 @@ no_flash:
dev_info(&pdev->dev, "Registered MPFS system controller\n");
return 0;
+
+out_free:
+ kfree(sys_controller);
+ return ret;
}
static void mpfs_sys_controller_remove(struct platform_device *pdev)
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 04937c40da47..b459607c118a 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -231,6 +231,7 @@ static int __init rockchip_grf_init(void)
grf = syscon_node_to_regmap(np);
if (IS_ERR(grf)) {
pr_err("%s: could not get grf syscon\n", __func__);
+ of_node_put(np);
return PTR_ERR(grf);
}
diff --git a/drivers/spi/spi-amlogic-spifc-a4.c b/drivers/spi/spi-amlogic-spifc-a4.c
index 3956869cfec1..1aabafa36e48 100644
--- a/drivers/spi/spi-amlogic-spifc-a4.c
+++ b/drivers/spi/spi-amlogic-spifc-a4.c
@@ -1083,14 +1083,6 @@ static int aml_sfc_clk_init(struct aml_sfc *sfc)
return clk_set_rate(sfc->core_clk, SFC_BUS_DEFAULT_CLK);
}
-static int aml_sfc_disable_clk(struct aml_sfc *sfc)
-{
- clk_disable_unprepare(sfc->core_clk);
- clk_disable_unprepare(sfc->gate_clk);
-
- return 0;
-}
-
static int aml_sfc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1141,16 +1133,12 @@ static int aml_sfc_probe(struct platform_device *pdev)
/* Enable Amlogic flash controller spi mode */
ret = regmap_write(sfc->regmap_base, SFC_SPI_CFG, SPI_MODE_EN);
- if (ret) {
- dev_err(dev, "failed to enable SPI mode\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable SPI mode\n");
ret = dma_set_mask(sfc->dev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(sfc->dev, "failed to set dma mask\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(sfc->dev, ret, "failed to set dma mask\n");
sfc->ecc_eng.dev = &pdev->dev;
sfc->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
@@ -1158,10 +1146,8 @@ static int aml_sfc_probe(struct platform_device *pdev)
sfc->ecc_eng.priv = sfc;
ret = nand_ecc_register_on_host_hw_engine(&sfc->ecc_eng);
- if (ret) {
- dev_err(&pdev->dev, "failed to register Aml host ecc engine.\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register Aml host ecc engine.\n");
ret = of_property_read_u32(np, "amlogic,rx-adj", &val);
if (!ret)
@@ -1177,24 +1163,7 @@ static int aml_sfc_probe(struct platform_device *pdev)
ctrl->min_speed_hz = SFC_MIN_FREQUENCY;
ctrl->num_chipselect = SFC_MAX_CS_NUM;
- ret = devm_spi_register_controller(dev, ctrl);
- if (ret)
- goto err_out;
-
- return 0;
-
-err_out:
- aml_sfc_disable_clk(sfc);
-
- return ret;
-}
-
-static void aml_sfc_remove(struct platform_device *pdev)
-{
- struct spi_controller *ctlr = platform_get_drvdata(pdev);
- struct aml_sfc *sfc = spi_controller_get_devdata(ctlr);
-
- aml_sfc_disable_clk(sfc);
+ return devm_spi_register_controller(dev, ctrl);
}
static const struct of_device_id aml_sfc_of_match[] = {
@@ -1212,7 +1181,6 @@ static struct platform_driver aml_sfc_driver = {
.of_match_table = aml_sfc_of_match,
},
.probe = aml_sfc_probe,
- .remove = aml_sfc_remove,
};
module_platform_driver(aml_sfc_driver);
diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c
index 1509df2b17ae..9d568e385f05 100644
--- a/drivers/spi/spi-amlogic-spisg.c
+++ b/drivers/spi/spi-amlogic-spisg.c
@@ -729,9 +729,9 @@ static int aml_spisg_probe(struct platform_device *pdev)
};
if (of_property_read_bool(dev->of_node, "spi-slave"))
- ctlr = spi_alloc_target(dev, sizeof(*spisg));
+ ctlr = devm_spi_alloc_target(dev, sizeof(*spisg));
else
- ctlr = spi_alloc_host(dev, sizeof(*spisg));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*spisg));
if (!ctlr)
return -ENOMEM;
@@ -750,10 +750,8 @@ static int aml_spisg_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(spisg->map), "regmap init failed\n");
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto out_controller;
- }
+ if (irq < 0)
+ return irq;
ret = device_reset_optional(dev);
if (ret)
@@ -817,8 +815,6 @@ out_clk:
if (spisg->core)
clk_disable_unprepare(spisg->core);
clk_disable_unprepare(spisg->pclk);
-out_controller:
- spi_controller_put(ctlr);
return ret;
}
diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c
index 8cea81432c5b..8ddcd27def22 100644
--- a/drivers/spi/spi-axiado.c
+++ b/drivers/spi/spi-axiado.c
@@ -765,30 +765,22 @@ static int ax_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctlr);
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(xspi->regs)) {
- ret = PTR_ERR(xspi->regs);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->regs))
+ return PTR_ERR(xspi->regs);
xspi->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(xspi->pclk)) {
- dev_err(&pdev->dev, "pclk clock not found.\n");
- ret = PTR_ERR(xspi->pclk);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->pclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(xspi->pclk),
+ "pclk clock not found.\n");
xspi->ref_clk = devm_clk_get(&pdev->dev, "ref");
- if (IS_ERR(xspi->ref_clk)) {
- dev_err(&pdev->dev, "ref clock not found.\n");
- ret = PTR_ERR(xspi->ref_clk);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->ref_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(xspi->ref_clk),
+ "ref clock not found.\n");
ret = clk_prepare_enable(xspi->pclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable APB clock.\n");
- goto remove_ctlr;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Unable to enable APB clock.\n");
ret = clk_prepare_enable(xspi->ref_clk);
if (ret) {
@@ -869,8 +861,7 @@ clk_dis_all:
clk_disable_unprepare(xspi->ref_clk);
clk_dis_apb:
clk_disable_unprepare(xspi->pclk);
-remove_ctlr:
- spi_controller_put(ctlr);
+
return ret;
}
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index b361c1bb3e43..45390e9b8cae 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -1009,7 +1009,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
enable_irq(irq);
}
- ret = devm_spi_register_controller(&pdev->dev, controller);
+ ret = spi_register_controller(controller);
if (ret < 0) {
dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n");
goto free_dma;
@@ -1035,6 +1035,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
+ spi_unregister_controller(controller);
fsl_lpspi_dma_exit(controller);
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 43ce47f2454c..d5fb0edc8e0c 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -359,9 +359,9 @@ static int setup_fifo_params(struct spi_device *spi_slv,
writel((spi_slv->mode & SPI_LOOP) ? LOOPBACK_ENABLE : 0, se->base + SE_SPI_LOOPBACK);
if (cs_changed)
writel(chipselect, se->base + SE_SPI_DEMUX_SEL);
- if (mode_changed & SE_SPI_CPHA)
+ if (mode_changed & SPI_CPHA)
writel((spi_slv->mode & SPI_CPHA) ? CPHA : 0, se->base + SE_SPI_CPHA);
- if (mode_changed & SE_SPI_CPOL)
+ if (mode_changed & SPI_CPOL)
writel((spi_slv->mode & SPI_CPOL) ? CPOL : 0, se->base + SE_SPI_CPOL);
if ((mode_changed & SPI_CS_HIGH) || (cs_changed && (spi_slv->mode & SPI_CS_HIGH)))
writel((spi_slv->mode & SPI_CS_HIGH) ? BIT(chipselect) : 0, se->base + SE_SPI_DEMUX_OUTPUT_INV);
@@ -906,10 +906,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
struct spi_controller *spi = data;
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
- u32 m_irq;
+ u32 m_irq, dma_tx_status, dma_rx_status;
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
- if (!m_irq)
+ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (!m_irq && !dma_tx_status && !dma_rx_status)
return IRQ_NONE;
if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
@@ -957,8 +960,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
}
} else if (mas->cur_xfer_mode == GENI_SE_DMA) {
const struct spi_transfer *xfer = mas->cur_xfer;
- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
if (dma_tx_status)
writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index a7001b9e36e6..57768da3205d 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -1101,8 +1101,6 @@ static void meson_spicc_remove(struct platform_device *pdev)
/* Disable SPI */
writel(0, spicc->base + SPICC_CONREG);
-
- spi_controller_put(spicc->host);
}
static const struct meson_spicc_data meson_spicc_gx_data = {
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index bfcc140df810..3c61c799723b 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -612,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev)
u32 num_cs = OSPI_NUM_CS;
int ret;
- ctlr = spi_alloc_host(dev, sizeof(*ospi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*ospi));
if (!ctlr)
return -ENOMEM;
@@ -635,43 +635,22 @@ static int f_ospi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ospi);
ospi->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(ospi->base)) {
- ret = PTR_ERR(ospi->base);
- goto err_put_ctlr;
- }
+ if (IS_ERR(ospi->base))
+ return PTR_ERR(ospi->base);
ospi->clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(ospi->clk)) {
- ret = PTR_ERR(ospi->clk);
- goto err_put_ctlr;
- }
+ if (IS_ERR(ospi->clk))
+ return PTR_ERR(ospi->clk);
- mutex_init(&ospi->mlock);
-
- ret = f_ospi_init(ospi);
+ ret = devm_mutex_init(dev, &ospi->mlock);
if (ret)
- goto err_destroy_mutex;
+ return ret;
- ret = devm_spi_register_controller(dev, ctlr);
+ ret = f_ospi_init(ospi);
if (ret)
- goto err_destroy_mutex;
-
- return 0;
-
-err_destroy_mutex:
- mutex_destroy(&ospi->mlock);
-
-err_put_ctlr:
- spi_controller_put(ctlr);
-
- return ret;
-}
-
-static void f_ospi_remove(struct platform_device *pdev)
-{
- struct f_ospi *ospi = platform_get_drvdata(pdev);
+ return ret;
- mutex_destroy(&ospi->mlock);
+ return devm_spi_register_controller(dev, ctlr);
}
static const struct of_device_id f_ospi_dt_ids[] = {
@@ -686,7 +665,6 @@ static struct platform_driver f_ospi_driver = {
.of_match_table = f_ospi_dt_ids,
},
.probe = f_ospi_probe,
- .remove = f_ospi_remove,
};
module_platform_driver(f_ospi_driver);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 61f7bde8c7fb..9b1125556d29 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -50,7 +50,6 @@ static void spidev_release(struct device *dev)
struct spi_device *spi = to_spi_device(dev);
spi_controller_put(spi->controller);
- kfree(spi->driver_override);
free_percpu(spi->pcpu_statistics);
kfree(spi);
}
@@ -73,10 +72,9 @@ static ssize_t driver_override_store(struct device *dev,
struct device_attribute *a,
const char *buf, size_t count)
{
- struct spi_device *spi = to_spi_device(dev);
int ret;
- ret = driver_set_override(dev, &spi->driver_override, buf, count);
+ ret = __device_set_driver_override(dev, buf, count);
if (ret)
return ret;
@@ -86,13 +84,8 @@ static ssize_t driver_override_store(struct device *dev,
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *a, char *buf)
{
- const struct spi_device *spi = to_spi_device(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", spi->driver_override ? : "");
- device_unlock(dev);
- return len;
+ guard(spinlock)(&dev->driver_override.lock);
+ return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: "");
}
static DEVICE_ATTR_RW(driver_override);
@@ -376,10 +369,12 @@ static int spi_match_device(struct device *dev, const struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
+ int ret;
/* Check override first, and if set, only use the named driver */
- if (spi->driver_override)
- return strcmp(spi->driver_override, drv->name) == 0;
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
@@ -3049,6 +3044,8 @@ static void spi_controller_release(struct device *dev)
struct spi_controller *ctlr;
ctlr = container_of(dev, struct spi_controller, dev);
+
+ free_percpu(ctlr->pcpu_statistics);
kfree(ctlr);
}
@@ -3192,6 +3189,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
if (!ctlr)
return NULL;
+ ctlr->pcpu_statistics = spi_alloc_pcpu_stats(NULL);
+ if (!ctlr->pcpu_statistics) {
+ kfree(ctlr);
+ return NULL;
+ }
+
device_initialize(&ctlr->dev);
INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock);
@@ -3480,17 +3483,8 @@ int spi_register_controller(struct spi_controller *ctlr)
dev_info(dev, "controller is unqueued, this is deprecated\n");
} else if (ctlr->transfer_one || ctlr->transfer_one_message) {
status = spi_controller_initialize_queue(ctlr);
- if (status) {
- device_del(&ctlr->dev);
- goto free_bus_id;
- }
- }
- /* Add statistics */
- ctlr->pcpu_statistics = spi_alloc_pcpu_stats(dev);
- if (!ctlr->pcpu_statistics) {
- dev_err(dev, "Error allocating per-cpu statistics\n");
- status = -ENOMEM;
- goto destroy_queue;
+ if (status)
+ goto del_ctrl;
}
mutex_lock(&board_lock);
@@ -3504,8 +3498,8 @@ int spi_register_controller(struct spi_controller *ctlr)
acpi_register_spi_devices(ctlr);
return status;
-destroy_queue:
- spi_destroy_queue(ctlr);
+del_ctrl:
+ device_del(&ctlr->dev);
free_bus_id:
mutex_lock(&board_lock);
idr_remove(&spi_controller_idr, ctlr->bus_num);
@@ -3540,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev,
if (ret)
return ret;
- return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
+ /*
+ * Prevent controller from being freed by spi_unregister_controller()
+ * if devm_add_action_or_reset() fails for a non-devres allocated
+ * controller.
+ */
+ spi_controller_get(ctlr);
+
+ ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
+ if (ret == 0 || ctlr->devm_allocated)
+ spi_controller_put(ctlr);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(devm_spi_register_controller);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index d668bd19fd4a..528883d989b8 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/configfs.h>
+#include <linux/blk-mq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
@@ -269,15 +270,27 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
+static bool tcm_loop_flush_work_iter(struct request *rq, void *data)
+{
+ struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq);
+ struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
+ struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
+
+ flush_work(&se_cmd->work);
+ return true;
+}
+
static int tcm_loop_target_reset(struct scsi_cmnd *sc)
{
struct tcm_loop_hba *tl_hba;
struct tcm_loop_tpg *tl_tpg;
+ struct Scsi_Host *sh = sc->device->host;
+ int ret;
/*
* Locate the tcm_loop_hba_t pointer
*/
- tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
+ tl_hba = *(struct tcm_loop_hba **)shost_priv(sh);
if (!tl_hba) {
pr_err("Unable to perform device reset without active I_T Nexus\n");
return FAILED;
@@ -286,11 +299,38 @@ static int tcm_loop_target_reset(struct scsi_cmnd *sc)
* Locate the tl_tpg pointer from TargetID in sc->device->id
*/
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
- if (tl_tpg) {
- tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
- return SUCCESS;
- }
- return FAILED;
+ if (!tl_tpg)
+ return FAILED;
+
+ /*
+ * Issue a LUN_RESET to drain all commands that the target core
+ * knows about. This handles commands not yet marked CMD_T_COMPLETE.
+ */
+ ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET);
+ if (ret != TMR_FUNCTION_COMPLETE)
+ return FAILED;
+
+ /*
+ * Flush any deferred target core completion work that may still be
+ * queued. Commands that already had CMD_T_COMPLETE set before the TMR
+ * are skipped by the TMR drain, but their async completion work
+ * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done)
+ * may still be pending in target_completion_wq.
+ *
+ * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery
+ * commands (e.g. TUR) immediately after this handler returns SUCCESS —
+ * if deferred work is still pending, the memset in queuecommand would
+ * zero the se_cmd while the work accesses it, leaking the LUN
+ * percpu_ref and hanging configfs unlink forever.
+ *
+ * Use blk_mq_tagset_busy_iter() to find all started requests and
+ * flush_work() on each — the same pattern used by mpi3mr, scsi_debug,
+ * and other SCSI drivers to drain outstanding commands during reset.
+ */
+ blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL);
+
+ tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
+ return SUCCESS;
}
static const struct scsi_host_template tcm_loop_driver_template = {
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 3ae1f7137d9d..3d593af30aa5 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -276,7 +276,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ssize_t len = 0;
int ret = 0, i;
- aio_cmd = kmalloc_flex(*aio_cmd, bvecs, sgl_nents);
+ aio_cmd = kzalloc_flex(*aio_cmd, bvecs, sgl_nents);
if (!aio_cmd)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 6c5b9e352e5e..e9ea9f80cfd9 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -23,29 +23,11 @@ struct tee_shm_dma_mem {
struct page *page;
};
-static void shm_put_kernel_pages(struct page **pages, size_t page_count)
-{
- size_t n;
-
- for (n = 0; n < page_count; n++)
- put_page(pages[n]);
-}
-
-static void shm_get_kernel_pages(struct page **pages, size_t page_count)
-{
- size_t n;
-
- for (n = 0; n < page_count; n++)
- get_page(pages[n]);
-}
-
static void release_registered_pages(struct tee_shm *shm)
{
if (shm->pages) {
if (shm->flags & TEE_SHM_USER_MAPPED)
unpin_user_pages(shm->pages, shm->num_pages);
- else
- shm_put_kernel_pages(shm->pages, shm->num_pages);
kfree(shm->pages);
}
@@ -477,13 +459,6 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
goto err_put_shm_pages;
}
- /*
- * iov_iter_extract_kvec_pages does not get reference on the pages,
- * get a reference on them.
- */
- if (iov_iter_is_kvec(iter))
- shm_get_kernel_pages(shm->pages, num_pages);
-
shm->offset = off;
shm->size = len;
shm->num_pages = num_pages;
@@ -499,8 +474,6 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
err_put_shm_pages:
if (!iov_iter_is_kvec(iter))
unpin_user_pages(shm->pages, shm->num_pages);
- else
- shm_put_kernel_pages(shm->pages, shm->num_pages);
err_free_shm_pages:
kfree(shm->pages);
err_free_shm:
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
index 49ff3bae7271..91f291627132 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
@@ -176,15 +176,21 @@ static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 v
static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider)
{
+ u8 offset;
u64 val;
val = read_soc_slider(proc_priv);
val &= ~SLIDER_MASK;
val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT);
+ if (slider == SOC_SLIDER_VALUE_MINIMUM || slider == SOC_SLIDER_VALUE_MAXIMUM)
+ offset = 0;
+ else
+ offset = slider_offset;
+
/* Set the slider offset from module params */
val &= ~SLIDER_OFFSET_MASK;
- val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset);
+ val |= FIELD_PREP(SLIDER_OFFSET_MASK, offset);
write_soc_slider(proc_priv, val);
}
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 8caecfc85d93..77fe0588fd6b 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -175,7 +175,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
return value;
}
+void serial8250_clear_fifos(struct uart_8250_port *p);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -400,6 +402,26 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
return dma && dma->tx_running;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_pause(dma->txchan);
+}
+
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_resume(dma->txchan);
+}
#else
static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
@@ -421,6 +443,9 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
{
return false;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { }
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { }
#endif
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index bdd26c9f34bd..3b6452e759d5 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -162,7 +162,22 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
+ /*
+ * We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
+ * holding the uart port spinlock.
+ */
dmaengine_terminate_async(dma->txchan);
+
+ /*
+ * The callback might or might not run. If it doesn't run, we need to ensure
+ * that `tx_running` is cleared so that we can schedule new transactions.
+ * If it does run, then the zombie callback will clear `tx_running` again
+ * and perform a no-op since `tx_size` was cleared above.
+ *
+ * In either case, we ASSUME the DMA transaction will terminate before we
+ * issue a new `serial8250_tx_dma`.
+ */
+ dma->tx_running = 0;
}
int serial8250_rx_dma(struct uart_8250_port *p)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index db73b2ae17fa..94beadb4024d 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -9,10 +9,14 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
@@ -40,8 +44,12 @@
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
+#define DW_UART_IIR_IID GENMASK(3, 0)
+
#define DW_UART_MCR_SIRE BIT(6)
+#define DW_UART_USR_BUSY BIT(0)
+
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
@@ -56,6 +64,13 @@
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
#define DW_UART_QUIRK_CPR_VALUE BIT(5)
+#define DW_UART_QUIRK_IER_KICK BIT(6)
+
+/*
+ * Number of consecutive IIR_NO_INT interrupts required to trigger interrupt
+ * storm prevention code.
+ */
+#define DW_UART_QUIRK_IER_KICK_THRES 4
struct dw8250_platform_data {
u8 usr_reg;
@@ -77,6 +92,9 @@ struct dw8250_data {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
+ unsigned int in_idle:1;
+
+ u8 no_int_count;
};
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
@@ -107,78 +125,167 @@ static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u3
return value;
}
+static void dw8250_idle_exit(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ if (d->uart_16550_compatible)
+ return;
+
+ if (up->capabilities & UART_CAP_FIFO)
+ serial_port_out(p, UART_FCR, up->fcr);
+ serial_port_out(p, UART_MCR, up->mcr);
+ serial_port_out(p, UART_IER, up->ier);
+
+ /* DMA Rx is restarted by IRQ handler as needed. */
+ if (up->dma)
+ serial8250_tx_dma_resume(up);
+
+ d->in_idle = 0;
+}
+
/*
- * This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * Ensure BUSY is not asserted. If DW UART is configured with
+ * !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while
+ * BUSY is asserted.
+ *
+ * Context: port's lock must be held
*/
-static void dw8250_force_idle(struct uart_port *p)
+static int dw8250_idle_enter(struct uart_port *p)
{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int lsr;
+ int retries;
+ u32 lsr;
- /*
- * The following call currently performs serial_out()
- * against the FCR register. Because it differs to LCR
- * there will be no infinite loop, but if it ever gets
- * modified, we might need a new custom version of it
- * that avoids infinite recursion.
- */
- serial8250_clear_and_reinit_fifos(up);
+ lockdep_assert_held_once(&p->lock);
+
+ if (d->uart_16550_compatible)
+ return 0;
+
+ d->in_idle = 1;
+
+ /* Prevent triggering interrupt from RBR filling */
+ serial_port_out(p, UART_IER, 0);
+
+ if (up->dma) {
+ serial8250_rx_dma_flush(up);
+ if (serial8250_tx_dma_running(up))
+ serial8250_tx_dma_pause(up);
+ }
/*
- * With PSLVERR_RESP_EN parameter set to 1, the device generates an
- * error response when an attempt to read an empty RBR with FIFO
- * enabled.
+ * Wait until Tx becomes empty + one extra frame time to ensure all bits
+ * have been sent on the wire.
+ *
+ * FIXME: frame_time delay is too long with very low baudrates.
*/
- if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = serial_port_in(p, UART_LSR);
- if (!(lsr & UART_LSR_DR))
- return;
+ serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
+ ndelay(p->frame_time);
+
+ serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);
+
+ retries = 4; /* Arbitrary limit, 2 was always enough in tests */
+ do {
+ serial8250_clear_fifos(up);
+ if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY))
+ break;
+ /* FIXME: frame_time delay is too long with very low baudrates. */
+ ndelay(p->frame_time);
+ } while (--retries);
+
+ lsr = serial_lsr_in(up);
+ if (lsr & UART_LSR_DR) {
+ serial_port_in(p, UART_RX);
+ up->lsr_saved_flags = 0;
+ }
+
+ /* Now guaranteed to have BUSY deasserted? Just sanity check */
+ if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) {
+ dw8250_idle_exit(p);
+ return -EBUSY;
}
- serial_port_in(p, UART_RX);
+ return 0;
+}
+
+static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int ret;
+
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ return;
+
+ serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB);
+ if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB))
+ goto idle_failed;
+
+ serial_dl_write(up, quot);
+ serial_port_out(p, UART_LCR, up->lcr);
+
+idle_failed:
+ dw8250_idle_exit(p);
}
/*
* This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * routine. Hence, special care must be taken when serial_port_out() or
+ * serial_out() against the modified registers here, i.e. LCR (d->in_idle is
+ * used to break recursion loop).
*/
static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
- void __iomem *addr = p->membase + (offset << p->regshift);
- int tries = 1000;
+ u32 lcr;
+ int ret;
if (offset != UART_LCR || d->uart_16550_compatible)
return;
+ lcr = serial_port_in(p, UART_LCR);
+
/* Make sure LCR write wasn't ignored */
- while (tries--) {
- u32 lcr = serial_port_in(p, offset);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
+ if (d->in_idle)
+ goto write_err;
- dw8250_force_idle(p);
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ goto write_err;
-#ifdef CONFIG_64BIT
- if (p->type == PORT_OCTEON)
- __raw_writeq(value & 0xff, addr);
- else
-#endif
- if (p->iotype == UPIO_MEM32)
- writel(value, addr);
- else if (p->iotype == UPIO_MEM32BE)
- iowrite32be(value, addr);
- else
- writeb(value, addr);
- }
+ serial_port_out(p, UART_LCR, value);
+ dw8250_idle_exit(p);
+ return;
+
+write_err:
/*
* FIXME: this deadlocks if port->lock is already held
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
*/
+ return; /* Silences "label at the end of compound statement" */
+}
+
+/*
+ * With BUSY, LCR writes can be very expensive (IRQ + complex retry logic).
+ * If the write does not change the value of the LCR register, skip it entirely.
+ */
+static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int offset, u32 value)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ u32 lcr;
+
+ if (offset != UART_LCR || d->uart_16550_compatible)
+ return false;
+
+ lcr = serial_port_in(p, offset);
+ return lcr == value;
}
/* Returns once the transmitter is empty or we run out of retries */
@@ -207,12 +314,18 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writeb(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
/* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR)
dw8250_tx_wait_empty(p);
@@ -237,6 +350,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
@@ -248,6 +364,9 @@ static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 val
static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writel(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -261,6 +380,9 @@ static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
iowrite32be(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -272,6 +394,29 @@ static u32 dw8250_serial_in32be(struct uart_port *p, unsigned int offset)
return dw8250_modify_msr(p, offset, value);
}
+/*
+ * INTC10EE UART can IRQ storm while reporting IIR_NO_INT. Inducing IIR value
+ * change has been observed to break the storm.
+ *
+ * If Tx is empty (THRE asserted), we use here IER_THRI to cause IIR_NO_INT ->
+ * IIR_THRI transition.
+ */
+static void dw8250_quirk_ier_kick(struct uart_port *p)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ u32 lsr;
+
+ if (up->ier & UART_IER_THRI)
+ return;
+
+ lsr = serial_lsr_in(up);
+ if (!(lsr & UART_LSR_THRE))
+ return;
+
+ serial_port_out(p, UART_IER, up->ier | UART_IER_THRI);
+ serial_port_in(p, UART_LCR); /* safe, no side-effects */
+ serial_port_out(p, UART_IER, up->ier);
+}
static int dw8250_handle_irq(struct uart_port *p)
{
@@ -281,7 +426,31 @@ static int dw8250_handle_irq(struct uart_port *p)
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
- unsigned long flags;
+
+ guard(uart_port_lock_irqsave)(p);
+
+ switch (FIELD_GET(DW_UART_IIR_IID, iir)) {
+ case UART_IIR_NO_INT:
+ if (d->uart_16550_compatible || up->dma)
+ return 0;
+
+ if (quirks & DW_UART_QUIRK_IER_KICK &&
+ d->no_int_count == (DW_UART_QUIRK_IER_KICK_THRES - 1))
+ dw8250_quirk_ier_kick(p);
+ d->no_int_count = (d->no_int_count + 1) % DW_UART_QUIRK_IER_KICK_THRES;
+
+ return 0;
+
+ case UART_IIR_BUSY:
+ /* Clear the USR */
+ serial_port_in(p, d->pdata->usr_reg);
+
+ d->no_int_count = 0;
+
+ return 1;
+ }
+
+ d->no_int_count = 0;
/*
* There are ways to get Designware-based UARTs into a state where
@@ -294,20 +463,15 @@ static int dw8250_handle_irq(struct uart_port *p)
* so we limit the workaround only to non-DMA mode.
*/
if (!up->dma && rx_timeout) {
- uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
-
- uart_port_unlock_irqrestore(p, flags);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
- uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
- uart_port_unlock_irqrestore(p, flags);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
@@ -315,17 +479,9 @@ static int dw8250_handle_irq(struct uart_port *p)
}
}
- if (serial8250_handle_irq(p, iir))
- return 1;
-
- if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
- /* Clear the USR */
- serial_port_in(p, d->pdata->usr_reg);
-
- return 1;
- }
+ serial8250_handle_irq_locked(p, iir);
- return 0;
+ return 1;
}
static void dw8250_clk_work_cb(struct work_struct *work)
@@ -527,6 +683,14 @@ static void dw8250_reset_control_assert(void *data)
reset_control_assert(data);
}
+static void dw8250_shutdown(struct uart_port *port)
+{
+ struct dw8250_data *d = to_dw8250_data(port->private_data);
+
+ serial8250_do_shutdown(port);
+ d->no_int_count = 0;
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -545,8 +709,10 @@ static int dw8250_probe(struct platform_device *pdev)
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
p->dev = dev;
+
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
+ p->set_divisor = dw8250_set_divisor;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -654,10 +820,12 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible)
+ if (data->uart_16550_compatible) {
p->handle_irq = NULL;
- else if (data->pdata)
+ } else if (data->pdata) {
p->handle_irq = dw8250_handle_irq;
+ p->shutdown = dw8250_shutdown;
+ }
dw8250_setup_dma_filter(p, data);
@@ -789,6 +957,11 @@ static const struct dw8250_platform_data dw8250_skip_set_rate_data = {
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
+static const struct dw8250_platform_data dw8250_intc10ee = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_IER_KICK,
+};
+
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -818,7 +991,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
- { "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb },
+ { "INTC10EE", (kernel_ulong_t)&dw8250_intc10ee },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@@ -836,6 +1009,7 @@ static struct platform_driver dw8250_platform_driver = {
module_platform_driver(dw8250_platform_driver);
+MODULE_IMPORT_NS("SERIAL_8250");
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index aa1ab4da9ff1..6cfd1b2af5b7 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -137,6 +137,8 @@ struct serial_private {
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
+#define PCIE_VENDOR_ID_ASIX 0x125B
+#define PCIE_DEVICE_ID_AX99100 0x9100
static const struct pci_device_id pci_use_msi[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
@@ -149,6 +151,8 @@ static const struct pci_device_id pci_use_msi[] = {
0xA000, 0x1000) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
PCI_ANY_ID, PCI_ANY_ID) },
+ { PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000) },
{ }
};
@@ -920,6 +924,7 @@ static int pci_netmos_init(struct pci_dev *dev)
case PCI_DEVICE_ID_NETMOS_9912:
case PCI_DEVICE_ID_NETMOS_9922:
case PCI_DEVICE_ID_NETMOS_9900:
+ case PCIE_DEVICE_ID_AX99100:
num_serial = pci_netmos_9900_numports(dev);
break;
@@ -2544,6 +2549,14 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.init = pci_netmos_init,
.setup = pci_netmos_9900_setup,
},
+ {
+ .vendor = PCIE_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_netmos_init,
+ .setup = pci_netmos_9900_setup,
+ },
/*
* EndRun Technologies
*/
@@ -6065,6 +6078,10 @@ static const struct pci_device_id serial_pci_tbl[] = {
0xA000, 0x3002,
0, 0, pbn_NETMOS9900_2s_115200 },
+ { PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
/*
* Best Connectivity and Rosewill PCI Multi I/O cards
*/
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index cc94af2d578a..328711b5df1a 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/console.h>
#include <linux/gpio/consumer.h>
+#include <linux/lockdep.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -488,7 +489,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
/*
* FIFO support.
*/
-static void serial8250_clear_fifos(struct uart_8250_port *p)
+void serial8250_clear_fifos(struct uart_8250_port *p)
{
if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -497,6 +498,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
serial_out(p, UART_FCR, 0);
}
}
+EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250");
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -1782,20 +1784,16 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
}
/*
- * This handles the interrupt from one port.
+ * Context: port's lock must be held by the caller.
*/
-int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
- unsigned long flags;
u16 status;
- if (iir & UART_IIR_NO_INT)
- return 0;
-
- uart_port_lock_irqsave(port, &flags);
+ lockdep_assert_held_once(&port->lock);
status = serial_lsr_in(up);
@@ -1828,8 +1826,19 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
else if (!up->dma->tx_running)
__stop_tx(up);
}
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_handle_irq_locked, "SERIAL_8250");
+
+/*
+ * This handles the interrupt from one port.
+ */
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+{
+ if (iir & UART_IIR_NO_INT)
+ return 0;
- uart_unlock_and_check_sysrq_irqrestore(port, flags);
+ guard(uart_port_lock_irqsave)(port);
+ serial8250_handle_irq_locked(port, iir);
return 1;
}
@@ -2147,8 +2156,7 @@ static void serial8250_THRE_test(struct uart_port *port)
if (up->port.flags & UPF_NO_THRE_TEST)
return;
- if (port->irqflags & IRQF_SHARED)
- disable_irq_nosync(port->irq);
+ disable_irq(port->irq);
/*
* Test for UARTs that do not reassert THRE when the transmitter is idle and the interrupt
@@ -2170,8 +2178,7 @@ static void serial8250_THRE_test(struct uart_port *port)
serial_port_out(port, UART_IER, 0);
}
- if (port->irqflags & IRQF_SHARED)
- enable_irq(port->irq);
+ enable_irq(port->irq);
/*
* If the interrupt is not reasserted, or we otherwise don't trust the iir, setup a timer to
@@ -2350,6 +2357,7 @@ static int serial8250_startup(struct uart_port *port)
void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ u32 lcr;
serial8250_rpm_get(up);
/*
@@ -2376,13 +2384,13 @@ void serial8250_do_shutdown(struct uart_port *port)
port->mctrl &= ~TIOCM_OUT2;
serial8250_set_mctrl(port, port->mctrl);
+
+ /* Disable break condition */
+ lcr = serial_port_in(port, UART_LCR);
+ lcr &= ~UART_LCR_SBC;
+ serial_port_out(port, UART_LCR, lcr);
}
- /*
- * Disable break condition and FIFOs
- */
- serial_port_out(port, UART_LCR,
- serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
serial8250_clear_fifos(up);
rsa_disable(up);
@@ -2392,6 +2400,12 @@ void serial8250_do_shutdown(struct uart_port *port)
* the IRQ chain.
*/
serial_port_in(port, UART_RX);
+ /*
+ * LCR writes on DW UART can trigger late (unmaskable) IRQs.
+ * Handle them before releasing the handler.
+ */
+ synchronize_irq(port->irq);
+
serial8250_rpm_put(up);
up->ops->release_irq(up);
@@ -3185,6 +3199,17 @@ void serial8250_set_defaults(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_lsr(up, UART_LSR_THRE))
+ return;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
+
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3226,16 +3251,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
-static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
-{
- unsigned int i;
-
- for (i = 0; i < count; i++) {
- if (wait_for_lsr(up, UART_LSR_THRE))
- return;
- }
-}
-
/*
* Print a string to the serial port using the device FIFO
*
@@ -3254,7 +3269,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
while (s != end) {
/* Allow timeout for each byte of a possibly full FIFO */
- fifo_wait_for_lsr(up, fifosize);
+ serial8250_fifo_wait_for_lsr_thre(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
@@ -3272,7 +3287,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
* Allow timeout for each byte written since the caller will only wait
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
*/
- fifo_wait_for_lsr(up, tx_count);
+ serial8250_fifo_wait_for_lsr_thre(up, tx_count);
}
/*
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 487756947a96..89cebdd27841 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -643,7 +643,10 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_ref_lock(state, &flags);
- ret = kfifo_avail(&state->port.xmit_fifo);
+ if (!state->port.xmit_buf)
+ ret = 0;
+ else
+ ret = kfifo_avail(&state->port.xmit_fifo);
uart_port_unlock_deref(port, flags);
return ret;
}
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 39c1fd1ff9ce..6240c3d4dfd7 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -878,6 +878,7 @@ of_err:
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index c1f152d8b03b..e2df99e3d458 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1339,6 +1339,8 @@ struct vc_data *vc_deallocate(unsigned int currcons)
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
}
+ vc_uniscr_free(vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
}
return vc;
}
@@ -1884,6 +1886,8 @@ static void enter_alt_screen(struct vc_data *vc)
vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
if (vc->vc_saved_screen == NULL)
return;
+ vc->vc_saved_uni_lines = vc->vc_uni_lines;
+ vc->vc_uni_lines = NULL;
vc->vc_saved_rows = vc->vc_rows;
vc->vc_saved_cols = vc->vc_cols;
save_cur(vc);
@@ -1905,6 +1909,8 @@ static void leave_alt_screen(struct vc_data *vc)
dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
memcpy(dest, src, 2 * cols);
}
+ vc_uniscr_set(vc, vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
restore_cur(vc);
/* Update the entire screen */
if (con_should_update(vc))
@@ -2227,6 +2233,8 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
if (vc->vc_saved_screen != NULL) {
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
+ vc_uniscr_free(vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
vc->vc_saved_rows = 0;
vc->vc_saved_cols = 0;
}
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index 3a803923141b..f87fd32e4a01 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -316,11 +316,10 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
*/
ret = dma_buf_fd(priv->dmabuf, get_dma_buf.open_flags);
if (ret < 0)
- goto err_dma_buf;
+ dma_buf_put(priv->dmabuf);
+
return ret;
-err_dma_buf:
- dma_buf_put(priv->dmabuf);
err_dev_put:
vfio_device_put_registration(&vdev->vdev);
err_free_phys:
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 4252b147593a..7cee97559ba2 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -171,6 +171,8 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
#define GET_QUOTE_SUCCESS 0
#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff
+#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf))
+
/* struct tdx_quote_buf: Format of Quote request buffer.
* @version: Quote format version, filled by TD.
* @status: Status code of Quote request, filled by VMM.
@@ -269,6 +271,7 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data)
u8 *buf;
struct tdx_quote_buf *quote_buf = quote_data;
struct tsm_report_desc *desc = &report->desc;
+ u32 out_len;
int ret;
u64 err;
@@ -306,12 +309,17 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data)
return ret;
}
- buf = kvmemdup(quote_buf->data, quote_buf->out_len, GFP_KERNEL);
+ out_len = READ_ONCE(quote_buf->out_len);
+
+ if (out_len > TDX_QUOTE_MAX_LEN)
+ return -EFBIG;
+
+ buf = kvmemdup(quote_buf->data, out_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
report->outblob = buf;
- report->outblob_len = quote_buf->out_len;
+ report->outblob_len = out_len;
/*
* TODO: parse the PEM-formatted cert chain out of the quote buffer when
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 335692d41617..fbca7ce1c6bf 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2912,10 +2912,10 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf);
* @data: the token identifying the buffer.
* @gfp: how to do memory allocations (if necessary).
*
- * Same as virtqueue_add_inbuf but passes DMA_ATTR_CPU_CACHE_CLEAN to indicate
- * that the CPU will not dirty any cacheline overlapping this buffer while it
- * is available, and to suppress overlapping cacheline warnings in DMA debug
- * builds.
+ * Same as virtqueue_add_inbuf but passes DMA_ATTR_DEBUGGING_IGNORE_CACHELINES
+ * to indicate that the CPU will not dirty any cacheline overlapping this buffer
+ * while it is available, and to suppress overlapping cacheline warnings in DMA
+ * debug builds.
*
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
@@ -2928,7 +2928,7 @@ int virtqueue_add_inbuf_cache_clean(struct virtqueue *vq,
gfp_t gfp)
{
return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, false, gfp,
- DMA_ATTR_CPU_CACHE_CLEAN);
+ DMA_ATTR_DEBUGGING_IGNORE_CACHELINES);
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_cache_clean);
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 1759cc18753f..15ba592236e8 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -12,6 +12,7 @@
#include <linux/eventfd.h>
#include <linux/file.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
@@ -30,7 +31,10 @@
#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
#include <linux/virtio_mmio.h>
+#include <linux/wait.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -46,6 +50,7 @@
#include <xen/page.h>
#include <xen/xen-ops.h>
#include <xen/balloon.h>
+#include <xen/xenbus.h>
#ifdef CONFIG_XEN_ACPI
#include <xen/acpi.h>
#endif
@@ -68,10 +73,20 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
MODULE_PARM_DESC(dm_op_buf_max_size,
"Maximum size of a dm_op hypercall buffer");
+static bool unrestricted;
+module_param(unrestricted, bool, 0);
+MODULE_PARM_DESC(unrestricted,
+ "Don't restrict hypercalls to target domain if running in a domU");
+
struct privcmd_data {
domid_t domid;
};
+/* DOMID_INVALID implies no restriction */
+static domid_t target_domain = DOMID_INVALID;
+static bool restrict_wait;
+static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq);
+
static int privcmd_vma_range_is_mapped(
struct vm_area_struct *vma,
unsigned long addr,
@@ -1563,13 +1578,16 @@ static long privcmd_ioctl(struct file *file,
static int privcmd_open(struct inode *ino, struct file *file)
{
- struct privcmd_data *data = kzalloc_obj(*data);
+ struct privcmd_data *data;
+ if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0)
+ return -EINTR;
+
+ data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
- /* DOMID_INVALID implies no restriction */
- data->domid = DOMID_INVALID;
+ data->domid = target_domain;
file->private_data = data;
return 0;
@@ -1662,6 +1680,52 @@ static struct miscdevice privcmd_dev = {
.fops = &xen_privcmd_fops,
};
+static int init_restrict(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ char *target;
+ unsigned int domid;
+
+ /* Default to an guaranteed unused domain-id. */
+ target_domain = DOMID_IDLE;
+
+ target = xenbus_read(XBT_NIL, "target", "", NULL);
+ if (IS_ERR(target) || kstrtouint(target, 10, &domid)) {
+ pr_err("No target domain found, blocking all hypercalls\n");
+ goto out;
+ }
+
+ target_domain = domid;
+
+ out:
+ if (!IS_ERR(target))
+ kfree(target);
+
+ restrict_wait = false;
+ wake_up_all(&restrict_wait_wq);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xenstore_notifier = {
+ .notifier_call = init_restrict,
+};
+
+static void __init restrict_driver(void)
+{
+ if (unrestricted) {
+ if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS))
+ pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n");
+ else
+ return;
+ }
+
+ restrict_wait = true;
+
+ register_xenstore_notifier(&xenstore_notifier);
+}
+
static int __init privcmd_init(void)
{
int err;
@@ -1669,6 +1733,9 @@ static int __init privcmd_init(void)
if (!xen_domain())
return -ENODEV;
+ if (!xen_initial_domain())
+ restrict_driver();
+
err = misc_register(&privcmd_dev);
if (err != 0) {
pr_err("Could not register Xen privcmd device\n");
@@ -1698,6 +1765,9 @@ err_privcmdbuf:
static void __exit privcmd_exit(void)
{
+ if (!xen_initial_domain())
+ unregister_xenstore_notifier(&xenstore_notifier);
+
privcmd_ioeventfd_exit();
privcmd_irqfd_exit();
misc_deregister(&privcmd_dev);