summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
commit93467b31bec6da512b51544e5e4584f2745e995e (patch)
tree2ea2be38c5e4dc9aafffbbc0db5aae0f6513a1d9 /drivers
parent8ca1f4c6fb1462ee120730ea75c19da10d2f2d6f (diff)
parent7a5cef0db4795d9d453a12e0f61b5b7634fc4d40 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/cppc_acpi.c11
-rw-r--r--drivers/acpi/nfit/core.c21
-rw-r--r--drivers/android/binder.c19
-rw-r--r--drivers/android/binder/allocation.rs5
-rw-r--r--drivers/android/binder/error.rs13
-rw-r--r--drivers/android/binder/freeze.rs11
-rw-r--r--drivers/android/binder/node.rs10
-rw-r--r--drivers/android/binder/process.rs18
-rw-r--r--drivers/android/binder/rust_binder_events.c7
-rw-r--r--drivers/android/binder/stats.rs4
-rw-r--r--drivers/android/binder/thread.rs65
-rw-r--r--drivers/android/binder/transaction.rs15
-rw-r--r--drivers/base/firmware_loader/sysfs_upload.c8
-rw-r--r--drivers/bluetooth/btmtksdio.c2
-rw-r--r--drivers/bluetooth/btnxpuart.c6
-rw-r--r--drivers/bluetooth/btusb.c39
-rw-r--r--drivers/bluetooth/hci_ldisc.c14
-rw-r--r--drivers/char/hw_random/jh7110-trng.c13
-rw-r--r--drivers/char/hw_random/virtio-rng.c23
-rw-r--r--drivers/clocksource/timer-tegra186.c3
-rw-r--r--drivers/cpufreq/cpufreq.c2
-rw-r--r--drivers/cpufreq/intel_pstate.c6
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c2
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c1
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c88
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.h4
-rw-r--r--drivers/crypto/amcc/crypto4xx_reg_def.h11
-rw-r--r--drivers/crypto/amlogic/amlogic-gxl-core.c2
-rw-r--r--drivers/crypto/atmel-sha204a.c27
-rw-r--r--drivers/crypto/caam/caamalg.c12
-rw-r--r--drivers/crypto/caam/caamalg_qi.c12
-rw-r--r--drivers/crypto/caam/caamalg_qi2.c12
-rw-r--r--drivers/crypto/caam/caamhash.c4
-rw-r--r--drivers/crypto/caam/key_gen.c4
-rw-r--r--drivers/crypto/ccp/sev-dev.c70
-rw-r--r--drivers/crypto/hisilicon/Kconfig1
-rw-r--r--drivers/crypto/hisilicon/trng/trng.c296
-rw-r--r--drivers/crypto/intel/qat/qat_420xx/adf_drv.c2
-rw-r--r--drivers/crypto/intel/qat/qat_4xxx/adf_drv.c2
-rw-r--r--drivers/crypto/intel/qat/qat_6xxx/adf_drv.c2
-rw-r--r--drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c1
-rw-r--r--drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c1
-rw-r--r--drivers/crypto/intel/qat/qat_c62x/adf_drv.c1
-rw-r--r--drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c1
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_accel_devices.h2
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_aer.c109
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_common_drv.h3
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_init.c18
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_isr.c39
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_sriov.c32
-rw-r--r--drivers/crypto/intel/qat/qat_common/qat_asym_algs.c10
-rw-r--r--drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c1
-rw-r--r--drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c1
-rw-r--r--drivers/crypto/loongson/Kconfig5
-rw-r--r--drivers/crypto/loongson/Makefile1
-rw-r--r--drivers/crypto/loongson/loongson-rng.c209
-rw-r--r--drivers/crypto/talitos.c549
-rw-r--r--drivers/crypto/talitos.h12
-rw-r--r--drivers/crypto/tegra/tegra-se-main.c2
-rw-r--r--drivers/dma-buf/udmabuf.c9
-rw-r--r--drivers/edac/i10nm_base.c14
-rw-r--r--drivers/fpga/dfl-afu-main.c3
-rw-r--r--drivers/gpio/gpio-eic-sprd.c8
-rw-r--r--drivers/gpio/gpio-sch.c32
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c31
-rw-r--r--drivers/hid/hid-appleir.c45
-rw-r--r--drivers/hid/hid-goodix-spi.c3
-rw-r--r--drivers/hid/hid-lenovo-go.c9
-rw-r--r--drivers/hid/hid-letsketch.c36
-rw-r--r--drivers/hid/hid-lg-g15.c16
-rw-r--r--drivers/hid/hid-logitech-dj.c9
-rw-r--r--drivers/hid/hid-multitouch.c32
-rw-r--r--drivers/hid/hid-sensor-hub.c77
-rw-r--r--drivers/hid/uhid.c8
-rw-r--r--drivers/hid/usbhid/hid-pidff.c2
-rw-r--r--drivers/hid/wacom_sys.c20
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c6
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.c1
-rw-r--r--drivers/i2c/busses/i2c-davinci.c4
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c15
-rw-r--r--drivers/i2c/busses/i2c-mpc.c2
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c9
-rw-r--r--drivers/i2c/i2c-core-base.c81
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c2
-rw-r--r--drivers/iio/accel/kxsd9.c5
-rw-r--r--drivers/iio/adc/Kconfig4
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c39
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c4
-rw-r--r--drivers/iio/adc/nxp-sar-adc.c4
-rw-r--r--drivers/iio/adc/spear_adc.c3
-rw-r--r--drivers/iio/adc/ti-ads1119.c6
-rw-r--r--drivers/iio/adc/ti-ads124s08.c3
-rw-r--r--drivers/iio/buffer/industrialio-hw-consumer.c2
-rw-r--r--drivers/iio/chemical/scd30_core.c19
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c23
-rw-r--r--drivers/iio/dac/ad3552r-hs.c2
-rw-r--r--drivers/iio/gyro/bmg160_core.c16
-rw-r--r--drivers/iio/imu/adis_trigger.c2
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c3
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c4
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c9
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h1
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c4
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c21
-rw-r--r--drivers/iio/industrialio-backend.c2
-rw-r--r--drivers/iio/industrialio-core.c2
-rw-r--r--drivers/iio/industrialio-event.c5
-rw-r--r--drivers/iio/light/Kconfig3
-rw-r--r--drivers/iio/light/al3010.c10
-rw-r--r--drivers/iio/light/al3320a.c8
-rw-r--r--drivers/iio/light/gp2ap002.c2
-rw-r--r--drivers/iio/light/opt3001.c6
-rw-r--r--drivers/iio/light/tsl2591.c6
-rw-r--r--drivers/iio/light/veml6030.c8
-rw-r--r--drivers/iio/magnetometer/ak8975.c1
-rw-r--r--drivers/iio/pressure/bmp280-core.c2
-rw-r--r--drivers/iio/pressure/mpl115.c4
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c7
-rw-r--r--drivers/iio/resolver/ad2s1210.c2
-rw-r--r--drivers/iio/temperature/Makefile2
-rw-r--r--drivers/iio/temperature/ltc2983.c5
-rw-r--r--drivers/iio/temperature/tmp006.c2
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/sw/siw/siw_qp_rx.c9
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv.c5
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c18
-rw-r--r--drivers/input/joystick/maplecontrol.c3
-rw-r--r--drivers/input/keyboard/maple_keyb.c4
-rw-r--r--drivers/input/mouse/elan_i2c_core.c36
-rw-r--r--drivers/input/mouse/maplemouse.c9
-rw-r--r--drivers/input/rmi4/rmi_bus.c4
-rw-r--r--drivers/input/rmi4/rmi_f30.c2
-rw-r--r--drivers/input/rmi4/rmi_f3a.c2
-rw-r--r--drivers/input/serio/gscps2.c1
-rw-r--r--drivers/input/touchscreen/ads7846.c5
-rw-r--r--drivers/input/touchscreen/goodix.c3
-rw-r--r--drivers/input/touchscreen/mms114.c26
-rw-r--r--drivers/input/touchscreen/touchwin.c15
-rw-r--r--drivers/iommu/amd/iommu.c3
-rw-r--r--drivers/iommu/intel/iommu.h11
-rw-r--r--drivers/iommu/intel/svm.c12
-rw-r--r--drivers/iommu/iommufd/driver.c13
-rw-r--r--drivers/iommu/iommufd/eventq.c36
-rw-r--r--drivers/iommu/iommufd/hw_pagetable.c11
-rw-r--r--drivers/iommu/iommufd/iommufd_private.h2
-rw-r--r--drivers/md/dm-ioctl.c5
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c3
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c2
-rw-r--r--drivers/mfd/cros_ec_dev.c3
-rw-r--r--drivers/net/usb/kalmia.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c3
-rw-r--r--drivers/ntb/hw/epf/ntb_hw_epf.c14
-rw-r--r--drivers/nvme/host/multipath.c6
-rw-r--r--drivers/nvme/target/discovery.c23
-rw-r--r--drivers/nvme/target/fabrics-cmd-auth.c15
-rw-r--r--drivers/nvme/target/rdma.c6
-rw-r--r--drivers/opp/of.c3
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c65
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c6
-rw-r--r--drivers/pci/controller/pci-host-common.c4
-rw-r--r--drivers/pci/controller/pci-loongson.c36
-rw-r--r--drivers/pci/controller/pcie-altera.c36
-rw-r--r--drivers/pci/controller/pcie-mediatek.c63
-rw-r--r--drivers/pci/iov.c6
-rw-r--r--drivers/pci/quirks.c51
-rw-r--r--drivers/pci/rebar.c6
-rw-r--r--drivers/perf/arm-cmn.c23
-rw-r--r--drivers/platform/x86/intel/hid.c9
-rw-r--r--drivers/regulator/scmi-regulator.c4
-rw-r--r--drivers/spi/spi-fsl-lpspi.c18
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c6
-rw-r--r--drivers/staging/media/ipu3/ipu3-css-params.c8
-rw-r--r--drivers/staging/media/ipu7/ipu7.c22
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c15
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c20
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_wlan_util.c23
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c8
-rw-r--r--drivers/staging/rtl8723bs/os_dep/xmit_linux.c6
-rw-r--r--drivers/staging/vme_user/vme_fake.c8
-rw-r--r--drivers/staging/vme_user/vme_tsi148.c8
-rw-r--r--drivers/staging/vme_user/vme_user.c22
-rw-r--r--drivers/tty/serial/8250/8250_mid.c13
-rw-r--r--drivers/tty/vt/keyboard.c12
-rw-r--r--drivers/usb/cdns3/cdnsp-mem.c2
-rw-r--r--drivers/usb/class/cdc-acm.c3
-rw-r--r--drivers/usb/common/ulpi.c23
-rw-r--r--drivers/usb/core/quirks.c6
-rw-r--r--drivers/usb/dwc3/core.c4
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c14
-rw-r--r--drivers/usb/dwc3/gadget.c43
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.c6
-rw-r--r--drivers/usb/gadget/composite.c5
-rw-r--r--drivers/usb/gadget/function/f_fs.c9
-rw-r--r--drivers/usb/gadget/function/f_printer.c3
-rw-r--r--drivers/usb/gadget/function/rndis.c20
-rw-r--r--drivers/usb/gadget/udc/core.c29
-rw-r--r--drivers/usb/host/ehci-sched.c11
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/xhci-sideband.c2
-rw-r--r--drivers/usb/host/xhci.c11
-rw-r--r--drivers/usb/misc/chaoskey.c1
-rw-r--r--drivers/usb/misc/idmouse.c45
-rw-r--r--drivers/usb/misc/iowarrior.c61
-rw-r--r--drivers/usb/misc/ldusb.c38
-rw-r--r--drivers/usb/misc/legousbtower.c37
-rw-r--r--drivers/usb/misc/usbio.c8
-rw-r--r--drivers/usb/misc/uss720.c5
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c1
-rw-r--r--drivers/usb/serial/digi_acceleport.c43
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/option.c16
-rw-r--r--drivers/usb/storage/ene_ub6250.c3
-rw-r--r--drivers/usb/storage/usb.c2
-rw-r--r--drivers/usb/typec/anx7411.c4
-rw-r--r--drivers/usb/typec/class.c1
-rw-r--r--drivers/usb/typec/mux.c13
-rw-r--r--drivers/usb/typec/mux/ps883x.c6
-rw-r--r--drivers/usb/typec/tcpm/tcpci_rt1711h.c13
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c9
-rw-r--r--drivers/usb/typec/ucsi/displayport.c7
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c20
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h1
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c10
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c2
-rw-r--r--drivers/usb/usbip/vudc.h1
-rw-r--r--drivers/usb/usbip/vudc_dev.c4
-rw-r--r--drivers/vfio/debugfs.c1
-rw-r--r--drivers/vfio/pci/mlx5/cmd.h15
-rw-r--r--drivers/vfio/pci/vfio_pci_core.c37
-rw-r--r--drivers/vfio/vfio_main.c11
-rw-r--r--drivers/virtio/virtio_mmio.c26
-rw-r--r--drivers/virtio/virtio_pci_common.c10
-rw-r--r--drivers/watchdog/apple_wdt.c1
239 files changed, 2309 insertions, 1761 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index f370be8715ae..34edec0f2bde 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -185,8 +185,13 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
-/* Check for valid access_width, otherwise, fallback to using bit_width */
-#define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width)
+/*
+ * PCC reuses the access_width field as the subspace id, so only decode access
+ * size for non-PCC registers. Otherwise, use the bit_width.
+ */
+#define GET_BIT_WIDTH(reg) (((reg)->access_width && \
+ (reg)->space_id != ACPI_ADR_SPACE_PLATFORM_COMM) ? \
+ (8 << ((reg)->access_width - 1)) : (reg)->bit_width)
/* Shift and apply the mask for CPC reads/writes */
#define MASK_VAL_READ(reg, val) (((val) >> (reg)->bit_offset) & \
@@ -1045,7 +1050,6 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
* by the bit width field; the access size is used to indicate
* the PCC subspace id.
*/
- size = reg->bit_width;
vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
@@ -1118,7 +1122,6 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
* by the bit width field; the access size is used to indicate
* the PCC subspace id.
*/
- size = reg->bit_width;
vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 9304ac996d41..7f554ce6345f 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -3069,6 +3069,8 @@ static void acpi_nfit_unregister(void *data)
struct acpi_nfit_desc *acpi_desc = data;
nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+ /* The nvdimm_bus object may have been freed, so clear the pointer. */
+ acpi_desc->nvdimm_bus = NULL;
}
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz)
@@ -3309,7 +3311,10 @@ static void acpi_nfit_remove_notify_handler(void *data)
void acpi_nfit_shutdown(void *data)
{
struct acpi_nfit_desc *acpi_desc = data;
- struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
+ struct device *bus_dev;
+
+ if (!acpi_desc || !acpi_desc->nvdimm_bus)
+ return;
/*
* Destruct under acpi_desc_lock so that nfit_handle_mce does not
@@ -3324,6 +3329,7 @@ void acpi_nfit_shutdown(void *data)
mutex_unlock(&acpi_desc->init_mutex);
cancel_delayed_work_sync(&acpi_desc->dwork);
+ bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
/*
* Bounce the nvdimm bus lock to make sure any in-flight
* acpi_nfit_ars_rescan() submissions have had a chance to
@@ -3406,9 +3412,14 @@ static int acpi_nfit_probe(struct platform_device *pdev)
sz - sizeof(struct acpi_table_nfit));
if (rc)
- return rc;
+ acpi_nfit_shutdown(acpi_desc);
+
+ return rc;
+}
- return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
+static void acpi_nfit_remove(struct platform_device *pdev)
+{
+ acpi_nfit_shutdown(platform_get_drvdata(pdev));
}
static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
@@ -3460,6 +3471,9 @@ static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle)
{
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
+ if (!acpi_desc)
+ return;
+
if (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON)
acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
else
@@ -3489,6 +3503,7 @@ MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
static struct platform_driver acpi_nfit_driver = {
.probe = acpi_nfit_probe,
+ .remove = acpi_nfit_remove,
.driver = {
.name = "acpi-nfit",
.acpi_match_table = acpi_nfit_ids,
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 9e6194224593..b85920c39694 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1658,7 +1658,20 @@ static void binder_txn_latency_free(struct binder_transaction *t)
static void binder_free_transaction(struct binder_transaction *t)
{
- struct binder_proc *target_proc = t->to_proc;
+ struct binder_thread *target_thread;
+ struct binder_proc *target_proc;
+
+ spin_lock(&t->lock);
+ target_proc = t->to_proc;
+ target_thread = t->to_thread;
+ /*
+ * Pin target_thread to keep target_proc alive. Undelivered
+ * transactions with !target_thread are safe, as target_proc
+ * can only be the current context there.
+ */
+ if (target_thread)
+ atomic_inc(&target_thread->tmp_ref);
+ spin_unlock(&t->lock);
if (target_proc) {
binder_inner_proc_lock(target_proc);
@@ -1672,6 +1685,10 @@ static void binder_free_transaction(struct binder_transaction *t)
t->buffer->transaction = NULL;
binder_inner_proc_unlock(target_proc);
}
+
+ if (target_thread)
+ binder_thread_dec_tmpref(target_thread);
+
if (trace_binder_txn_latency_free_enabled())
binder_txn_latency_free(t);
/*
diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs
index b7b05e72970a..ea5846e4da16 100644
--- a/drivers/android/binder/allocation.rs
+++ b/drivers/android/binder/allocation.rs
@@ -259,7 +259,7 @@ impl Drop for Allocation {
if let Some(offsets) = info.offsets.clone() {
let view = AllocationView::new(self, offsets.start);
- for i in offsets.step_by(size_of::<usize>()) {
+ for i in offsets.step_by(size_of::<u64>()) {
if view.cleanup_object(i).is_err() {
pr_warn!("Error cleaning up object at offset {}\n", i)
}
@@ -420,7 +420,8 @@ impl<'a> AllocationView<'a> {
}
fn cleanup_object(&self, index_offset: usize) -> Result {
- let offset = self.alloc.read(index_offset)?;
+ let offset = self.alloc.read::<u64>(index_offset)?;
+ let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
let header = self.read::<BinderObjectHeader>(offset)?;
match header.type_ {
BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => {
diff --git a/drivers/android/binder/error.rs b/drivers/android/binder/error.rs
index 45d85d4c2815..1296072c35d9 100644
--- a/drivers/android/binder/error.rs
+++ b/drivers/android/binder/error.rs
@@ -73,20 +73,17 @@ impl fmt::Debug for BinderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.reply {
BR_FAILED_REPLY => match self.source.as_ref() {
- Some(source) => f
- .debug_struct("BR_FAILED_REPLY")
- .field("source", source)
- .finish(),
+ Some(source) => source.fmt(f),
None => f.pad("BR_FAILED_REPLY"),
},
BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"),
BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"),
BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"),
BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"),
- _ => f
- .debug_struct("BinderError")
- .field("reply", &self.reply)
- .finish(),
+ _ => match self.source.as_ref() {
+ Some(source) => source.fmt(f),
+ None => self.reply.fmt(f),
+ },
}
}
}
diff --git a/drivers/android/binder/freeze.rs b/drivers/android/binder/freeze.rs
index 53b60035639a..f4df14568b25 100644
--- a/drivers/android/binder/freeze.rs
+++ b/drivers/android/binder/freeze.rs
@@ -154,10 +154,17 @@ impl DeliverToRead for FreezeMessage {
}
impl FreezeListener {
- pub(crate) fn on_process_exit(&self, proc: &Arc<Process>) {
+ /// Called when this freeze listener is cleared abnormally.
+ ///
+ /// This occurs either because the process exited or because the process dropped its last
+ /// refcount on the node ref without explicitly removing the freeze listener first.
+ ///
+ /// The returned `KVVec` is just a value that should be dropped outside of the lock.
+ pub(crate) fn on_process_cleanup(&self, proc: &Process) -> KVVec<Arc<Process>> {
if !self.is_clearing {
- self.node.remove_freeze_listener(proc);
+ return self.node.remove_freeze_listener(proc);
}
+ KVVec::new()
}
}
diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs
index 69f757ff7461..c10148e9069f 100644
--- a/drivers/android/binder/node.rs
+++ b/drivers/android/binder/node.rs
@@ -682,12 +682,13 @@ impl Node {
}
}
- pub(crate) fn remove_freeze_listener(&self, p: &Arc<Process>) {
- let _unused_capacity;
+ pub(crate) fn remove_freeze_listener(&self, p: &Process) -> KVVec<Arc<Process>> {
let mut guard = self.owner.inner.lock();
let inner = self.inner.access_mut(&mut guard);
let len = inner.freeze_list.len();
- inner.freeze_list.retain(|proc| !Arc::ptr_eq(proc, p));
+ inner
+ .freeze_list
+ .retain(|proc| !core::ptr::eq::<Process>(&**proc, p));
if len == inner.freeze_list.len() {
pr_warn!(
"Could not remove freeze listener for {}\n",
@@ -695,8 +696,9 @@ impl Node {
);
}
if inner.freeze_list.is_empty() {
- _unused_capacity = mem::take(&mut inner.freeze_list);
+ return mem::take(&mut inner.freeze_list);
}
+ KVVec::new()
}
pub(crate) fn freeze_list<'a>(&'a self, guard: &'a ProcessInner) -> &'a [Arc<Process>] {
diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
index 96b8440ceac6..cdd1a9079726 100644
--- a/drivers/android/binder/process.rs
+++ b/drivers/android/binder/process.rs
@@ -900,7 +900,11 @@ impl Process {
pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult<NodeRef> {
// When handle is zero, try to get the context manager.
if handle == 0 {
- Ok(self.ctx.get_manager_node(true)?)
+ let node_ref = self.ctx.get_manager_node(true)?;
+ if core::ptr::eq(self, &*node_ref.node.owner) {
+ return Err(EINVAL.into());
+ }
+ Ok(node_ref)
} else {
Ok(self.get_node_from_handle(handle, true)?)
}
@@ -942,6 +946,8 @@ impl Process {
// To preserve original binder behaviour, we only fail requests where the manager tries to
// increment references on itself.
+ let _to_free_freeze_listener;
+ let _to_free_freeze_listener_cleanup;
let mut refs = self.node_refs.lock();
if let Some(info) = refs.by_handle.get_mut(&handle) {
if info.node_ref().update(inc, strong) {
@@ -957,6 +963,14 @@ impl Process {
unsafe { info.node_ref2().node.remove_node_info(info) };
let id = info.node_ref().node.global_id();
+
+ if let Some(freeze) = *info.freeze() {
+ if let Some(fl) = refs.freeze_listeners.remove(&freeze) {
+ _to_free_freeze_listener_cleanup = fl.on_process_cleanup(&self);
+ _to_free_freeze_listener = fl;
+ }
+ }
+
refs.by_handle.remove(&handle);
refs.by_node.remove(&id);
refs.handle_is_present.release_id(handle as usize);
@@ -1380,7 +1394,7 @@ impl Process {
// Clean up freeze listeners.
let freeze_listeners = take(&mut self.node_refs.lock().freeze_listeners);
for listener in freeze_listeners.values() {
- listener.on_process_exit(&self);
+ listener.on_process_cleanup(&self);
}
drop(freeze_listeners);
diff --git a/drivers/android/binder/rust_binder_events.c b/drivers/android/binder/rust_binder_events.c
index 488b1470060c..5792aa59cc82 100644
--- a/drivers/android/binder/rust_binder_events.c
+++ b/drivers/android/binder/rust_binder_events.c
@@ -28,6 +28,9 @@ const char * const binder_command_strings[] = {
"BC_DEAD_BINDER_DONE",
"BC_TRANSACTION_SG",
"BC_REPLY_SG",
+ "BC_REQUEST_FREEZE_NOTIFICATION",
+ "BC_CLEAR_FREEZE_NOTIFICATION",
+ "BC_FREEZE_NOTIFICATION_DONE",
};
const char * const binder_return_strings[] = {
@@ -51,7 +54,9 @@ const char * const binder_return_strings[] = {
"BR_FAILED_REPLY",
"BR_FROZEN_REPLY",
"BR_ONEWAY_SPAM_SUSPECT",
- "BR_TRANSACTION_PENDING_FROZEN"
+ "BR_TRANSACTION_PENDING_FROZEN",
+ "BR_FROZEN_BINDER",
+ "BR_CLEAR_FREEZE_NOTIFICATION_DONE",
};
#define CREATE_TRACE_POINTS
diff --git a/drivers/android/binder/stats.rs b/drivers/android/binder/stats.rs
index ab75e9561cbf..ec81dc7747db 100644
--- a/drivers/android/binder/stats.rs
+++ b/drivers/android/binder/stats.rs
@@ -8,8 +8,8 @@ use crate::defs::*;
use kernel::sync::atomic::{ordering::Relaxed, Atomic};
use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print};
-const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1;
-const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1;
+const BC_COUNT: usize = _IOC_NR(BC_FREEZE_NOTIFICATION_DONE) as usize + 1;
+const BR_COUNT: usize = _IOC_NR(BR_CLEAR_FREEZE_NOTIFICATION_DONE) as usize + 1;
pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new();
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index 97d5f31e8fe3..3b8520813941 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -495,9 +495,16 @@ impl Thread {
Ok(())
}
+ pub(crate) fn clear_extended_error(&self, debug_id: usize) {
+ self.inner.lock().extended_error = ExtendedError::new(debug_id as u32, BR_OK, 0);
+ }
+
pub(crate) fn get_extended_error(&self, data: UserSlice) -> Result {
let mut writer = data.writer();
- let ee = self.inner.lock().extended_error;
+ let mut inner = self.inner.lock();
+ let ee = inner.extended_error;
+ inner.extended_error = ExtendedError::new(0, BR_OK, 0);
+ drop(inner);
writer.write(&ee)?;
Ok(())
}
@@ -1109,7 +1116,10 @@ impl Thread {
inner.pop_transaction_to_reply(thread.as_ref())
} {
let reply = Err(BR_DEAD_REPLY);
- if !transaction.from.deliver_single_reply(reply, &transaction) {
+ if !transaction
+ .from
+ .deliver_single_reply(reply, &transaction, None)
+ {
break;
}
@@ -1121,8 +1131,9 @@ impl Thread {
&self,
reply: Result<DLArc<Transaction>, u32>,
transaction: &DArc<Transaction>,
+ extended_error: Option<ExtendedError>,
) {
- if self.deliver_single_reply(reply, transaction) {
+ if self.deliver_single_reply(reply, transaction, extended_error) {
transaction.from.unwind_transaction_stack();
}
}
@@ -1136,6 +1147,7 @@ impl Thread {
&self,
reply: Result<DLArc<Transaction>, u32>,
transaction: &DArc<Transaction>,
+ extended_error: Option<ExtendedError>,
) -> bool {
if let Ok(transaction) = &reply {
crate::trace::trace_transaction(true, transaction, Some(&self.task));
@@ -1152,6 +1164,12 @@ impl Thread {
return true;
}
+ if let Some(ee) = extended_error {
+ if inner.extended_error.command == BR_OK {
+ inner.extended_error = ee;
+ }
+ }
+
match reply {
Ok(work) => {
inner.push_work(work);
@@ -1222,6 +1240,9 @@ impl Thread {
info.buffers_size = td.buffers_size as usize;
// SAFETY: Above `read` call initializes all bytes, so this union read is ok.
info.target_handle = unsafe { td.transaction_data.target.handle };
+
+ info.debug_id = super::next_debug_id();
+
Ok(())
}
@@ -1230,6 +1251,8 @@ impl Thread {
let mut info = TransactionInfo::zeroed();
self.read_transaction_info(cmd, reader, &mut info)?;
+ self.clear_extended_error(info.debug_id);
+
let ret = if info.is_reply {
self.reply_inner(&mut info)
} else if info.is_oneway() {
@@ -1239,23 +1262,21 @@ impl Thread {
};
if let Err(err) = ret {
- if err.reply != BR_TRANSACTION_COMPLETE {
- info.reply = err.reply;
- }
-
self.push_return_work(err.reply);
- if let Some(source) = &err.source {
- info.errno = source.to_errno();
+ if err.reply != BR_TRANSACTION_COMPLETE {
info.reply = err.reply;
+ if let Some(source) = &err.source {
+ info.errno = source.to_errno();
- {
- let mut ee = self.inner.lock().extended_error;
- ee.command = err.reply;
- ee.param = source.to_errno();
+ {
+ let mut inner = self.inner.lock();
+ inner.extended_error =
+ ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
+ }
}
pr_warn!(
- "{}:{} transaction to {} failed: {source:?}",
+ "{}:{} transaction to {} failed: {err:?}",
info.from_pid,
info.from_tid,
info.to_pid
@@ -1320,18 +1341,24 @@ impl Thread {
let allow_fds = orig.flags & TF_ACCEPT_FDS != 0;
let reply = Transaction::new_reply(self, process, info, allow_fds)?;
self.inner.lock().push_work(completion);
- orig.from.deliver_reply(Ok(reply), &orig);
+ orig.from.deliver_reply(Ok(reply), &orig, None);
Ok(())
})()
.map_err(|mut err| {
// At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let
// the sender know that the transaction has completed (with an error in this case).
+
pr_warn!(
- "Failure {:?} during reply - delivering BR_FAILED_REPLY to sender.",
- err
+ "{}:{} reply to {} failed: {err:?}",
+ info.from_pid,
+ info.from_tid,
+ info.to_pid
);
- let reply = Err(BR_FAILED_REPLY);
- orig.from.deliver_reply(reply, &orig);
+
+ let param = err.source.as_ref().map_or(0, |e| e.to_errno());
+ let ee = ExtendedError::new(info.debug_id as u32, err.reply, param);
+ orig.from
+ .deliver_reply(Err(BR_FAILED_REPLY), &orig, Some(ee));
err.reply = BR_TRANSACTION_COMPLETE;
err
});
diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
index 1d9b66920a21..0e5d07b7e6f0 100644
--- a/drivers/android/binder/transaction.rs
+++ b/drivers/android/binder/transaction.rs
@@ -42,6 +42,7 @@ pub(crate) struct TransactionInfo {
pub(crate) reply: u32,
pub(crate) oneway_spam_suspect: bool,
pub(crate) is_reply: bool,
+ pub(crate) debug_id: usize,
}
impl TransactionInfo {
@@ -93,7 +94,6 @@ impl Transaction {
from: &Arc<Thread>,
info: &mut TransactionInfo,
) -> BinderResult<DLArc<Self>> {
- let debug_id = super::next_debug_id();
let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0;
let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0;
let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None };
@@ -101,7 +101,7 @@ impl Transaction {
let mut alloc = match from.copy_transaction_data(
to.clone(),
info,
- debug_id,
+ info.debug_id,
allow_fds,
txn_security_ctx_off.as_mut(),
) {
@@ -128,7 +128,7 @@ impl Transaction {
let data_address = alloc.ptr;
Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
- debug_id,
+ debug_id: info.debug_id,
target_node: Some(target_node),
from_parent,
sender_euid: Kuid::current_euid(),
@@ -152,9 +152,8 @@ impl Transaction {
info: &mut TransactionInfo,
allow_fds: bool,
) -> BinderResult<DLArc<Self>> {
- let debug_id = super::next_debug_id();
let mut alloc =
- match from.copy_transaction_data(to.clone(), info, debug_id, allow_fds, None) {
+ match from.copy_transaction_data(to.clone(), info, info.debug_id, allow_fds, None) {
Ok(alloc) => alloc,
Err(err) => {
pr_warn!("Failure in copy_transaction_data: {:?}", err);
@@ -165,7 +164,7 @@ impl Transaction {
alloc.set_info_clear_on_drop();
}
Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
- debug_id,
+ debug_id: info.debug_id,
target_node: None,
from_parent: None,
sender_euid: Kuid::current_euid(),
@@ -394,7 +393,7 @@ impl DeliverToRead for Transaction {
let send_failed_reply = ScopeGuard::new(|| {
if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
let reply = Err(BR_FAILED_REPLY);
- self.from.deliver_reply(reply, &self);
+ self.from.deliver_reply(reply, &self, None);
}
self.drop_outstanding_txn();
});
@@ -478,7 +477,7 @@ impl DeliverToRead for Transaction {
// If this is not a reply or oneway transaction, then send a dead reply.
if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
let reply = Err(BR_DEAD_REPLY);
- self.from.deliver_reply(reply, &self);
+ self.from.deliver_reply(reply, &self, None);
}
self.drop_outstanding_txn();
diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c
index f59a7856934c..efc33294212f 100644
--- a/drivers/base/firmware_loader/sysfs_upload.c
+++ b/drivers/base/firmware_loader/sysfs_upload.c
@@ -343,7 +343,6 @@ firmware_upload_register(struct module *module, struct device *parent,
goto free_fw_upload_priv;
}
fw_upload->priv = fw_sysfs;
- fw_sysfs->fw_upload_priv = fw_upload_priv;
fw_dev = &fw_sysfs->dev;
ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, NULL, 0, 0,
@@ -351,10 +350,12 @@ firmware_upload_register(struct module *module, struct device *parent,
if (ret != 0) {
if (ret > 0)
ret = -EINVAL;
- goto free_fw_sysfs;
+ put_device(fw_dev);
+ goto free_fw_upload_priv;
}
fw_priv->is_paged_buf = true;
fw_sysfs->fw_priv = fw_priv;
+ fw_sysfs->fw_upload_priv = fw_upload_priv;
ret = device_add(fw_dev);
if (ret) {
@@ -365,9 +366,6 @@ firmware_upload_register(struct module *module, struct device *parent,
return fw_upload;
-free_fw_sysfs:
- kfree(fw_sysfs);
-
free_fw_upload_priv:
kfree(fw_upload_priv);
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 5b0fab7b89b5..c6f80c419e90 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -620,7 +620,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
if (btmtksdio_rx_packet(bdev, rx_size) < 0)
bdev->hdev->stat.err_rx++;
}
- } while (int_status || time_is_before_jiffies(txrx_timeout));
+ } while (int_status && time_is_after_jiffies(txrx_timeout));
/* Enable interrupt */
if (bdev->func->irq_handler)
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index e7036a48ce48..6a1cffe08d5f 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -1267,6 +1267,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
}
nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
+ if (nxpdev->fw_dnld_v3_offset >= nxpdev->fw->size ||
+ len > nxpdev->fw->size - nxpdev->fw_dnld_v3_offset) {
+ bt_dev_err(hdev, "FW download out of bounds, ignoring request");
+ len = 0;
+ goto free_skb;
+ }
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
nxpdev->fw_dnld_v3_offset, len);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 830fefb342c6..cc6392f8d98c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -531,6 +531,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x7392, 0xe611), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x2c4e, 0x0128), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
/* Realtek 8852AE Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK |
@@ -2994,6 +2996,11 @@ static int marvell_config_oob_wake(struct hci_dev *hdev)
return 0;
}
+#else
+static inline int marvell_config_oob_wake(struct hci_dev *hdev)
+{
+ return 0;
+}
#endif
static int btusb_set_bdaddr_marvell(struct hci_dev *hdev,
@@ -3836,6 +3843,11 @@ static int btusb_config_oob_wake(struct hci_dev *hdev)
bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq);
return 0;
}
+#else
+static inline int btusb_config_oob_wake(struct hci_dev *hdev)
+{
+ return 0;
+}
#endif
static void btusb_check_needs_reset_resume(struct usb_interface *intf)
@@ -4172,7 +4184,6 @@ static int btusb_probe(struct usb_interface *intf,
hdev->wakeup = btusb_wakeup;
hdev->hci_drv = &btusb_hci_drv;
-#ifdef CONFIG_PM
err = btusb_config_oob_wake(hdev);
if (err)
goto out_free_dev;
@@ -4181,9 +4192,9 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) {
err = marvell_config_oob_wake(hdev);
if (err)
- goto out_free_dev;
+ goto err_disable_wakeup;
}
-#endif
+
if (id->driver_info & BTUSB_CW6622)
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_STORED_LINK_KEY);
@@ -4218,7 +4229,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INTEL_COMBINED) {
err = btintel_configure_setup(hdev, btusb_driver.name);
if (err)
- goto out_free_dev;
+ goto err_kill_tx_urbs;
/* Transport specific configuration */
hdev->send = btusb_send_frame_intel;
@@ -4381,7 +4392,7 @@ static int btusb_probe(struct usb_interface *intf,
err = usb_set_interface(data->udev, 0, 0);
if (err < 0) {
BT_ERR("failed to set interface 0, alt 0 %d", err);
- goto out_free_dev;
+ goto err_kill_tx_urbs;
}
}
@@ -4389,7 +4400,7 @@ static int btusb_probe(struct usb_interface *intf,
err = usb_driver_claim_interface(&btusb_driver,
data->isoc, data);
if (err < 0)
- goto out_free_dev;
+ goto err_kill_tx_urbs;
}
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) && data->diag) {
@@ -4407,7 +4418,7 @@ static int btusb_probe(struct usb_interface *intf,
err = hci_register_dev(hdev);
if (err < 0)
- goto out_free_dev;
+ goto err_release_siblings;
usb_set_intfdata(intf, data);
@@ -4416,6 +4427,20 @@ static int btusb_probe(struct usb_interface *intf,
return 0;
+err_release_siblings:
+ if (data->diag) {
+ usb_set_intfdata(data->diag, NULL);
+ usb_driver_release_interface(&btusb_driver, data->diag);
+ }
+ if (data->isoc) {
+ usb_set_intfdata(data->isoc, NULL);
+ usb_driver_release_interface(&btusb_driver, data->isoc);
+ }
+err_kill_tx_urbs:
+ usb_kill_anchored_urbs(&data->tx_anchor);
+err_disable_wakeup:
+ if (data->oob_wake_irq)
+ device_init_wakeup(&data->udev->dev, false);
out_free_dev:
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 47f4902b40b4..2ad42c3bbaac 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -239,6 +239,8 @@ static int hci_uart_flush(struct hci_dev *hdev)
BT_DBG("hdev %p tty %p", hdev, tty);
+ disable_work_sync(&hu->write_work);
+
if (hu->tx_skb) {
kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
}
@@ -254,6 +256,14 @@ static int hci_uart_flush(struct hci_dev *hdev)
percpu_up_read(&hu->proto_lock);
+ /* Resume TX. Also reschedule in case work was queued concurrently;
+ * this may schedule write_work although there's nothing to do.
+ */
+ enable_work(&hu->write_work);
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
+ hci_uart_tx_wakeup(hu);
+
return 0;
}
@@ -271,12 +281,8 @@ static int hci_uart_open(struct hci_dev *hdev)
/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
BT_DBG("hdev %p", hdev);
- cancel_work_sync(&hu->write_work);
-
hci_uart_flush(hdev);
hdev->flush = NULL;
return 0;
diff --git a/drivers/char/hw_random/jh7110-trng.c b/drivers/char/hw_random/jh7110-trng.c
index 9776f4daa044..4712c3c530e4 100644
--- a/drivers/char/hw_random/jh7110-trng.c
+++ b/drivers/char/hw_random/jh7110-trng.c
@@ -256,19 +256,22 @@ static int starfive_trng_read(struct hwrng *rng, void *buf, size_t max, bool wai
if (wait) {
ret = starfive_trng_wait_idle(trng);
- if (ret)
- return -ETIMEDOUT;
+ if (ret) {
+ ret = -ETIMEDOUT;
+ goto out_put;
+ }
}
ret = starfive_trng_cmd(trng, STARFIVE_CTRL_GENE_RANDNUM, wait);
if (ret)
- return ret;
+ goto out_put;
memcpy_fromio(buf, trng->base + STARFIVE_RAND0, max);
+ ret = max;
+out_put:
pm_runtime_put_sync_autosuspend(trng->dev);
-
- return max;
+ return ret;
}
static int starfive_trng_probe(struct platform_device *pdev)
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 0ce02d7e5048..5e83ffa105e4 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -7,6 +7,7 @@
#include <asm/barrier.h>
#include <linux/err.h>
#include <linux/hw_random.h>
+#include <linux/nospec.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/virtio.h>
@@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
static unsigned int copy_data(struct virtrng_info *vi, void *buf,
unsigned int size)
{
- size = min_t(unsigned int, size, vi->data_avail);
- memcpy(buf, vi->data + vi->data_idx, size);
+ unsigned int idx, avail;
+
+ /*
+ * vi->data_avail was set from the device-reported used.len and
+ * vi->data_idx was advanced by previous copy_data() calls. A
+ * malicious or buggy virtio-rng backend can drive either past
+ * sizeof(vi->data). Clamp at point of use and harden the index
+ * with array_index_nospec() so the memcpy() below cannot be
+ * steered into adjacent slab memory, including under
+ * speculation.
+ */
+ avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
+ if (vi->data_idx >= avail) {
+ vi->data_avail = 0;
+ request_entropy(vi);
+ return 0;
+ }
+ size = min_t(unsigned int, size, avail - vi->data_idx);
+ idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
+ memcpy(buf, vi->data + idx, size);
vi->data_idx += size;
vi->data_avail -= size;
if (vi->data_avail == 0)
diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c
index 355558893e5f..bfe16d2d5104 100644
--- a/drivers/clocksource/timer-tegra186.c
+++ b/drivers/clocksource/timer-tegra186.c
@@ -149,7 +149,8 @@ static void tegra186_wdt_enable(struct tegra186_wdt *wdt)
u32 value;
/* unmask hardware IRQ, this may have been lost across powergate */
- value = TKEIE_WDT_MASK(wdt->index, 1);
+ value = readl(tegra->regs + TKEIE(wdt->tmr->hwirq));
+ value |= TKEIE_WDT_MASK(wdt->index, 1);
writel(value, tegra->regs + TKEIE(wdt->tmr->hwirq));
/* clear interrupt */
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 44eb1b7e7fc1..d41067cd1f1b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1972,6 +1972,7 @@ void cpufreq_suspend(void)
if (!cpufreq_driver)
return;
+ cpus_read_lock();
if (!has_target() && !cpufreq_driver->suspend)
goto suspend;
@@ -1991,6 +1992,7 @@ void cpufreq_suspend(void)
suspend:
cpufreq_suspended = true;
+ cpus_read_unlock();
}
/**
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 1f093e346430..0fbbdbd5765c 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2984,10 +2984,12 @@ static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
* from getting to lower performance levels, so force the minimum
* performance on CPU offline to prevent that from happening.
*/
- if (hwp_active)
+ if (hwp_active) {
intel_pstate_hwp_offline(cpu);
- else
+ } else {
intel_pstate_set_min_pstate(cpu);
+ policy->cur = cpu->pstate.min_freq;
+ }
intel_pstate_exit_perf_limits(policy);
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index ac2e90a65f0c..a355ec4f3dd4 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -352,6 +352,8 @@ static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
}
kfree(output.pointer);
+ output.pointer = NULL;
+ output.length = ACPI_ALLOCATE_BUFFER;
capabilities[0] = 0x0;
capabilities[1] = 0x1;
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index ea9a20d27b8f..ef19faedbfec 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -578,7 +578,6 @@ static void qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
qcom_cpufreq_hw_lmh_exit(data);
kfree(policy->freq_table);
- kfree(data);
}
static void qcom_cpufreq_ready(struct cpufreq_policy *policy)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index d23b58b81ca3..0712e9bf6e54 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -301,7 +301,6 @@ config CRYPTO_DEV_PPC4XX
select CRYPTO_CCM
select CRYPTO_CTR
select CRYPTO_GCM
- select CRYPTO_RNG
select CRYPTO_SKCIPHER
help
This option allows you to have support for AMCC crypto acceleration.
@@ -846,7 +845,6 @@ config CRYPTO_DEV_CCREE
If unsure say Y.
source "drivers/crypto/hisilicon/Kconfig"
-source "drivers/crypto/loongson/Kconfig"
source "drivers/crypto/amlogic/Kconfig"
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..ad773158ae56 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -43,7 +43,6 @@ obj-y += inside-secure/
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
obj-y += xilinx/
obj-y += hisilicon/
-obj-y += loongson/
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
obj-y += intel/
obj-y += starfive/
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index b7b6c97d2147..68c5ff7a85b4 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -31,11 +31,9 @@
#include <crypto/ctr.h>
#include <crypto/gcm.h>
#include <crypto/sha1.h>
-#include <crypto/rng.h>
#include <crypto/scatterwalk.h>
#include <crypto/skcipher.h>
#include <crypto/internal/aead.h>
-#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_core.h"
@@ -985,10 +983,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
rc = crypto_register_aead(&alg->alg.u.aead);
break;
- case CRYPTO_ALG_TYPE_RNG:
- rc = crypto_register_rng(&alg->alg.u.rng);
- break;
-
default:
rc = crypto_register_skcipher(&alg->alg.u.cipher);
break;
@@ -1014,10 +1008,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
crypto_unregister_aead(&alg->alg.u.aead);
break;
- case CRYPTO_ALG_TYPE_RNG:
- crypto_unregister_rng(&alg->alg.u.rng);
- break;
-
default:
crypto_unregister_skcipher(&alg->alg.u.cipher);
}
@@ -1076,69 +1066,6 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
PPC4XX_TMO_ERR_INT);
}
-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
- u8 *data, unsigned int max)
-{
- unsigned int i, curr = 0;
- u32 val[2];
-
- do {
- /* trigger PRN generation */
- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
-
- for (i = 0; i < 1024; i++) {
- /* usually 19 iterations are enough */
- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
- CRYPTO4XX_PRNG_STAT_BUSY))
- continue;
-
- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
- break;
- }
- if (i == 1024)
- return -ETIMEDOUT;
-
- if ((max - curr) >= 8) {
- memcpy(data, &val, 8);
- data += 8;
- curr += 8;
- } else {
- /* copy only remaining bytes */
- memcpy(data, &val, max - curr);
- break;
- }
- } while (curr < max);
-
- return curr;
-}
-
-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
- const u8 *src, unsigned int slen,
- u8 *dstn, unsigned int dlen)
-{
- struct rng_alg *alg = crypto_rng_alg(tfm);
- struct crypto4xx_alg *amcc_alg;
- struct crypto4xx_device *dev;
- int ret;
-
- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
- dev = amcc_alg->dev;
-
- mutex_lock(&dev->core_dev->rng_lock);
- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
- mutex_unlock(&dev->core_dev->rng_lock);
- return ret;
-}
-
-
-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- return 0;
-}
-
/*
* Supported Crypto Algorithms
*/
@@ -1268,18 +1195,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_module = THIS_MODULE,
},
} },
- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "crypto4xx_rng",
- .cra_priority = 300,
- .cra_ctxsize = 0,
- .cra_module = THIS_MODULE,
- },
- .generate = crypto4xx_prng_generate,
- .seed = crypto4xx_prng_seed,
- .seedsize = 0,
- } },
};
/*
@@ -1353,9 +1268,6 @@ static int crypto4xx_probe(struct platform_device *ofdev)
core_dev->dev->core_dev = core_dev;
core_dev->dev->is_revb = is_revb;
core_dev->device = dev;
- rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock);
- if (rc)
- return rc;
spin_lock_init(&core_dev->lock);
INIT_LIST_HEAD(&core_dev->dev->alg_list);
ratelimit_default_init(&core_dev->dev->aead_ratelimit);
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index ee36630c670f..3a028aec3f0c 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -14,10 +14,8 @@
#define __CRYPTO4XX_CORE_H__
#include <linux/ratelimit.h>
-#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <crypto/internal/aead.h>
-#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_sa.h"
@@ -111,7 +109,6 @@ struct crypto4xx_core_device {
u32 irq;
struct tasklet_struct tasklet;
spinlock_t lock;
- struct mutex rng_lock;
};
struct crypto4xx_ctx {
@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {
union {
struct skcipher_alg cipher;
struct aead_alg aead;
- struct rng_alg rng;
} u;
};
diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
index 1038061224da..73d626308a84 100644
--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
+++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
@@ -90,20 +90,9 @@
#define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
#define CRYPTO4XX_ENDIAN_CFG 0x000600d8
-#define CRYPTO4XX_PRNG_STAT 0x00070000
-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
#define CRYPTO4XX_PRNG_CTRL 0x00070004
#define CRYPTO4XX_PRNG_SEED_L 0x00070008
#define CRYPTO4XX_PRNG_SEED_H 0x0007000c
-
-#define CRYPTO4XX_PRNG_RES_0 0x00070020
-#define CRYPTO4XX_PRNG_RES_1 0x00070024
-#define CRYPTO4XX_PRNG_RES_2 0x00070028
-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
-
-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
-
/*
* Initialize CRYPTO ENGINE registers, and memory bases.
*/
diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c
index 1c18a5b8470e..6cb33949915f 100644
--- a/drivers/crypto/amlogic/amlogic-gxl-core.c
+++ b/drivers/crypto/amlogic/amlogic-gxl-core.c
@@ -291,8 +291,8 @@ static int meson_crypto_probe(struct platform_device *pdev)
return 0;
error_alg:
meson_unregister_algs(mc);
-error_flow:
meson_free_chanlist(mc, MAXFLOW - 1);
+error_flow:
clk_disable_unprepare(mc->busclk);
return err;
}
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index dbb39ed0cea1..987eadae2007 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -19,6 +19,12 @@
#include <linux/workqueue.h>
#include "atmel-i2c.h"
+/*
+ * According to review by Bill Cox [1], the ATSHA204 has very low entropy.
+ * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
+ */
+static const unsigned short atsha204_quality = 1;
+
static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
void *areq, int status)
{
@@ -158,6 +164,7 @@ static const struct attribute_group atmel_sha204a_groups = {
static int atmel_sha204a_probe(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv;
+ const unsigned short *quality;
int ret;
ret = atmel_i2c_probe(client);
@@ -171,19 +178,19 @@ static int atmel_sha204a_probe(struct i2c_client *client)
i2c_priv->hwrng.name = dev_name(&client->dev);
i2c_priv->hwrng.read = atmel_sha204a_rng_read;
- /*
- * According to review by Bill Cox [1], this HWRNG has very low entropy.
- * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
- */
- i2c_priv->hwrng.quality = 1;
+ quality = i2c_get_match_data(client);
+ if (quality)
+ i2c_priv->hwrng.quality = *quality;
ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng);
- if (ret)
- dev_warn(&client->dev, "failed to register RNG (%d)\n", ret);
+ if (ret) {
+ dev_err(&client->dev, "failed to register RNG (%d)\n", ret);
+ return ret;
+ }
ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups);
if (ret) {
- dev_err(&client->dev, "failed to register sysfs entry\n");
+ dev_err(&client->dev, "failed to create sysfs group (%d)\n", ret);
return ret;
}
@@ -203,14 +210,14 @@ static void atmel_sha204a_remove(struct i2c_client *client)
}
static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = {
- { .compatible = "atmel,atsha204", },
+ { .compatible = "atmel,atsha204", .data = &atsha204_quality },
{ .compatible = "atmel,atsha204a", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
static const struct i2c_device_id atmel_sha204a_id[] = {
- { "atsha204" },
+ { "atsha204", (kernel_ulong_t)&atsha204_quality },
{ "atsha204a" },
{ /* sentinel */ }
};
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 32a6e6e15ee2..ddbd60cf3b3c 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -603,7 +603,7 @@ static int aead_setkey(struct crypto_aead *aead,
dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
keys.authkeylen + keys.enckeylen, keys.enckeylen,
keys.authkeylen);
- print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/*
@@ -639,7 +639,7 @@ static int aead_setkey(struct crypto_aead *aead,
dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
keys.enckeylen, ctx->dir);
- print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ",
+ print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
ctx->adata.keylen_pad + keys.enckeylen, 1);
@@ -680,7 +680,7 @@ static int gcm_setkey(struct crypto_aead *aead,
if (err)
return err;
- print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -701,7 +701,7 @@ static int rfc4106_setkey(struct crypto_aead *aead,
if (err)
return err;
- print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -727,7 +727,7 @@ static int rfc4543_setkey(struct crypto_aead *aead,
if (err)
return err;
- print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -754,7 +754,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
u32 *desc;
const bool is_rfc3686 = alg->caam.rfc3686;
- print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/* Here keylen is actual key length */
diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c
index 65f6adb6c673..aa779caacfe5 100644
--- a/drivers/crypto/caam/caamalg_qi.c
+++ b/drivers/crypto/caam/caamalg_qi.c
@@ -212,7 +212,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
keys.authkeylen + keys.enckeylen, keys.enckeylen,
keys.authkeylen);
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/*
@@ -248,7 +248,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
ctx->adata.keylen_pad + keys.enckeylen,
ctx->dir);
- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
+ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
ctx->adata.keylen_pad + keys.enckeylen, 1);
@@ -371,7 +371,7 @@ static int gcm_setkey(struct crypto_aead *aead,
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -475,7 +475,7 @@ static int rfc4106_setkey(struct crypto_aead *aead,
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -581,7 +581,7 @@ static int rfc4543_setkey(struct crypto_aead *aead,
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -631,7 +631,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
const bool is_rfc3686 = alg->caam.rfc3686;
int ret = 0;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
ctx->cdata.keylen = keylen;
diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
index bf10c3dda745..6b47bcc16a50 100644
--- a/drivers/crypto/caam/caamalg_qi2.c
+++ b/drivers/crypto/caam/caamalg_qi2.c
@@ -301,7 +301,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n",
keys.authkeylen + keys.enckeylen, keys.enckeylen,
keys.authkeylen);
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
ctx->adata.keylen = keys.authkeylen;
@@ -315,7 +315,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
keys.enckeylen, ctx->dir);
- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
+ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
ctx->adata.keylen_pad + keys.enckeylen, 1);
@@ -732,7 +732,7 @@ static int gcm_setkey(struct crypto_aead *aead,
ret = aes_check_keylen(keylen);
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -828,7 +828,7 @@ static int rfc4106_setkey(struct crypto_aead *aead,
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -927,7 +927,7 @@ static int rfc4543_setkey(struct crypto_aead *aead,
if (ret)
return ret;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -955,7 +955,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
u32 *desc;
const bool is_rfc3686 = alg->caam.rfc3686;
- print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key in @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
ctx->cdata.keylen = keylen;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index ddb2a35aec2d..3cd71810380f 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -505,7 +505,7 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key,
DMA_TO_DEVICE);
ctx->adata.keylen = keylen;
- print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ",
+ print_hex_dump_devel("axcbc ctx.key@" __stringify(__LINE__)" : ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, keylen, 1);
return axcbc_set_sh_desc(ahash);
@@ -525,7 +525,7 @@ static int acmac_setkey(struct crypto_ahash *ahash, const u8 *key,
ctx->adata.key_virt = key;
ctx->adata.keylen = keylen;
- print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ",
+ print_hex_dump_devel("acmac ctx.key@" __stringify(__LINE__)" : ",
DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
return acmac_set_sh_desc(ahash);
diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c
index 88cc4fe2a585..de2fcc387477 100644
--- a/drivers/crypto/caam/key_gen.c
+++ b/drivers/crypto/caam/key_gen.c
@@ -58,7 +58,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
dev_dbg(jrdev, "split keylen %d split keylen padded %d\n",
adata->keylen, adata->keylen_pad);
- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
+ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1);
if (local_max > max_keylen)
@@ -113,7 +113,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
wait_for_completion(&result.completion);
ret = result.err;
- print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ",
+ print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key_out,
adata->keylen_pad, 1);
}
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index d1e9e0ac63b6..7c4dd57fabb9 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -1716,29 +1716,11 @@ static int sev_get_platform_state(int *state, int *error)
static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required)
{
- struct sev_platform_init_args init_args = {0};
int rc;
- rc = _sev_platform_init_locked(&init_args);
- if (rc) {
- argp->error = SEV_RET_INVALID_PLATFORM_STATE;
- return rc;
- }
-
- *shutdown_required = true;
-
- return 0;
-}
-
-static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required)
-{
- int error, rc;
-
- rc = __sev_snp_init_locked(&error, 0);
- if (rc) {
- argp->error = SEV_RET_INVALID_PLATFORM_STATE;
+ rc = __sev_platform_init_locked(&argp->error);
+ if (rc)
return rc;
- }
*shutdown_required = true;
@@ -2440,24 +2422,13 @@ cleanup:
static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp)
{
- struct sev_device *sev = psp_master->sev_data;
struct sev_data_snp_commit buf;
- bool shutdown_required = false;
- int ret, error;
-
- if (!sev->snp_initialized) {
- ret = snp_move_to_init_state(argp, &shutdown_required);
- if (ret)
- return ret;
- }
+ int ret;
buf.len = sizeof(buf);
ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error);
- if (shutdown_required)
- __sev_snp_shutdown_locked(&error, false);
-
return ret;
}
@@ -2465,8 +2436,6 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable
{
struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_snp_config config;
- bool shutdown_required = false;
- int ret, error;
if (!argp->data)
return -EINVAL;
@@ -2474,30 +2443,21 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable
if (!writable)
return -EPERM;
+ if (!sev->snp_initialized)
+ return -ENODEV;
+
if (copy_from_user(&config, (void __user *)argp->data, sizeof(config)))
return -EFAULT;
- if (!sev->snp_initialized) {
- ret = snp_move_to_init_state(argp, &shutdown_required);
- if (ret)
- return ret;
- }
-
- ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error);
-
- if (shutdown_required)
- __sev_snp_shutdown_locked(&error, false);
-
- return ret;
+ return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error);
}
static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable)
{
struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_snp_vlek_load input;
- bool shutdown_required = false;
- int ret, error;
void *blob;
+ int ret;
if (!argp->data)
return -EINVAL;
@@ -2505,6 +2465,9 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable)
if (!writable)
return -EPERM;
+ if (!sev->snp_initialized)
+ return -ENODEV;
+
if (copy_from_user(&input, u64_to_user_ptr(argp->data), sizeof(input)))
return -EFAULT;
@@ -2518,18 +2481,7 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable)
input.vlek_wrapped_address = __psp_pa(blob);
- if (!sev->snp_initialized) {
- ret = snp_move_to_init_state(argp, &shutdown_required);
- if (ret)
- goto cleanup;
- }
-
ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error);
-
- if (shutdown_required)
- __sev_snp_shutdown_locked(&error, false);
-
-cleanup:
kfree(blob);
return ret;
diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
index 1e6d772f4bb6..8aa23c939775 100644
--- a/drivers/crypto/hisilicon/Kconfig
+++ b/drivers/crypto/hisilicon/Kconfig
@@ -80,6 +80,5 @@ config CRYPTO_DEV_HISI_TRNG
tristate "Support for HISI TRNG Driver"
depends on ARM64 && ACPI
select HW_RANDOM
- select CRYPTO_RNG
help
Support for HiSilicon TRNG Driver.
diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
index 5ca0b90859a8..6584ed051e09 100644
--- a/drivers/crypto/hisilicon/trng/trng.c
+++ b/drivers/crypto/hisilicon/trng/trng.c
@@ -1,234 +1,27 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
-#include <crypto/internal/rng.h>
#include <linux/acpi.h>
-#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
-#include <linux/list.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#define HISI_TRNG_REG 0x00F0
#define HISI_TRNG_BYTES 4
#define HISI_TRNG_QUALITY 512
-#define HISI_TRNG_VERSION 0x01B8
-#define HISI_TRNG_VER_V1 GENMASK(31, 0)
#define SLEEP_US 10
#define TIMEOUT_US 10000
-#define SW_DRBG_NUM_SHIFT 2
-#define SW_DRBG_KEY_BASE 0x082C
-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
-#define SW_DRBG_SEED_REGS_NUM 12
-#define SW_DRBG_SEED_SIZE 48
-#define SW_DRBG_BLOCKS 0x0830
-#define SW_DRBG_INIT 0x0834
-#define SW_DRBG_GEN 0x083c
-#define SW_DRBG_STATUS 0x0840
-#define SW_DRBG_BLOCKS_NUM 4095
-#define SW_DRBG_DATA_BASE 0x0850
-#define SW_DRBG_DATA_NUM 4
-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
-#define SW_DRBG_BYTES 16
-#define SW_DRBG_ENABLE_SHIFT 12
-#define SEED_SHIFT_24 24
-#define SEED_SHIFT_16 16
-#define SEED_SHIFT_8 8
-#define SW_MAX_RANDOM_BYTES 65520
-
-struct hisi_trng_list {
- struct mutex lock;
- struct list_head list;
- bool is_init;
-};
struct hisi_trng {
void __iomem *base;
- struct hisi_trng_list *trng_list;
- struct list_head list;
struct hwrng rng;
- u32 ver;
- u32 ctx_num;
- /* The bytes of the random number generated since the last seeding. */
- u32 random_bytes;
- struct mutex lock;
-};
-
-struct hisi_trng_ctx {
- struct hisi_trng *trng;
};
-static atomic_t trng_active_devs;
-static struct hisi_trng_list trng_devices;
-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
-
-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
-{
- u32 val, seed_reg, i;
- int ret;
-
- writel(0x0, trng->base + SW_DRBG_BLOCKS);
-
- for (i = 0; i < SW_DRBG_SEED_SIZE;
- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
- val = seed[i] << SEED_SHIFT_24;
- val |= seed[i + 1UL] << SEED_SHIFT_16;
- val |= seed[i + 2UL] << SEED_SHIFT_8;
- val |= seed[i + 3UL];
-
- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
- writel(val, trng->base + SW_DRBG_SEED(seed_reg));
- }
-
- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
- trng->base + SW_DRBG_BLOCKS);
- writel(0x1, trng->base + SW_DRBG_INIT);
- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
- if (ret) {
- pr_err("failed to init trng(%d)\n", ret);
- return -EIO;
- }
-
- trng->random_bytes = 0;
-
- return 0;
-}
-
-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
- struct hisi_trng *trng = ctx->trng;
- int ret;
-
- if (slen < SW_DRBG_SEED_SIZE) {
- pr_err("slen(%u) is not matched with trng(%d)\n", slen,
- SW_DRBG_SEED_SIZE);
- return -EINVAL;
- }
-
- mutex_lock(&trng->lock);
- ret = hisi_trng_set_seed(trng, seed);
- mutex_unlock(&trng->lock);
-
- return ret;
-}
-
-static int hisi_trng_reseed(struct hisi_trng *trng)
-{
- u8 seed[SW_DRBG_SEED_SIZE];
- int size;
-
- if (!trng->random_bytes)
- return 0;
-
- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
- if (size != SW_DRBG_SEED_SIZE)
- return -EIO;
-
- return hisi_trng_set_seed(trng, seed);
-}
-
-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
-{
- u32 data[SW_DRBG_DATA_NUM];
- u32 currsize = 0;
- u32 val = 0;
- int ret;
- u32 i;
-
- ret = hisi_trng_reseed(trng);
- if (ret)
- return ret;
-
- do {
- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
- if (ret) {
- pr_err("failed to generate random number(%d)!\n", ret);
- break;
- }
-
- for (i = 0; i < SW_DRBG_DATA_NUM; i++)
- data[i] = readl(trng->base + SW_DRBG_DATA(i));
-
- if (dlen - currsize >= SW_DRBG_BYTES) {
- memcpy(dstn + currsize, data, SW_DRBG_BYTES);
- currsize += SW_DRBG_BYTES;
- } else {
- memcpy(dstn + currsize, data, dlen - currsize);
- currsize = dlen;
- }
-
- trng->random_bytes += SW_DRBG_BYTES;
- writel(0x1, trng->base + SW_DRBG_GEN);
- } while (currsize < dlen);
-
- return ret;
-}
-
-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
- unsigned int slen, u8 *dstn, unsigned int dlen)
-{
- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
- struct hisi_trng *trng = ctx->trng;
- unsigned int currsize = 0;
- unsigned int block_size;
- int ret;
-
- if (!dstn || !dlen) {
- pr_err("output is error, dlen %u!\n", dlen);
- return -EINVAL;
- }
-
- do {
- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
- mutex_lock(&trng->lock);
- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
- mutex_unlock(&trng->lock);
- if (ret)
- return ret;
- currsize += block_size;
- } while (currsize < dlen);
-
- return 0;
-}
-
-static int hisi_trng_init(struct crypto_tfm *tfm)
-{
- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
- struct hisi_trng *trng;
- u32 ctx_num = ~0;
-
- mutex_lock(&trng_devices.lock);
- list_for_each_entry(trng, &trng_devices.list, list) {
- if (trng->ctx_num < ctx_num) {
- ctx_num = trng->ctx_num;
- ctx->trng = trng;
- }
- }
- ctx->trng->ctx_num++;
- mutex_unlock(&trng_devices.lock);
-
- return 0;
-}
-
-static void hisi_trng_exit(struct crypto_tfm *tfm)
-{
- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
-
- mutex_lock(&trng_devices.lock);
- ctx->trng->ctx_num--;
- mutex_unlock(&trng_devices.lock);
-}
-
static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
struct hisi_trng *trng;
@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
return currsize;
}
-static struct rng_alg hisi_trng_alg = {
- .generate = hisi_trng_generate,
- .seed = hisi_trng_seed,
- .seedsize = SW_DRBG_SEED_SIZE,
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "hisi_stdrng",
- .cra_priority = 300,
- .cra_ctxsize = sizeof(struct hisi_trng_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = hisi_trng_init,
- .cra_exit = hisi_trng_exit,
- },
-};
-
-static void hisi_trng_add_to_list(struct hisi_trng *trng)
-{
- mutex_lock(&trng_devices.lock);
- list_add_tail(&trng->list, &trng_devices.list);
- mutex_unlock(&trng_devices.lock);
-}
-
-static int hisi_trng_del_from_list(struct hisi_trng *trng)
-{
- int ret = -EBUSY;
-
- mutex_lock(&trng_devices.lock);
- if (!trng->ctx_num) {
- list_del(&trng->list);
- ret = 0;
- }
- mutex_unlock(&trng_devices.lock);
-
- return ret;
-}
-
static int hisi_trng_probe(struct platform_device *pdev)
{
struct hisi_trng *trng;
@@ -305,68 +62,20 @@ static int hisi_trng_probe(struct platform_device *pdev)
if (!trng)
return -ENOMEM;
- platform_set_drvdata(pdev, trng);
-
trng->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(trng->base))
return PTR_ERR(trng->base);
- trng->ctx_num = 0;
- trng->random_bytes = SW_MAX_RANDOM_BYTES;
- mutex_init(&trng->lock);
- trng->ver = readl(trng->base + HISI_TRNG_VERSION);
- if (!trng_devices.is_init) {
- INIT_LIST_HEAD(&trng_devices.list);
- mutex_init(&trng_devices.lock);
- trng_devices.is_init = true;
- }
-
- hisi_trng_add_to_list(trng);
- if (trng->ver != HISI_TRNG_VER_V1 &&
- atomic_inc_return(&trng_active_devs) == 1) {
- ret = crypto_register_rng(&hisi_trng_alg);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to register crypto(%d)\n", ret);
- atomic_dec_return(&trng_active_devs);
- goto err_remove_from_list;
- }
- }
-
trng->rng.name = pdev->name;
trng->rng.read = hisi_trng_read;
trng->rng.quality = HISI_TRNG_QUALITY;
+
ret = devm_hwrng_register(&pdev->dev, &trng->rng);
- if (ret) {
+ if (ret)
dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
- goto err_crypto_unregister;
- }
-
- return ret;
-
-err_crypto_unregister:
- if (trng->ver != HISI_TRNG_VER_V1 &&
- atomic_dec_return(&trng_active_devs) == 0)
- crypto_unregister_rng(&hisi_trng_alg);
-
-err_remove_from_list:
- hisi_trng_del_from_list(trng);
return ret;
}
-static void hisi_trng_remove(struct platform_device *pdev)
-{
- struct hisi_trng *trng = platform_get_drvdata(pdev);
-
- /* Wait until the task is finished */
- while (hisi_trng_del_from_list(trng))
- ;
-
- if (trng->ver != HISI_TRNG_VER_V1 &&
- atomic_dec_return(&trng_active_devs) == 0)
- crypto_unregister_rng(&hisi_trng_alg);
-}
-
static const struct acpi_device_id hisi_trng_acpi_match[] = {
{ "HISI02B3", 0 },
{ }
@@ -375,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
static struct platform_driver hisi_trng_driver = {
.probe = hisi_trng_probe,
- .remove = hisi_trng_remove,
.driver = {
.name = "hisi-trng-v2",
.acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
index cfa00daeb4fb..3acbbb586dc0 100644
--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
@@ -146,8 +146,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- pci_set_master(pdev);
-
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state.\n");
ret = -ENOMEM;
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
index c9be5dcddb27..f33182c101e2 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
@@ -148,8 +148,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- pci_set_master(pdev);
-
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state.\n");
ret = -ENOMEM;
diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
index c52462a48c34..ab62b91ecb51 100644
--- a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
@@ -189,8 +189,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- pci_set_master(pdev);
-
/*
* The PCI config space is saved at this point and will be restored
* after a Function Level Reset (FLR) as the FLR does not completely
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
index bceb5dd8b148..c745397e63a5 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
index c622793e94a8..b31c58fdfb58 100644
--- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
/* Completion for VF2PF request/response message exchange */
init_completion(&accel_dev->vf.msg_received);
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
index 23ccb72b6ea2..941400c64d4b 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
index 4840d44bbd5b..631eb2b41150 100644
--- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
/* Completion for VF2PF request/response message exchange */
init_completion(&accel_dev->vf.msg_received);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
index cbd1d1eda5a3..58cf98fadb6c 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
@@ -475,6 +475,8 @@ struct adf_accel_dev {
struct {
/* protects VF2PF interrupts access */
spinlock_t vf2pf_ints_lock;
+ /* prevents VF2PF handling from racing with VF state teardown */
+ bool vf2pf_disabled;
/* vf_info is non-zero when SR-IOV is init'ed */
struct adf_accel_vf_info *vf_info;
} pf;
diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index ed01fb9ad74e..3fc7d13e882c 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -17,6 +17,58 @@ struct adf_fatal_error_data {
static struct workqueue_struct *device_reset_wq;
static struct workqueue_struct *device_sriov_wq;
+static pci_ers_result_t reset_prepare(struct pci_dev *pdev)
+{
+ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
+
+ if (!accel_dev) {
+ dev_err(&pdev->dev, "Can't find acceleration device\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ if (!adf_dev_started(accel_dev))
+ return PCI_ERS_RESULT_CAN_RECOVER;
+
+ set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
+ if (accel_dev->hw_device->exit_arb) {
+ dev_dbg(&pdev->dev, "Disabling arbitration\n");
+ accel_dev->hw_device->exit_arb(accel_dev);
+ }
+ adf_dev_restarting_notify(accel_dev);
+ adf_dev_down(accel_dev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t reset_done(struct pci_dev *pdev)
+{
+ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
+ int res;
+
+ if (!accel_dev) {
+ dev_err(&pdev->dev, "Can't find acceleration device\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ if (!adf_devmgr_in_reset(accel_dev))
+ goto reset_complete;
+
+ pci_restore_state(pdev);
+ res = adf_dev_up(accel_dev, false);
+ if (res && res != -EALREADY)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ adf_reenable_sriov(accel_dev);
+ adf_pf2vf_notify_restarted(accel_dev);
+ adf_dev_restarted_notify(accel_dev);
+ clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
+
+reset_complete:
+ dev_info(&pdev->dev, "Device reset completed successfully\n");
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
@@ -33,18 +85,10 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_DISCONNECT;
}
- set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
- if (accel_dev->hw_device->exit_arb) {
- dev_dbg(&pdev->dev, "Disabling arbitration\n");
- accel_dev->hw_device->exit_arb(accel_dev);
- }
adf_error_notifier(accel_dev);
adf_pf2vf_notify_fatal_error(accel_dev);
- adf_dev_restarting_notify(accel_dev);
- pci_clear_master(pdev);
- adf_dev_down(accel_dev);
- return PCI_ERS_RESULT_NEED_RESET;
+ return reset_prepare(pdev);
}
/* reset dev data */
@@ -106,6 +150,13 @@ void adf_dev_restore(struct adf_accel_dev *accel_dev)
}
}
+void adf_set_bme(struct adf_accel_dev *accel_dev)
+{
+ struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
+
+ pci_set_master(pdev);
+}
+
static void adf_device_sriov_worker(struct work_struct *work)
{
struct adf_sriov_dev_data *sriov_data =
@@ -156,13 +207,14 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
struct adf_reset_dev_data *reset_data;
if (!adf_dev_started(accel_dev) ||
- test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+ test_and_set_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
return 0;
- set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
reset_data = kzalloc_obj(*reset_data);
- if (!reset_data)
+ if (!reset_data) {
+ clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
return -ENOMEM;
+ }
reset_data->accel_dev = accel_dev;
init_completion(&reset_data->compl);
reset_data->mode = mode;
@@ -190,26 +242,7 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
{
- struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
- int res = 0;
-
- if (!accel_dev) {
- pr_err("QAT: Can't find acceleration device\n");
- return PCI_ERS_RESULT_DISCONNECT;
- }
-
- if (!pdev->is_busmaster)
- pci_set_master(pdev);
- pci_restore_state(pdev);
- res = adf_dev_up(accel_dev, false);
- if (res && res != -EALREADY)
- return PCI_ERS_RESULT_DISCONNECT;
-
- adf_reenable_sriov(accel_dev);
- adf_pf2vf_notify_restarted(accel_dev);
- adf_dev_restarted_notify(accel_dev);
- clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
- return PCI_ERS_RESULT_RECOVERED;
+ return reset_done(pdev);
}
static void adf_resume(struct pci_dev *pdev)
@@ -218,10 +251,22 @@ static void adf_resume(struct pci_dev *pdev)
dev_info(&pdev->dev, "Device is up and running\n");
}
+static void adf_reset_prepare(struct pci_dev *pdev)
+{
+ reset_prepare(pdev);
+}
+
+static void adf_reset_done(struct pci_dev *pdev)
+{
+ reset_done(pdev);
+}
+
const struct pci_error_handlers adf_err_handler = {
.error_detected = adf_error_detected,
.slot_reset = adf_slot_reset,
.resume = adf_resume,
+ .reset_prepare = adf_reset_prepare,
+ .reset_done = adf_reset_done,
};
EXPORT_SYMBOL_GPL(adf_err_handler);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
index 8ff35dd840f3..db26e0b31170 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
@@ -84,6 +84,7 @@ extern const struct pci_error_handlers adf_err_handler;
void adf_reset_sbr(struct adf_accel_dev *accel_dev);
void adf_reset_flr(struct adf_accel_dev *accel_dev);
void adf_dev_restore(struct adf_accel_dev *accel_dev);
+void adf_set_bme(struct adf_accel_dev *accel_dev);
int adf_init_aer(void);
void adf_exit_aer(void);
int adf_init_arb(struct adf_accel_dev *accel_dev);
@@ -118,6 +119,7 @@ void qat_comp_alg_callback(void *resp);
int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
void adf_isr_resource_free(struct adf_accel_dev *accel_dev);
+void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev);
int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev);
@@ -191,6 +193,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs);
void adf_disable_sriov(struct adf_accel_dev *accel_dev);
void adf_reenable_sriov(struct adf_accel_dev *accel_dev);
void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask);
+void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs);
void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev);
bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev);
bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c
index f8088388cf12..1c7f9e49914d 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_init.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_init.c
@@ -74,6 +74,8 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev)
return -EFAULT;
}
+ adf_set_bme(accel_dev);
+
if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status) &&
!accel_dev->is_vf) {
dev_err(&GET_DEV(accel_dev), "Device not configured\n");
@@ -153,15 +155,18 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev)
* This is to facilitate any ordering dependencies between services
* prior to starting any of the accelerators.
*/
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_INIT)) {
dev_err(&GET_DEV(accel_dev),
"Failed to initialise service %s\n",
service->name);
+ mutex_unlock(&service_lock);
return -EFAULT;
}
set_bit(accel_dev->accel_id, service->init_status);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -231,15 +236,18 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
if (ret && ret != -EOPNOTSUPP)
return ret;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_START)) {
dev_err(&GET_DEV(accel_dev),
"Failed to start service %s\n",
service->name);
+ mutex_unlock(&service_lock);
return -EFAULT;
}
set_bit(accel_dev->accel_id, service->start_status);
}
+ mutex_unlock(&service_lock);
clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
set_bit(ADF_STATUS_STARTED, &accel_dev->status);
@@ -313,6 +321,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev)
qat_comp_algs_unregister(hw_data->accel_capabilities_ext_mask);
clear_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status);
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (!test_bit(accel_dev->accel_id, service->start_status))
continue;
@@ -324,6 +333,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev)
clear_bit(accel_dev->accel_id, service->start_status);
}
}
+ mutex_unlock(&service_lock);
if (hw_data->stop_timer)
hw_data->stop_timer(accel_dev);
@@ -373,6 +383,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
&accel_dev->status);
}
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (!test_bit(accel_dev->accel_id, service->init_status))
continue;
@@ -383,6 +394,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
else
clear_bit(accel_dev->accel_id, service->init_status);
}
+ mutex_unlock(&service_lock);
adf_rl_exit(accel_dev);
@@ -417,12 +429,14 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING))
dev_err(&GET_DEV(accel_dev),
"Failed to restart service %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -430,12 +444,14 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED))
dev_err(&GET_DEV(accel_dev),
"Failed to restart service %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -443,12 +459,14 @@ void adf_error_notifier(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_FATAL_ERROR))
dev_err(&GET_DEV(accel_dev),
"Failed to send error event to %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
}
int adf_dev_down(struct adf_accel_dev *accel_dev)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c
index 4639d7fd93e6..159e91a50106 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_isr.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c
@@ -62,6 +62,23 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
unsigned long flags;
spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+ if (!READ_ONCE(accel_dev->pf.vf2pf_disabled))
+ GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
+ spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
+}
+
+void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs)
+{
+ void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
+ unsigned long flags;
+ u32 vf_mask;
+
+ vf_mask = BIT_ULL(num_vfs) - 1;
+ if (!vf_mask)
+ return;
+
+ spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+ WRITE_ONCE(accel_dev->pf.vf2pf_disabled, false);
GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
}
@@ -72,6 +89,7 @@ void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
unsigned long flags;
spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+ WRITE_ONCE(accel_dev->pf.vf2pf_disabled, true);
GET_PFVF_OPS(accel_dev)->disable_all_vf2pf_interrupts(pmisc_addr);
spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
}
@@ -174,6 +192,27 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
return IRQ_NONE;
}
+void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev)
+{
+ struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
+ struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
+ u32 num_entries = pci_dev_info->msix_entries.num_entries;
+ struct adf_irq *irqs = pci_dev_info->msix_entries.irqs;
+ u32 irq_idx;
+ int irq;
+
+ if (!test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status) || !irqs)
+ return;
+
+ irq_idx = num_entries > 1 ? hw_data->num_banks : 0;
+ if (irq_idx >= num_entries || !irqs[irq_idx].enabled)
+ return;
+
+ irq = pci_irq_vector(pci_dev_info->pci_dev, hw_data->num_banks);
+ if (irq > 0)
+ synchronize_irq(irq);
+}
+
static void adf_free_irqs(struct adf_accel_dev *accel_dev)
{
struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
index 8bf0fe1fcb4d..f2011300a929 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
@@ -26,6 +26,9 @@ static void adf_iov_send_resp(struct work_struct *work)
u32 vf_nr = vf_info->vf_nr;
bool ret;
+ if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
+ goto out;
+
mutex_lock(&vf_info->pfvf_mig_lock);
ret = adf_recv_and_handle_vf2pf_msg(accel_dev, vf_nr);
if (ret)
@@ -33,13 +36,18 @@ static void adf_iov_send_resp(struct work_struct *work)
adf_enable_vf2pf_interrupts(accel_dev, 1 << vf_nr);
mutex_unlock(&vf_info->pfvf_mig_lock);
+out:
kfree(pf2vf_resp);
}
void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
{
+ struct adf_accel_dev *accel_dev = vf_info->accel_dev;
struct adf_pf2vf_resp *pf2vf_resp;
+ if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
+ return;
+
pf2vf_resp = kzalloc_obj(*pf2vf_resp, GFP_ATOMIC);
if (!pf2vf_resp)
return;
@@ -49,6 +57,12 @@ void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
queue_work(pf2vf_resp_wq, &pf2vf_resp->pf2vf_resp_work);
}
+static void adf_flush_pf2vf_resp_wq(void)
+{
+ if (pf2vf_resp_wq)
+ flush_workqueue(pf2vf_resp_wq);
+}
+
static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
{
struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
@@ -75,7 +89,11 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
hw_data->configure_iov_threads(accel_dev, true);
/* Enable VF to PF interrupts for all VFs */
- adf_enable_vf2pf_interrupts(accel_dev, BIT_ULL(totalvfs) - 1);
+ adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs);
+
+ /* Do not enable SR-IOV if already enabled */
+ if (pci_num_vf(pdev))
+ return 0;
/*
* Due to the hardware design, when SR-IOV and the ring arbiter
@@ -246,10 +264,18 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev)
adf_pf2vf_notify_restarting(accel_dev);
adf_pf2vf_wait_for_restarting_complete(accel_dev);
- pci_disable_sriov(accel_to_pci_dev(accel_dev));
+ /*
+ * When the device is restarting, preserve VF PCI devices across
+ * the reset by skipping pci_disable_sriov(). VFs are notified to
+ * quiesce regardless so the PF can safely shut down.
+ */
+ if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+ pci_disable_sriov(accel_to_pci_dev(accel_dev));
- /* Disable VF to PF interrupts */
+ /* Block VF2PF work and disable VF to PF interrupts */
adf_disable_all_vf2pf_interrupts(accel_dev);
+ adf_isr_sync_ae_cluster(accel_dev);
+ adf_flush_pf2vf_resp_wq();
/* Clear Valid bits in AE Thread to PCIe Function Mapping */
if (hw_data->configure_iov_threads)
diff --git a/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c b/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c
index e09b9edfce42..75c15c8e41db 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c
@@ -1085,7 +1085,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->p;
len = rsa_key->p_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
- if (!len)
+ if (!len || len > half_key_sz)
goto err;
ctx->p = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_p, GFP_KERNEL);
if (!ctx->p)
@@ -1096,7 +1096,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->q;
len = rsa_key->q_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
- if (!len)
+ if (!len || len > half_key_sz)
goto free_p;
ctx->q = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_q, GFP_KERNEL);
if (!ctx->q)
@@ -1107,7 +1107,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->dp;
len = rsa_key->dp_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
- if (!len)
+ if (!len || len > half_key_sz)
goto free_q;
ctx->dp = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dp,
GFP_KERNEL);
@@ -1119,7 +1119,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->dq;
len = rsa_key->dq_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
- if (!len)
+ if (!len || len > half_key_sz)
goto free_dp;
ctx->dq = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dq,
GFP_KERNEL);
@@ -1131,7 +1131,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->qinv;
len = rsa_key->qinv_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
- if (!len)
+ if (!len || len > half_key_sz)
goto free_dq;
ctx->qinv = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_qinv,
GFP_KERNEL);
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
index b59e0cc49e52..99a6bf9e2b00 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
index 7cd528ee31e7..e3eab03ad65b 100644
--- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err_free_reg;
}
}
- pci_set_master(pdev);
/* Completion for VF2PF request/response message exchange */
init_completion(&accel_dev->vf.msg_received);
diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig
deleted file mode 100644
index 15475da8fc11..000000000000
--- a/drivers/crypto/loongson/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-config CRYPTO_DEV_LOONGSON_RNG
- tristate "Support for Loongson RNG Driver"
- depends on MFD_LOONGSON_SE
- help
- Support for Loongson RNG Driver.
diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile
deleted file mode 100644
index 1ce5ec32b553..000000000000
--- a/drivers/crypto/loongson/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o
diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c
deleted file mode 100644
index 3a4940260f9e..000000000000
--- a/drivers/crypto/loongson/loongson-rng.c
+++ /dev/null
@@ -1,209 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2019 HiSilicon Limited. */
-/* Copyright (c) 2025 Loongson Technology Corporation Limited. */
-
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <linux/hw_random.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mfd/loongson-se.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <crypto/internal/rng.h>
-
-#define SE_SEED_SIZE 32
-
-struct loongson_rng_list {
- struct mutex lock;
- struct list_head list;
- int registered;
-};
-
-struct loongson_rng {
- u32 used;
- struct loongson_se_engine *engine;
- struct list_head list;
- struct mutex lock;
-};
-
-struct loongson_rng_ctx {
- struct loongson_rng *rng;
-};
-
-struct loongson_rng_cmd {
- u32 cmd_id;
- union {
- u32 len;
- u32 ret;
- } u;
- u32 seed_off;
- u32 out_off;
- u32 pad[4];
-};
-
-static struct loongson_rng_list rng_devices = {
- .lock = __MUTEX_INITIALIZER(rng_devices.lock),
- .list = LIST_HEAD_INIT(rng_devices.list),
-};
-
-static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src,
- unsigned int slen, u8 *dstn, unsigned int dlen)
-{
- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
- struct loongson_rng *rng = ctx->rng;
- struct loongson_rng_cmd *cmd = rng->engine->command;
- int err, len;
-
- mutex_lock(&rng->lock);
- cmd->seed_off = 0;
- do {
- len = min(dlen, rng->engine->buffer_size);
- cmd = rng->engine->command;
- cmd->u.len = len;
- err = loongson_se_send_engine_cmd(rng->engine);
- if (err)
- break;
-
- cmd = rng->engine->command_ret;
- if (cmd->u.ret) {
- err = -EIO;
- break;
- }
-
- memcpy(dstn, rng->engine->data_buffer, len);
- dlen -= len;
- dstn += len;
- } while (dlen > 0);
- mutex_unlock(&rng->lock);
-
- return err;
-}
-
-static int loongson_rng_init(struct crypto_tfm *tfm)
-{
- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
- struct loongson_rng *rng;
- u32 min_used = U32_MAX;
-
- mutex_lock(&rng_devices.lock);
- list_for_each_entry(rng, &rng_devices.list, list) {
- if (rng->used < min_used) {
- ctx->rng = rng;
- min_used = rng->used;
- }
- }
- ctx->rng->used++;
- mutex_unlock(&rng_devices.lock);
-
- return 0;
-}
-
-static void loongson_rng_exit(struct crypto_tfm *tfm)
-{
- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
-
- mutex_lock(&rng_devices.lock);
- ctx->rng->used--;
- mutex_unlock(&rng_devices.lock);
-}
-
-static int loongson_rng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
- struct loongson_rng *rng = ctx->rng;
- struct loongson_rng_cmd *cmd;
- int err;
-
- if (slen < SE_SEED_SIZE)
- return -EINVAL;
-
- slen = min(slen, rng->engine->buffer_size);
-
- mutex_lock(&rng->lock);
- cmd = rng->engine->command;
- cmd->u.len = slen;
- cmd->seed_off = rng->engine->buffer_off;
- memcpy(rng->engine->data_buffer, seed, slen);
- err = loongson_se_send_engine_cmd(rng->engine);
- if (err)
- goto out;
-
- cmd = rng->engine->command_ret;
- if (cmd->u.ret)
- err = -EIO;
-out:
- mutex_unlock(&rng->lock);
-
- return err;
-}
-
-static struct rng_alg loongson_rng_alg = {
- .generate = loongson_rng_generate,
- .seed = loongson_rng_seed,
- .seedsize = SE_SEED_SIZE,
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "loongson_stdrng",
- .cra_priority = 300,
- .cra_ctxsize = sizeof(struct loongson_rng_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = loongson_rng_init,
- .cra_exit = loongson_rng_exit,
- },
-};
-
-static int loongson_rng_probe(struct platform_device *pdev)
-{
- struct loongson_rng_cmd *cmd;
- struct loongson_rng *rng;
- int ret = 0;
-
- rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
- if (!rng)
- return -ENOMEM;
-
- rng->engine = loongson_se_init_engine(pdev->dev.parent, SE_ENGINE_RNG);
- if (!rng->engine)
- return -ENODEV;
- cmd = rng->engine->command;
- cmd->cmd_id = SE_CMD_RNG;
- cmd->out_off = rng->engine->buffer_off;
- mutex_init(&rng->lock);
-
- mutex_lock(&rng_devices.lock);
-
- if (!rng_devices.registered) {
- ret = crypto_register_rng(&loongson_rng_alg);
- if (ret) {
- dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret);
- goto out;
- }
- rng_devices.registered = 1;
- }
-
- list_add_tail(&rng->list, &rng_devices.list);
-out:
- mutex_unlock(&rng_devices.lock);
-
- return ret;
-}
-
-static struct platform_driver loongson_rng_driver = {
- .probe = loongson_rng_probe,
- .driver = {
- .name = "loongson-rng",
- },
-};
-module_platform_driver(loongson_rng_driver);
-
-MODULE_ALIAS("platform:loongson-rng");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>");
-MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>");
-MODULE_DESCRIPTION("Loongson Random Number Generator driver");
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index bc61d0fe3514..4b53b13f96d9 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -12,7 +12,6 @@
* All rights reserved.
*/
-#include <linux/workqueue.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -255,6 +254,46 @@ static int init_device(struct device *dev)
return 0;
}
+static void dma_map_request(struct device *dev, struct talitos_request *request,
+ struct talitos_desc *desc, bool is_sec1)
+{
+ struct talitos_edesc *edesc =
+ container_of(desc, struct talitos_edesc, desc);
+ dma_addr_t dma_desc, prev_dma_desc;
+ struct talitos_edesc *prev_edesc = NULL;
+
+ if (is_sec1) {
+ while (edesc) {
+ edesc->desc.hdr1 = edesc->desc.hdr;
+
+ dma_desc = dma_map_single(dev, &edesc->desc.hdr1,
+ TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ if (!prev_edesc) {
+ request->dma_desc = dma_desc;
+ goto next;
+ }
+
+ /* Chain in any previous descriptors. */
+
+ prev_edesc->desc.next_desc = cpu_to_be32(dma_desc);
+
+ dma_sync_single_for_device(dev, prev_dma_desc,
+ TALITOS_DESC_SIZE,
+ DMA_TO_DEVICE);
+
+next:
+ prev_edesc = edesc;
+ prev_dma_desc = dma_desc;
+ edesc = edesc->next_desc;
+ }
+ } else {
+ request->dma_desc = dma_map_single(dev, desc, TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ }
+}
+
/**
* talitos_submit - submits a descriptor to the device for processing
* @dev: the SEC device to be used
@@ -291,16 +330,7 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
request = &priv->chan[ch].fifo[head];
/* map descriptor and save caller data */
- if (is_sec1) {
- desc->hdr1 = desc->hdr;
- request->dma_desc = dma_map_single(dev, &desc->hdr1,
- TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
- } else {
- request->dma_desc = dma_map_single(dev, desc,
- TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
- }
+ dma_map_request(dev, request, desc, is_sec1);
request->callback = callback;
request->context = context;
@@ -322,19 +352,51 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
return -EINPROGRESS;
}
-static __be32 get_request_hdr(struct talitos_request *request, bool is_sec1)
+static __be32 get_request_hdr(struct device *dev,
+ struct talitos_request *request, bool is_sec1)
{
struct talitos_edesc *edesc;
+ dma_addr_t dma_desc;
- if (!is_sec1)
- return request->desc->hdr;
+ if (!is_sec1) {
+ dma_sync_single_for_cpu(dev, request->dma_desc,
+ TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
- if (!request->desc->next_desc)
- return request->desc->hdr1;
+ return request->desc->hdr;
+ }
edesc = container_of(request->desc, struct talitos_edesc, desc);
+ dma_desc = request->dma_desc;
+ while (edesc->next_desc) {
+ dma_desc = be32_to_cpu(edesc->desc.next_desc);
+ edesc = edesc->next_desc;
+ }
+
+ dma_sync_single_for_cpu(dev, dma_desc, TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ return edesc->desc.hdr1;
+}
- return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1;
+static void dma_unmap_request(struct device *dev,
+ struct talitos_request *request, bool is_sec1)
+{
+ struct talitos_edesc *edesc;
+
+ if (is_sec1) {
+ dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ edesc = container_of(request->desc, struct talitos_edesc, desc);
+ while (edesc->next_desc) {
+ dma_unmap_single(dev,
+ be32_to_cpu(edesc->desc.next_desc),
+ TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
+ edesc = edesc->next_desc;
+ }
+ } else {
+ dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ }
}
/*
@@ -358,7 +420,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/* descriptors with their done bits set don't get the error */
rmb();
- hdr = get_request_hdr(request, is_sec1);
+ hdr = get_request_hdr(dev, request, is_sec1);
if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
status = 0;
@@ -368,9 +430,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
else
status = error;
- dma_unmap_single(dev, request->dma_desc,
- TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
+ dma_unmap_request(dev, request, is_sec1);
/* copy entries so we can call callback outside lock */
saved_req.desc = request->desc;
@@ -459,14 +519,35 @@ DEF_TALITOS2_DONE(ch0, TALITOS2_ISR_CH_0_DONE)
DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE)
DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE)
+static __be32 search_desc_hdr_in_request(struct talitos_request *request,
+ dma_addr_t cur_desc, bool is_sec1)
+{
+ struct talitos_edesc *edesc;
+
+ if (request->dma_desc == cur_desc) {
+ return request->desc->hdr;
+ } else if (is_sec1) {
+ edesc = container_of(request->desc, struct talitos_edesc, desc);
+ while (edesc->next_desc) {
+ if (edesc->desc.next_desc == cpu_to_be32(cur_desc))
+ return edesc->next_desc->desc.hdr1;
+ edesc = edesc->next_desc;
+ }
+ }
+ return 0;
+}
+
/*
* locate current (offending) descriptor
*/
static __be32 current_desc_hdr(struct device *dev, int ch)
{
struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+ struct talitos_request *request;
int tail, iter;
dma_addr_t cur_desc;
+ __be32 hdr = 0;
cur_desc = ((u64)in_be32(priv->chan[ch].reg + TALITOS_CDPR)) << 32;
cur_desc |= in_be32(priv->chan[ch].reg + TALITOS_CDPR_LO);
@@ -477,27 +558,21 @@ static __be32 current_desc_hdr(struct device *dev, int ch)
}
tail = priv->chan[ch].tail;
-
iter = tail;
- while (priv->chan[ch].fifo[iter].dma_desc != cur_desc &&
- priv->chan[ch].fifo[iter].desc->next_desc != cpu_to_be32(cur_desc)) {
- iter = (iter + 1) & (priv->fifo_len - 1);
- if (iter == tail) {
- dev_err(dev, "couldn't locate current descriptor\n");
- return 0;
- }
- }
+ do {
+ request = &priv->chan[ch].fifo[iter];
- if (priv->chan[ch].fifo[iter].desc->next_desc == cpu_to_be32(cur_desc)) {
- struct talitos_edesc *edesc;
+ hdr = search_desc_hdr_in_request(request, cur_desc, is_sec1);
+ if (hdr)
+ break;
- edesc = container_of(priv->chan[ch].fifo[iter].desc,
- struct talitos_edesc, desc);
- return ((struct talitos_desc *)
- (edesc->buf + edesc->dma_len))->hdr;
- }
+ iter = (iter + 1) & (priv->fifo_len - 1);
+ } while (iter != tail);
- return priv->chan[ch].fifo[iter].desc->hdr;
+ if (!hdr)
+ dev_err(dev, "couldn't locate current descriptor\n");
+
+ return hdr;
}
/*
@@ -869,28 +944,20 @@ struct talitos_ahash_req_ctx {
u8 buf[2][HASH_MAX_BLOCK_SIZE];
int buf_idx;
unsigned int swinit;
- unsigned int first_desc;
- unsigned int last_desc;
+ unsigned int first_request;
unsigned int last_request;
unsigned int to_hash_later;
unsigned int nbuf;
struct scatterlist bufsl[2];
struct scatterlist *psrc;
-
- struct scatterlist request_bufsl[2];
- struct ahash_request *areq;
- struct scatterlist *request_sl;
- unsigned int remaining_ahash_request_bytes;
- unsigned int current_ahash_request_bytes;
- struct work_struct sec1_ahash_process_remaining;
};
struct talitos_export_state {
u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
u8 buf[HASH_MAX_BLOCK_SIZE];
unsigned int swinit;
- unsigned int first_desc;
- unsigned int last_desc;
+ unsigned int first_request;
+ unsigned int last_request;
unsigned int to_hash_later;
unsigned int nbuf;
};
@@ -1396,10 +1463,6 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
dma_len = 0;
}
alloc_len += icv_stashing ? authsize : 0;
-
- /* if its a ahash, add space for a second desc next to the first one */
- if (is_sec1 && !dst)
- alloc_len += sizeof(struct talitos_desc);
alloc_len += ivsize;
edesc = kmalloc(ALIGN(alloc_len, dma_get_cache_alignment()), flags);
@@ -1415,6 +1478,7 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
edesc->dst_nents = dst_nents;
edesc->iv_dma = iv_dma;
edesc->dma_len = dma_len;
+ edesc->next_desc = NULL;
if (dma_len)
edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
edesc->dma_len,
@@ -1715,39 +1779,37 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
struct talitos_desc *desc = &edesc->desc;
- struct talitos_desc *desc2 = (struct talitos_desc *)
- (edesc->buf + edesc->dma_len);
unmap_single_talitos_ptr(dev, &desc->ptr[5], DMA_FROM_DEVICE);
- if (desc->next_desc &&
- desc->ptr[5].ptr != desc2->ptr[5].ptr)
- unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
- if (req_ctx->last_desc)
+
+ if (edesc->last && req_ctx->last_request)
memcpy(areq->result, req_ctx->hw_context,
crypto_ahash_digestsize(tfm));
- if (req_ctx->psrc)
- talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
+ if (edesc->src)
+ talitos_sg_unmap(dev, edesc, edesc->src, NULL, 0, 0);
/* When using hashctx-in, must unmap it. */
if (from_talitos_ptr_len(&desc->ptr[1], is_sec1))
unmap_single_talitos_ptr(dev, &desc->ptr[1],
DMA_TO_DEVICE);
- else if (desc->next_desc)
- unmap_single_talitos_ptr(dev, &desc2->ptr[1],
- DMA_TO_DEVICE);
-
- if (is_sec1 && req_ctx->nbuf)
- unmap_single_talitos_ptr(dev, &desc->ptr[3],
- DMA_TO_DEVICE);
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
DMA_BIDIRECTIONAL);
+}
+
+static void free_edesc_list_from(struct ahash_request *areq, struct talitos_edesc *edesc)
+{
+ struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
+ struct talitos_edesc *next;
- if (desc->next_desc)
- dma_unmap_single(dev, be32_to_cpu(desc->next_desc),
- TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
+ while (edesc) {
+ next = edesc->next_desc;
+ common_nonsnoop_hash_unmap(ctx->dev, edesc, areq);
+ kfree(edesc);
+ edesc = next;
+ }
}
static void ahash_done(struct device *dev,
@@ -1758,30 +1820,46 @@ static void ahash_done(struct device *dev,
struct talitos_edesc *edesc =
container_of(desc, struct talitos_edesc, desc);
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ bool is_sec1 = has_ftr_sec1(dev_get_drvdata(dev));
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct talitos_edesc *next;
- if (!req_ctx->last_desc && req_ctx->to_hash_later) {
- /* Position any partial block for next update/final/finup */
- req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
- req_ctx->nbuf = req_ctx->to_hash_later;
- }
- common_nonsnoop_hash_unmap(dev, edesc, areq);
-
- kfree(edesc);
+ if (is_sec1) {
+ if (!req_ctx->last_request && req_ctx->to_hash_later) {
+ /* Position any partial block for next update/final/finup */
+ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+ req_ctx->nbuf = req_ctx->to_hash_later;
+ }
- if (err) {
+ free_edesc_list_from(areq, edesc);
ahash_request_complete(areq, err);
- return;
- }
+ } else {
+ next = edesc->next_desc;
- req_ctx->remaining_ahash_request_bytes -=
- req_ctx->current_ahash_request_bytes;
+ common_nonsnoop_hash_unmap(dev, edesc, areq);
+ kfree(edesc);
- if (!req_ctx->remaining_ahash_request_bytes) {
- ahash_request_complete(areq, 0);
- return;
- }
+ if (err)
+ goto out;
- schedule_work(&req_ctx->sec1_ahash_process_remaining);
+ if (next) {
+ err = talitos_submit(dev, ctx->ch, &next->desc,
+ ahash_done, areq);
+ if (err != -EINPROGRESS)
+ goto out;
+ return;
+ }
+out:
+ if (!req_ctx->last_request && req_ctx->to_hash_later) {
+ /* Position any partial block for next update/final/finup */
+ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+ req_ctx->nbuf = req_ctx->to_hash_later;
+ }
+ if (err && next)
+ free_edesc_list_from(areq, next);
+ ahash_request_complete(areq, err);
+ }
}
/*
@@ -1805,18 +1883,15 @@ static void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
(char *)padded_hash, DMA_TO_DEVICE);
}
-static int common_nonsnoop_hash(struct talitos_edesc *edesc,
- struct ahash_request *areq, unsigned int length,
- void (*callback) (struct device *dev,
- struct talitos_desc *desc,
- void *context, int error))
+static void common_nonsnoop_hash(struct talitos_edesc *edesc,
+ struct ahash_request *areq,
+ unsigned int length)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct device *dev = ctx->dev;
struct talitos_desc *desc = &edesc->desc;
- int ret;
bool sync_needed = false;
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
@@ -1825,7 +1900,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* first DWORD empty */
/* hash context in */
- if (!req_ctx->first_desc || req_ctx->swinit) {
+ if (!edesc->first || !req_ctx->first_request || req_ctx->swinit) {
map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
req_ctx->hw_context_size,
req_ctx->hw_context,
@@ -1833,40 +1908,31 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
req_ctx->swinit = 0;
}
/* Indicate next op is not the first. */
- req_ctx->first_desc = 0;
+ req_ctx->first_request = 0;
/* HMAC key */
if (ctx->keylen)
to_talitos_ptr(&desc->ptr[2], ctx->dma_key, ctx->keylen,
is_sec1);
- if (is_sec1 && req_ctx->nbuf)
- length -= req_ctx->nbuf;
-
sg_count = edesc->src_nents ?: 1;
if (is_sec1 && sg_count > 1)
- sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length);
+ sg_copy_to_buffer(edesc->src, sg_count, edesc->buf, length);
else if (length)
- sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count,
- DMA_TO_DEVICE);
+ sg_count = dma_map_sg(dev, edesc->src, sg_count, DMA_TO_DEVICE);
+
/*
* data in
*/
- if (is_sec1 && req_ctx->nbuf) {
- map_single_talitos_ptr(dev, &desc->ptr[3], req_ctx->nbuf,
- req_ctx->buf[req_ctx->buf_idx],
- DMA_TO_DEVICE);
- } else {
- sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc->ptr[3], sg_count, 0, 0);
- if (sg_count > 1)
- sync_needed = true;
- }
+ sg_count = talitos_sg_map(dev, edesc->src, length, edesc, &desc->ptr[3],
+ sg_count, 0, 0);
+ if (sg_count > 1)
+ sync_needed = true;
/* fifth DWORD empty */
/* hash/HMAC out -or- hash context out */
- if (req_ctx->last_desc)
+ if (edesc->last && req_ctx->last_request)
map_single_talitos_ptr(dev, &desc->ptr[5],
crypto_ahash_digestsize(tfm),
req_ctx->hw_context, DMA_FROM_DEVICE);
@@ -1881,73 +1947,94 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
if (is_sec1 && from_talitos_ptr_len(&desc->ptr[3], true) == 0)
talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
- if (is_sec1 && req_ctx->nbuf && length) {
- struct talitos_desc *desc2 = (struct talitos_desc *)
- (edesc->buf + edesc->dma_len);
- dma_addr_t next_desc;
-
- memset(desc2, 0, sizeof(*desc2));
- desc2->hdr = desc->hdr;
- desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT;
- desc2->hdr1 = desc2->hdr;
- desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD;
- desc->hdr |= DESC_HDR_MODE0_MDEU_CONT;
- desc->hdr &= ~DESC_HDR_DONE_NOTIFY;
-
- if (desc->ptr[1].ptr)
- copy_talitos_ptr(&desc2->ptr[1], &desc->ptr[1],
- is_sec1);
- else
- map_single_talitos_ptr_nosync(dev, &desc2->ptr[1],
- req_ctx->hw_context_size,
- req_ctx->hw_context,
- DMA_TO_DEVICE);
- copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1);
- sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc2->ptr[3], sg_count, 0, 0);
- if (sg_count > 1)
- sync_needed = true;
- copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
- if (req_ctx->last_desc)
- map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
- req_ctx->hw_context_size,
- req_ctx->hw_context,
- DMA_FROM_DEVICE);
-
- next_desc = dma_map_single(dev, &desc2->hdr1, TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
- desc->next_desc = cpu_to_be32(next_desc);
- }
-
if (sync_needed)
dma_sync_single_for_device(dev, edesc->dma_link_tbl,
edesc->dma_len, DMA_BIDIRECTIONAL);
-
- ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
- if (ret != -EINPROGRESS) {
- common_nonsnoop_hash_unmap(dev, edesc, areq);
- kfree(edesc);
- }
- return ret;
}
static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+ struct scatterlist *src,
unsigned int nbytes)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ return talitos_edesc_alloc(ctx->dev, src, NULL, NULL, 0,
+ nbytes, 0, 0, 0, areq->base.flags, false);
+}
+
+static struct talitos_edesc *
+ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
+ unsigned int blocksize, bool is_sec1)
+{
+ struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- struct talitos_private *priv = dev_get_drvdata(ctx->dev);
- bool is_sec1 = has_ftr_sec1(priv);
+ struct talitos_edesc *first = NULL, *prev_edesc = NULL, *edesc;
+ size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN :
+ TALITOS2_MAX_DATA_LEN;
+ struct scatterlist tmp[2];
+ size_t to_hash_this_desc;
+ struct scatterlist *src;
+ size_t offset = 0;
+
+ do {
+ src = scatterwalk_ffwd(tmp, req_ctx->psrc, offset);
+
+ to_hash_this_desc =
+ min(nbytes, ALIGN_DOWN(desc_max, blocksize));
+
+ /* Allocate extended descriptor */
+ edesc = ahash_edesc_alloc(areq, src, to_hash_this_desc);
+ if (IS_ERR(edesc)) {
+ if (first)
+ free_edesc_list_from(areq, first);
+ return edesc;
+ }
- if (is_sec1)
- nbytes -= req_ctx->nbuf;
+ edesc->src =
+ scatterwalk_ffwd(edesc->bufsl, req_ctx->psrc, offset);
+ edesc->desc.hdr = ctx->desc_hdr_template;
+ edesc->first = offset == 0;
+ edesc->last = nbytes - to_hash_this_desc == 0;
- return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, NULL, 0,
- nbytes, 0, 0, 0, areq->base.flags, false);
+ /* On last one, request SEC to pad; otherwise continue */
+ if (req_ctx->last_request && edesc->last)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+ else
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+
+ /* request SEC to INIT hash. */
+ if (req_ctx->first_request && edesc->first && !req_ctx->swinit)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+
+ /*
+ * When the tfm context has a keylen, it's an HMAC.
+ * A first or last (ie. not middle) descriptor must request HMAC.
+ */
+ if (ctx->keylen && ((req_ctx->first_request && edesc->first) ||
+ (req_ctx->last_request && edesc->last)))
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+ /* clear the DN bit */
+ if (is_sec1 && !edesc->last)
+ edesc->desc.hdr &= ~DESC_HDR_DONE_NOTIFY;
+
+ common_nonsnoop_hash(edesc, areq, to_hash_this_desc);
+
+ offset += to_hash_this_desc;
+ nbytes -= to_hash_this_desc;
+
+ if (!prev_edesc)
+ first = edesc;
+ else
+ prev_edesc->next_desc = edesc;
+ prev_edesc = edesc;
+ } while (nbytes);
+
+ return first;
}
-static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
+static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
@@ -1955,23 +2042,23 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
struct talitos_edesc *edesc;
unsigned int blocksize =
crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+ bool is_sec1 = has_ftr_sec1(dev_get_drvdata(ctx->dev));
unsigned int nbytes_to_hash;
unsigned int to_hash_later;
unsigned int nsg;
int nents;
struct device *dev = ctx->dev;
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
+ int ret;
- if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
+ if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) {
/* Buffer up to one whole block */
- nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ nents = sg_nents_for_len(areq->src, nbytes);
if (nents < 0) {
dev_err(dev, "Invalid number of src SG.\n");
return nents;
}
- sg_copy_to_buffer(req_ctx->request_sl, nents,
+ sg_copy_to_buffer(areq->src, nents,
ctx_buf + req_ctx->nbuf, nbytes);
req_ctx->nbuf += nbytes;
return 0;
@@ -1981,7 +2068,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
nbytes_to_hash = nbytes + req_ctx->nbuf;
to_hash_later = nbytes_to_hash & (blocksize - 1);
- if (req_ctx->last_desc)
+ if (req_ctx->last_request)
to_hash_later = 0;
else if (to_hash_later)
/* There is a partial block. Hash the full block(s) now */
@@ -1993,123 +2080,39 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
}
/* Chain in any previously buffered data */
- if (!is_sec1 && req_ctx->nbuf) {
+ if (req_ctx->nbuf) {
nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
sg_init_table(req_ctx->bufsl, nsg);
sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
if (nsg > 1)
- sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
+ sg_chain(req_ctx->bufsl, 2, areq->src);
req_ctx->psrc = req_ctx->bufsl;
- } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
- int offset;
-
- if (nbytes_to_hash > blocksize)
- offset = blocksize - req_ctx->nbuf;
- else
- offset = nbytes_to_hash - req_ctx->nbuf;
- nents = sg_nents_for_len(req_ctx->request_sl, offset);
- if (nents < 0) {
- dev_err(dev, "Invalid number of src SG.\n");
- return nents;
- }
- sg_copy_to_buffer(req_ctx->request_sl, nents,
- ctx_buf + req_ctx->nbuf, offset);
- req_ctx->nbuf += offset;
- req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
- offset);
} else
- req_ctx->psrc = req_ctx->request_sl;
+ req_ctx->psrc = areq->src;
if (to_hash_later) {
- nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ nents = sg_nents_for_len(areq->src, nbytes);
if (nents < 0) {
dev_err(dev, "Invalid number of src SG.\n");
return nents;
}
- sg_pcopy_to_buffer(req_ctx->request_sl, nents,
+ sg_pcopy_to_buffer(areq->src, nents,
req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
to_hash_later,
nbytes - to_hash_later);
}
req_ctx->to_hash_later = to_hash_later;
- /* Allocate extended descriptor */
- edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
+ edesc = ahash_process_req_prepare(areq, nbytes_to_hash, blocksize,
+ is_sec1);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
- edesc->desc.hdr = ctx->desc_hdr_template;
-
- /* On last one, request SEC to pad; otherwise continue */
- if (req_ctx->last_desc)
- edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
- else
- edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
-
- /* request SEC to INIT hash. */
- if (req_ctx->first_desc && !req_ctx->swinit)
- edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
-
- /* When the tfm context has a keylen, it's an HMAC.
- * A first or last (ie. not middle) descriptor must request HMAC.
- */
- if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
- edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
-
- return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
-}
-
-static void sec1_ahash_process_remaining(struct work_struct *work)
-{
- struct talitos_ahash_req_ctx *req_ctx =
- container_of(work, struct talitos_ahash_req_ctx,
- sec1_ahash_process_remaining);
- int err = 0;
-
- req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
- req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
+ ret = talitos_submit(dev, ctx->ch, &edesc->desc, ahash_done, areq);
+ if (ret != -EINPROGRESS)
+ free_edesc_list_from(areq, edesc);
- if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
- req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
- else {
- req_ctx->current_ahash_request_bytes =
- req_ctx->remaining_ahash_request_bytes;
-
- if (req_ctx->last_request)
- req_ctx->last_desc = 1;
- }
-
- err = ahash_process_req_one(req_ctx->areq,
- req_ctx->current_ahash_request_bytes);
-
- if (err != -EINPROGRESS)
- ahash_request_complete(req_ctx->areq, err);
-}
-
-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
- struct device *dev = ctx->dev;
- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
-
- req_ctx->areq = areq;
- req_ctx->request_sl = areq->src;
- req_ctx->remaining_ahash_request_bytes = nbytes;
-
- if (is_sec1) {
- if (nbytes > TALITOS1_MAX_DATA_LEN)
- nbytes = TALITOS1_MAX_DATA_LEN;
- else if (req_ctx->last_request)
- req_ctx->last_desc = 1;
- }
-
- req_ctx->current_ahash_request_bytes = nbytes;
-
- return ahash_process_req_one(req_ctx->areq,
- req_ctx->current_ahash_request_bytes);
+ return ret;
}
static int ahash_init(struct ahash_request *areq)
@@ -2124,15 +2127,13 @@ static int ahash_init(struct ahash_request *areq)
/* Initialize the context */
req_ctx->buf_idx = 0;
req_ctx->nbuf = 0;
- req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
+ req_ctx->first_request = 1;
req_ctx->swinit = 0; /* assume h/w init of context */
size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
req_ctx->hw_context_size = size;
req_ctx->last_request = 0;
- req_ctx->last_desc = 0;
- INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
DMA_TO_DEVICE);
@@ -2224,8 +2225,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
req_ctx->hw_context_size);
memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
export->swinit = req_ctx->swinit;
- export->first_desc = req_ctx->first_desc;
- export->last_desc = req_ctx->last_desc;
+ export->first_request = req_ctx->first_request;
+ export->last_request = req_ctx->last_request;
export->to_hash_later = req_ctx->to_hash_later;
export->nbuf = req_ctx->nbuf;
@@ -2250,8 +2251,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
memcpy(req_ctx->hw_context, export->hw_context, size);
memcpy(req_ctx->buf[0], export->buf, export->nbuf);
req_ctx->swinit = export->swinit;
- req_ctx->first_desc = export->first_desc;
- req_ctx->last_desc = export->last_desc;
+ req_ctx->first_request = export->first_request;
+ req_ctx->last_request = export->last_request;
req_ctx->to_hash_later = export->to_hash_later;
req_ctx->nbuf = export->nbuf;
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index 1a93ee355929..11f0eb6a41db 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -44,11 +44,17 @@ struct talitos_desc {
/*
* talitos_edesc - s/w-extended descriptor
+ * @bufsl: scatterlist buffer
+ * @src: pointer to input scatterlist
+ * @first: first descriptor of a chain
+ * @last: last descriptor of a chain
+ *
* @src_nents: number of segments in input scatterlist
* @dst_nents: number of segments in output scatterlist
* @iv_dma: dma address of iv for checking continuity and link table
* @dma_len: length of dma mapped link_tbl space
* @dma_link_tbl: bus physical address of link_tbl/buf
+ * @next_desc: next descriptor
* @desc: h/w descriptor
* @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
* @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
@@ -58,11 +64,17 @@ struct talitos_desc {
* of link_tbl data
*/
struct talitos_edesc {
+ struct scatterlist bufsl[2];
+ struct scatterlist *src;
+ int first;
+ int last;
+
int src_nents;
int dst_nents;
dma_addr_t iv_dma;
int dma_len;
dma_addr_t dma_link_tbl;
+ struct talitos_edesc *next_desc;
struct talitos_desc desc;
union {
DECLARE_FLEX_ARRAY(struct talitos_ptr, link_tbl);
diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c
index eb71113ed146..e8d8c3a23d7a 100644
--- a/drivers/crypto/tegra/tegra-se-main.c
+++ b/drivers/crypto/tegra/tegra-se-main.c
@@ -180,7 +180,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
MAX_SCHEDULE_TIMEOUT, NULL);
if (ret) {
dev_err(se->dev, "host1x job timed out\n");
- return ret;
+ goto job_put;
}
host1x_job_put(job);
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 94b8ecb892bb..2f94be1df525 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -40,6 +40,7 @@ struct udmabuf {
struct folio **pinned_folios;
struct sg_table *sg;
+ enum dma_data_direction sg_dir;
struct miscdevice *device;
pgoff_t *offsets;
};
@@ -162,7 +163,7 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf,
sg_set_folio(sgl, ubuf->folios[i], PAGE_SIZE,
ubuf->offsets[i]);
- ret = dma_map_sgtable(dev, sg, direction, 0);
+ ret = dma_map_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
if (ret < 0)
goto err_map;
return sg;
@@ -177,7 +178,7 @@ err_alloc:
static void put_sg_table(struct device *dev, struct sg_table *sg,
enum dma_data_direction direction)
{
- dma_unmap_sgtable(dev, sg, direction, 0);
+ dma_unmap_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sg);
kfree(sg);
}
@@ -235,7 +236,7 @@ static void release_udmabuf(struct dma_buf *buf)
struct device *dev = ubuf->device->this_device;
if (ubuf->sg)
- put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
+ put_sg_table(dev, ubuf->sg, ubuf->sg_dir);
deinit_udmabuf(ubuf);
kfree(ubuf);
@@ -253,6 +254,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
if (IS_ERR(ubuf->sg)) {
ret = PTR_ERR(ubuf->sg);
ubuf->sg = NULL;
+ } else {
+ ubuf->sg_dir = direction;
}
} else {
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 63df35444214..de6c52dbd9d2 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -79,6 +79,7 @@ static struct res_config *res_cfg;
static int retry_rd_err_log;
static int decoding_via_mca;
static bool mem_cfg_2lm;
+static bool no_adxl;
static struct reg_rrl icx_reg_rrl_ddr = {
.set_num = 2,
@@ -1222,8 +1223,14 @@ static int __init i10nm_init(void)
}
rc = skx_adxl_get();
- if (rc)
- goto fail;
+ if (rc) {
+ /* Decoding errors via MCA banks for 2LM isn't supported yet */
+ if (rc != -ENODEV || mem_cfg_2lm)
+ goto fail;
+ i10nm_printk(KERN_INFO, "ADXL not found, falling back to MCA-based decoding.\n");
+ no_adxl = true;
+ decoding_via_mca = true;
+ }
opstate_init();
mce_register_decode_chain(&i10nm_mce_dec);
@@ -1257,7 +1264,8 @@ static void __exit i10nm_exit(void)
skx_teardown_debug();
mce_unregister_decode_chain(&i10nm_mce_dec);
- skx_adxl_put();
+ if (!no_adxl)
+ skx_adxl_put();
skx_remove();
}
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
index 3bf8e7338dbe..097a97eeea66 100644
--- a/drivers/fpga/dfl-afu-main.c
+++ b/drivers/fpga/dfl-afu-main.c
@@ -723,6 +723,9 @@ afu_ioctl_dma_map(struct dfl_feature_dev_data *fdata, void __user *arg)
if (map.argsz < minsz || map.flags)
return -EINVAL;
+ if (map.length >> PAGE_SHIFT > (u64)INT_MAX)
+ return -EINVAL;
+
ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index 50fafeda8d7e..3b7ebcf12fe7 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -95,7 +95,7 @@ struct sprd_eic {
struct notifier_block irq_nb;
void __iomem *base[SPRD_EIC_MAX_BANK];
enum sprd_eic_type type;
- spinlock_t lock;
+ raw_spinlock_t lock;
int irq;
};
@@ -149,7 +149,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
unsigned long flags;
u32 tmp;
- spin_lock_irqsave(&sprd_eic->lock, flags);
+ raw_spin_lock_irqsave(&sprd_eic->lock, flags);
tmp = readl_relaxed(base + reg);
if (val)
@@ -158,7 +158,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
tmp &= ~BIT(SPRD_EIC_BIT(offset));
writel_relaxed(tmp, base + reg);
- spin_unlock_irqrestore(&sprd_eic->lock, flags);
+ raw_spin_unlock_irqrestore(&sprd_eic->lock, flags);
}
static int sprd_eic_read(struct gpio_chip *chip, unsigned int offset, u16 reg)
@@ -628,7 +628,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
if (!sprd_eic)
return -ENOMEM;
- spin_lock_init(&sprd_eic->lock);
+ raw_spin_lock_init(&sprd_eic->lock);
sprd_eic->type = pdata->type;
sprd_eic->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 966d16a6d515..5e361742a11a 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -39,7 +39,7 @@
struct sch_gpio {
struct gpio_chip chip;
void __iomem *regs;
- spinlock_t lock;
+ raw_spinlock_t lock;
unsigned short resume_base;
/* GPE handling */
@@ -104,9 +104,9 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GIO, 1);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -122,9 +122,9 @@ static int sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val)
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GLV, val);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -135,9 +135,9 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num,
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GIO, 0);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
/*
* according to the datasheet, writing to the level register has no
@@ -196,14 +196,14 @@ static int sch_irq_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GTPE, rising);
sch_gpio_reg_set(sch, gpio_num, GTNE, falling);
irq_set_handler_locked(d, handle_edge_irq);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -215,9 +215,9 @@ static void sch_irq_ack(struct irq_data *d)
irq_hw_number_t gpio_num = irqd_to_hwirq(d);
unsigned long flags;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GTS, 1);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
}
static void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num, int val)
@@ -225,9 +225,9 @@ static void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num,
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GGPE, val);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
}
static void sch_irq_mask(struct irq_data *d)
@@ -268,12 +268,12 @@ static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
int offset;
u32 ret;
- spin_lock_irqsave(&sch->lock, flags);
+ raw_spin_lock_irqsave(&sch->lock, flags);
core_status = ioread32(sch->regs + CORE_BANK_OFFSET + GTS);
resume_status = ioread32(sch->regs + RESUME_BANK_OFFSET + GTS);
- spin_unlock_irqrestore(&sch->lock, flags);
+ raw_spin_unlock_irqrestore(&sch->lock, flags);
pending = (resume_status << sch->resume_base) | core_status;
for_each_set_bit(offset, &pending, sch->chip.ngpio)
@@ -343,7 +343,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
sch->regs = regs;
- spin_lock_init(&sch->lock);
+ raw_spin_lock_init(&sch->lock);
sch->chip = sch_gpio_chip;
sch->chip.label = dev_name(dev);
sch->chip.parent = dev;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
index 958fd78080bd..c2d854c7af99 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
@@ -230,29 +230,26 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
* covered by a number of LPTEs, the LPTEs once again take
* control over their address range.
*
- * Determine how many LPTEs need to transition state.
+ * Transition each LPTE individually as each may have a
+ * different target state (sparse, invalid, or valid).
*/
- pgt->pte[ptei].s.spte_valid = false;
- for (ptes = 1, ptei++; ptei < lpti; ptes++, ptei++) {
+ for (ptei++; ptei < lpti; ptei++) {
if (pgt->pte[ptei].s.sptes)
break;
- pgt->pte[ptei].s.spte_valid = false;
}
- if (pgt->pte[pteb].s.sparse) {
- TRA(it, "LPTE %05x: U -> S %d PTEs", pteb, ptes);
- pair->func->sparse(vmm, pgt->pt[0], pteb, ptes);
- } else if (!pgt->pte[pteb].s.lpte_valid) {
- if (pair->func->invalid) {
- /* If the MMU supports it, restore the LPTE to the
- * INVALID state to tell the MMU there is no point
- * trying to fetch the corresponding SPTEs.
- */
- TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes);
- pair->func->invalid(vmm, pgt->pt[0], pteb, ptes);
+ while (pteb < ptei) {
+ pgt->pte[pteb].s.spte_valid = false;
+ if (pgt->pte[pteb].s.sparse) {
+ TRA(it, "LPTE %05x: U -> S", pteb);
+ pair->func->sparse(vmm, pgt->pt[0], pteb, 1);
+ } else if (!pgt->pte[pteb].s.lpte_valid) {
+ if (pair->func->invalid) {
+ TRA(it, "LPTE %05x: U -> I", pteb);
+ pair->func->invalid(vmm, pgt->pt[0], pteb, 1);
+ }
}
- } else {
- TRA(it, "LPTE %05x: V %d PTEs", pteb, ptes);
+ pteb++;
}
}
}
diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c
index 5e8ced7bc05a..adaa44a858ed 100644
--- a/drivers/hid/hid-appleir.c
+++ b/drivers/hid/hid-appleir.c
@@ -109,9 +109,10 @@ struct appleir {
struct hid_device *hid;
unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
struct timer_list key_up_timer; /* timer for key up */
- spinlock_t lock; /* protects .current_key */
+ spinlock_t lock; /* protects .current_key, .removing */
int current_key; /* the currently pressed key */
int prev_key_idx; /* key index in a 2 packets message */
+ bool removing; /* set during teardown; gates input_dev access */
};
static int get_key(int data)
@@ -172,7 +173,7 @@ static void key_up_tick(struct timer_list *t)
unsigned long flags;
spin_lock_irqsave(&appleir->lock, flags);
- if (appleir->current_key) {
+ if (!appleir->removing && appleir->current_key) {
key_up(hid, appleir, appleir->current_key);
appleir->current_key = 0;
}
@@ -195,6 +196,10 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
int index;
spin_lock_irqsave(&appleir->lock, flags);
+ if (appleir->removing) {
+ spin_unlock_irqrestore(&appleir->lock, flags);
+ goto out;
+ }
/*
* If we already have a key down, take it up before marking
* this one down
@@ -229,17 +234,25 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
appleir->prev_key_idx = 0;
if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
- key_down(hid, appleir, appleir->current_key);
- /*
- * Remote doesn't do key up, either pull them up, in the test
- * above, or here set a timer which pulls them up after 1/8 s
- */
- mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+ spin_lock_irqsave(&appleir->lock, flags);
+ if (!appleir->removing) {
+ key_down(hid, appleir, appleir->current_key);
+ /*
+ * Remote doesn't do key up, either pull them up, in
+ * the test above, or here set a timer which pulls them
+ * up after 1/8 s
+ */
+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+ }
+ spin_unlock_irqrestore(&appleir->lock, flags);
goto out;
}
if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
- battery_flat(appleir);
+ spin_lock_irqsave(&appleir->lock, flags);
+ if (!appleir->removing)
+ battery_flat(appleir);
+ spin_unlock_irqrestore(&appleir->lock, flags);
/* Fall through */
}
@@ -318,8 +331,20 @@ fail:
static void appleir_remove(struct hid_device *hid)
{
struct appleir *appleir = hid_get_drvdata(hid);
+ unsigned long flags;
+
+ /*
+ * Mark the driver as tearing down so that any concurrent raw_event
+ * (e.g. from a USB URB completion that hid_hw_stop() has not yet
+ * killed) and the key_up_timer softirq stop touching input_dev
+ * before hid_hw_stop() frees it via hidinput_disconnect().
+ */
+ spin_lock_irqsave(&appleir->lock, flags);
+ appleir->removing = true;
+ spin_unlock_irqrestore(&appleir->lock, flags);
+
+ timer_shutdown_sync(&appleir->key_up_timer);
hid_hw_stop(hid);
- timer_delete_sync(&appleir->key_up_timer);
}
static const struct hid_device_id appleir_devices[] = {
diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c
index 80c0288a3a38..288cb827e9d6 100644
--- a/drivers/hid/hid-goodix-spi.c
+++ b/drivers/hid/hid-goodix-spi.c
@@ -520,6 +520,9 @@ static int goodix_hid_set_raw_report(struct hid_device *hid,
memcpy(tmp_buf + tx_len, args, args_len);
tx_len += args_len;
+ if (tx_len + len > sizeof(tmp_buf))
+ return -EINVAL;
+
memcpy(tmp_buf + tx_len, buf, len);
tx_len += len;
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index e0c9d5ec9451..318b1152ff8b 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -2405,6 +2405,15 @@ static int hid_go_cfg_probe(struct hid_device *hdev,
static void hid_go_cfg_remove(struct hid_device *hdev)
{
+ /*
+ * cfg_setup is scheduled from hid_go_cfg_probe() with a 2 ms delay
+ * and dereferences drvdata.hdev. Drain it here before tearing
+ * down so the workqueue cannot run after hid_destroy_device()'s
+ * put_device() has released the underlying hdev and dereference
+ * a stale drvdata.hdev pointer.
+ */
+ cancel_delayed_work_sync(&drvdata.go_cfg_setup);
+
guard(mutex)(&drvdata.cfg_mutex);
sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups);
hid_hw_close(hdev);
diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c
index 11e21f988723..b52e93a91ae5 100644
--- a/drivers/hid/hid-letsketch.c
+++ b/drivers/hid/hid-letsketch.c
@@ -296,13 +296,42 @@ static int letsketch_probe(struct hid_device *hdev, const struct hid_device_id *
ret = letsketch_setup_input_tablet(data);
if (ret)
- return ret;
+ goto err_shutdown_timer;
ret = letsketch_setup_input_tablet_pad(data);
if (ret)
- return ret;
+ goto err_shutdown_timer;
+
+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (ret)
+ goto err_shutdown_timer;
- return hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ return 0;
+
+err_shutdown_timer:
+ /*
+ * Drain any pending callback and permanently disable the timer
+ * before devm releases data: if hid_hw_start() enabled I/O on an
+ * always-poll-quirk device and then failed, raw_event may have
+ * armed the timer already.
+ */
+ timer_shutdown_sync(&data->inrange_timer);
+ return ret;
+}
+
+static void letsketch_remove(struct hid_device *hdev)
+{
+ struct letsketch_data *data = hid_get_drvdata(hdev);
+
+ /*
+ * hid_hw_stop() synchronously kills the URBs that deliver
+ * raw_event(), so once it returns no path can re-arm
+ * inrange_timer. timer_shutdown_sync() then drains any
+ * in-flight callback and permanently disables further
+ * mod_timer() calls before devm releases data.
+ */
+ hid_hw_stop(hdev);
+ timer_shutdown_sync(&data->inrange_timer);
}
static const struct hid_device_id letsketch_devices[] = {
@@ -315,6 +344,7 @@ static struct hid_driver letsketch_driver = {
.name = "letsketch",
.id_table = letsketch_devices,
.probe = letsketch_probe,
+ .remove = letsketch_remove,
.raw_event = letsketch_raw_event,
};
module_hid_driver(letsketch_driver);
diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c
index 1a88bc44ada4..02ef3e2094b4 100644
--- a/drivers/hid/hid-lg-g15.c
+++ b/drivers/hid/hid-lg-g15.c
@@ -1374,11 +1374,27 @@ static const struct hid_device_id lg_g15_devices[] = {
};
MODULE_DEVICE_TABLE(hid, lg_g15_devices);
+static void lg_g15_remove(struct hid_device *hdev)
+{
+ struct lg_g15_data *g15 = hid_get_drvdata(hdev);
+
+ /*
+ * g15->work is only initialized for the models that schedule it
+ * (G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so only
+ * cancel it when it was set up.
+ */
+ if (g15 && g15->work.func)
+ cancel_work_sync(&g15->work);
+
+ hid_hw_stop(hdev);
+}
+
static struct hid_driver lg_g15_driver = {
.name = "lg-g15",
.id_table = lg_g15_devices,
.raw_event = lg_g15_raw_event,
.probe = lg_g15_probe,
+ .remove = lg_g15_remove,
};
module_hid_driver(lg_g15_driver);
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 381e4dc5aba7..9c574ab8b60b 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1907,8 +1907,13 @@ static int logi_dj_probe(struct hid_device *hdev,
output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
- if (rep && (rep->maxfield < 1 ||
- rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1)) {
+ if (rep && rep->maxfield < 1) {
+ hid_err(hdev, "Expected size of DJ short report is %d, but got 0",
+ DJREPORT_SHORT_LENGTH - 1);
+ return -EINVAL;
+ }
+
+ if (rep && rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1) {
hid_err(hdev, "Expected size of DJ short report is %d, but got %d",
DJREPORT_SHORT_LENGTH - 1, rep->field[0]->report_count);
return -EINVAL;
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index eeab0b6e32cc..b085bed874bf 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -31,6 +31,7 @@
* [1] https://gitlab.freedesktop.org/libevdev/hid-tools
*/
+#include <linux/bitmap.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/hid.h>
@@ -97,8 +98,7 @@ enum report_mode {
TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS,
};
-#define MT_IO_SLOTS_MASK GENMASK(7, 0) /* reserve first 8 bits for slot tracking */
-#define MT_IO_FLAGS_RUNNING 32
+#define MT_IO_FLAGS_RUNNING 0
static const bool mtrue = true; /* default for true */
static const bool mfalse; /* default for false */
@@ -174,10 +174,9 @@ struct mt_device {
struct timer_list release_timer; /* to release sticky fingers */
struct hid_haptic_device *haptic; /* haptic related configuration */
struct hid_device *hdev; /* hid_device we're attached to */
- unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_RUNNING)
- * first 8 bits are reserved for keeping the slot
- * states, this is fine because we only support up
- * to 250 slots (MT_MAX_MAXCONTACT)
+ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_RUNNING) */
+ unsigned long *active_slots; /* bitmap of slots with an active
+ * contact, sized for maxcontacts
*/
__u8 inputmode_value; /* InputMode HID feature value */
__u8 maxcontacts;
@@ -1033,7 +1032,7 @@ static void mt_release_pending_palms(struct mt_device *td,
for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) {
clear_bit(slotnum, app->pending_palm_slots);
- clear_bit(slotnum, &td->mt_io_flags);
+ clear_bit(slotnum, td->active_slots);
input_mt_slot(input, slotnum);
input_mt_report_slot_inactive(input);
@@ -1244,9 +1243,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
- set_bit(slotnum, &td->mt_io_flags);
+ set_bit(slotnum, td->active_slots);
} else {
- clear_bit(slotnum, &td->mt_io_flags);
+ clear_bit(slotnum, td->active_slots);
}
return 0;
@@ -1381,7 +1380,7 @@ static void mt_touch_report(struct hid_device *hid,
* defect.
*/
if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
- if (td->mt_io_flags & MT_IO_SLOTS_MASK)
+ if (!bitmap_empty(td->active_slots, td->maxcontacts))
mod_timer(&td->release_timer,
jiffies + msecs_to_jiffies(100));
else
@@ -1440,6 +1439,15 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (td->is_pressurepad)
__set_bit(INPUT_PROP_PRESSUREPAD, input->propbit);
+ if (!td->active_slots) {
+ td->active_slots = devm_kcalloc(&td->hdev->dev,
+ BITS_TO_LONGS(td->maxcontacts),
+ sizeof(long),
+ GFP_KERNEL);
+ if (!td->active_slots)
+ return -ENOMEM;
+ }
+
app->pending_palm_slots = devm_kcalloc(&hi->input->dev,
BITS_TO_LONGS(td->maxcontacts),
sizeof(long),
@@ -1917,7 +1925,7 @@ static void mt_release_contacts(struct hid_device *hid)
for (i = 0; i < mt->num_slots; i++) {
input_mt_slot(input_dev, i);
input_mt_report_slot_inactive(input_dev);
- clear_bit(i, &td->mt_io_flags);
+ clear_bit(i, td->active_slots);
}
input_mt_sync_frame(input_dev);
input_sync(input_dev);
@@ -1940,7 +1948,7 @@ static void mt_expired_timeout(struct timer_list *t)
*/
if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
return;
- if (td->mt_io_flags & MT_IO_SLOTS_MASK)
+ if (!bitmap_empty(td->active_slots, td->maxcontacts))
mt_release_contacts(hdev);
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 90666ff629de..34f710c465b8 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -286,6 +286,54 @@ done_proc:
}
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
+int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
+ u32 usage_id, u32 attr_usage_id,
+ u32 report_id,
+ enum sensor_hub_read_flags flag,
+ u32 buffer_size, u8 *buffer)
+{
+ struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
+ struct hid_report *report;
+ unsigned long flags;
+ long cycles;
+ int ret;
+
+ report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
+ if (!report)
+ return -EINVAL;
+
+ mutex_lock(hsdev->mutex_ptr);
+ if (flag == SENSOR_HUB_SYNC) {
+ memset(&hsdev->pending, 0, sizeof(hsdev->pending));
+ init_completion(&hsdev->pending.ready);
+ hsdev->pending.usage_id = usage_id;
+ hsdev->pending.attr_usage_id = attr_usage_id;
+ hsdev->pending.max_raw_size = buffer_size;
+ hsdev->pending.raw_data = buffer;
+
+ spin_lock_irqsave(&data->lock, flags);
+ hsdev->pending.status = true;
+ spin_unlock_irqrestore(&data->lock, flags);
+ }
+ mutex_lock(&data->mutex);
+ hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
+ mutex_unlock(&data->mutex);
+ ret = 0;
+ if (flag == SENSOR_HUB_SYNC) {
+ cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
+ HZ * 5);
+ if (cycles == 0)
+ ret = -ETIMEDOUT;
+ else if (cycles < 0)
+ ret = cycles;
+
+ hsdev->pending.status = false;
+ }
+ mutex_unlock(hsdev->mutex_ptr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values);
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
@@ -478,6 +526,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
struct hid_collection *collection = NULL;
void *priv = NULL;
struct hid_sensor_hub_device *hsdev = NULL;
+ u32 copy_size;
+ u32 avail;
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
report->id, size, report->type);
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
hsdev->pending.attr_usage_id ==
report->field[i]->logical)) {
hid_dbg(hdev, "data was pending ...\n");
- hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
- if (hsdev->pending.raw_data)
- hsdev->pending.raw_size = sz;
- else
- hsdev->pending.raw_size = 0;
- complete(&hsdev->pending.ready);
+ if (hsdev->pending.max_raw_size) {
+ if (hsdev->pending.index < hsdev->pending.max_raw_size) {
+ avail = hsdev->pending.max_raw_size - hsdev->pending.index;
+ copy_size = clamp(sz, 0U, avail);
+
+ memcpy(hsdev->pending.raw_data + hsdev->pending.index,
+ ptr, copy_size);
+ hsdev->pending.index += copy_size;
+ if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
+ hsdev->pending.raw_size = hsdev->pending.index;
+ complete(&hsdev->pending.ready);
+ }
+ }
+ } else {
+ hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
+ if (hsdev->pending.raw_data)
+ hsdev->pending.raw_size = sz;
+ else
+ hsdev->pending.raw_size = 0;
+ complete(&hsdev->pending.ready);
+ }
}
if (callback->capture_sample) {
if (report->field[i]->logical)
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 524b53a3c87b..37b60c3aaf66 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -595,8 +595,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
if (!READ_ONCE(uhid->running))
return -EINVAL;
- hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
- min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+ hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, UHID_DATA_MAX,
+ min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
return 0;
}
@@ -606,8 +606,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
if (!READ_ONCE(uhid->running))
return -EINVAL;
- hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
- min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
+ hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, UHID_DATA_MAX,
+ min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
return 0;
}
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index c45f182d0448..5f4395f7c645 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -522,7 +522,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
pidff->set_effect_type->value[0] =
- pidff->create_new_effect_type->value[0];
+ pidff_get_effect_type_id(pidff, effect);
pidff_set_duration(&pidff->set_effect[PID_DURATION],
effect->replay.length);
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 2220168bf116..24b8b33a07f6 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -54,7 +54,7 @@ static void wacom_wac_queue_insert(struct hid_device *hdev,
{
bool warned = false;
- while (kfifo_avail(fifo) < size) {
+ while (kfifo_avail(fifo) < size && !kfifo_is_empty(fifo)) {
if (!warned)
hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__);
warned = true;
@@ -62,7 +62,9 @@ static void wacom_wac_queue_insert(struct hid_device *hdev,
kfifo_skip(fifo);
}
- kfifo_in(fifo, raw_data, size);
+ if (!kfifo_in(fifo, raw_data, size))
+ hid_warn_ratelimited(hdev, "%s: report is too large (%d)\n",
+ __func__, size);
}
static void wacom_wac_queue_flush(struct hid_device *hdev,
@@ -74,7 +76,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
unsigned int count;
int err;
- buf = kzalloc(size, GFP_KERNEL);
+ buf = kzalloc(size, GFP_ATOMIC);
if (!buf) {
kfifo_skip(fifo);
continue;
@@ -2462,16 +2464,16 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
error = wacom_register_inputs(wacom);
if (error)
- goto fail;
+ goto fail_hw_stop;
if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
error = wacom_initialize_leds(wacom);
if (error)
- goto fail;
+ goto fail_hw_stop;
error = wacom_initialize_remotes(wacom);
if (error)
- goto fail;
+ goto fail_hw_stop;
}
if (!wireless) {
@@ -2485,14 +2487,14 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
cancel_delayed_work_sync(&wacom->init_work);
_wacom_query_tablet_data(wacom);
error = -ENODEV;
- goto fail_quirks;
+ goto fail_hw_stop;
}
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) {
error = hid_hw_open(hdev);
if (error) {
hid_err(hdev, "hw open failed\n");
- goto fail_quirks;
+ goto fail_hw_stop;
}
}
@@ -2501,7 +2503,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
return 0;
-fail_quirks:
+fail_hw_stop:
hid_hw_stop(hdev);
fail:
wacom_release_resources(wacom);
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index b952a1d47f12..a827f76b8144 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -83,7 +83,7 @@ struct etb_drvdata {
struct coresight_device *csdev;
struct miscdevice miscdev;
raw_spinlock_t spinlock;
- local_t reading;
+ atomic_t reading;
pid_t pid;
u8 *buf;
u32 buffer_depth;
@@ -601,7 +601,7 @@ static int etb_open(struct inode *inode, struct file *file)
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- if (local_cmpxchg(&drvdata->reading, 0, 1))
+ if (atomic_cmpxchg(&drvdata->reading, 0, 1))
return -EBUSY;
dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
@@ -639,7 +639,7 @@ static int etb_release(struct inode *inode, struct file *file)
{
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- local_set(&drvdata->reading, 0);
+ atomic_set(&drvdata->reading, 0);
dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
return 0;
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index 5776f63468fa..20a950b9dd4f 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -337,6 +337,7 @@ static void smb_sync_perf_buffer(struct smb_drv_data *drvdata,
unsigned long to_copy;
long pg_idx, pg_offset;
+ head %= (unsigned long)buf->nr_pages << PAGE_SHIFT;
pg_idx = head >> PAGE_SHIFT;
pg_offset = head & (PAGE_SIZE - 1);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 66c23535656b..0617f416cb0b 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -818,12 +818,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
if (r)
- goto err_unuse_clocks;
+ goto err_cpufreq;
pm_runtime_put_autosuspend(dev->dev);
return 0;
+err_cpufreq:
+ i2c_davinci_cpufreq_deregister(dev);
err_unuse_clocks:
pm_runtime_dont_use_autosuspend(dev->dev);
pm_runtime_put_sync(dev->dev);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 32a3cef02c7b..b29c99ed3883 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
*/
if (hwpec)
iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
-out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
* and clear status flags if not done already.
*/
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
+out:
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
return ret;
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index cd4da50c4dd9..e6c24a9d934d 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -1646,7 +1646,18 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
static int __maybe_unused lpi2c_suspend_noirq(struct device *dev)
{
- return pm_runtime_force_suspend(dev);
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ i2c_mark_adapter_suspended(&lpi2c_imx->adapter);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+ return ret;
+ }
+
+ return 0;
}
static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
@@ -1666,6 +1677,8 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
if (lpi2c_imx->target)
lpi2c_imx_target_init(lpi2c_imx);
+ i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+
return 0;
}
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 28c5c5c1fb7a..a21fa45bd64c 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -844,7 +844,7 @@ static int fsl_i2c_probe(struct platform_device *op)
"fsl,timeout", &mpc_ops.timeout);
if (!result) {
- mpc_ops.timeout *= HZ / 1000000;
+ mpc_ops.timeout = mpc_ops.timeout * HZ / 1000000;
if (mpc_ops.timeout < 5)
mpc_ops.timeout = 5;
} else {
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 067af255bd22..0ddd8a1d0e4d 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -464,8 +464,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
{
struct stm32f7_i2c_spec *specs;
u32 p_prev = STM32F7_PRESC_MAX;
- u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
- setup->clock_src);
+ /*
+ * Truncate instead of rounding to closest: if the clock period is
+ * overestimated, the computed SCL timings will come out shorter on
+ * the wire, which can push the bus above the target rate and below
+ * the spec's tLOW/tHIGH minimums.
+ */
+ u32 i2cclk = NSEC_PER_SEC / setup->clock_src;
u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
setup->speed_freq);
u32 clk_error_prev = i2cbus;
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 4039d1175c4c..8bea9fc6888f 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -63,6 +63,7 @@
static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);
+static void i2c_deregister_clients(struct i2c_adapter *adap);
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key);
@@ -1555,11 +1556,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
- dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+ res = dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+ if (res)
+ goto err_remove_irq_domain;
+
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
device_initialize(&adap->dev);
+ res = i2c_init_recovery(adap);
+ if (res == -EPROBE_DEFER)
+ goto err_put_adap;
+
/*
* This adapter can be used as a parent immediately after device_add(),
* setup runtime-pm (especially ignore-children) before hand.
@@ -1573,23 +1581,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
idr_replace(&i2c_adapter_idr, adap, adap->nr);
mutex_unlock(&core_lock);
+ adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
+
res = device_add(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
- put_device(&adap->dev);
- goto out_list;
+ goto err_replace_id;
}
- adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
-
res = i2c_setup_smbus_alert(adap);
if (res)
goto out_reg;
- res = i2c_init_recovery(adap);
- if (res == -EPROBE_DEFER)
- goto out_reg;
-
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
/* create pre-declared device nodes */
@@ -1608,10 +1611,19 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return 0;
out_reg:
+ i2c_deregister_clients(adap);
+ device_del(&adap->dev);
+err_replace_id:
+ mutex_lock(&core_lock);
+ idr_replace(&i2c_adapter_idr, NULL, adap->nr);
+ mutex_unlock(&core_lock);
debugfs_remove_recursive(adap->debugfs);
+err_put_adap:
init_completion(&adap->dev_released);
- device_unregister(&adap->dev);
+ put_device(&adap->dev);
wait_for_completion(&adap->dev_released);
+err_remove_irq_domain:
+ i2c_host_notify_irq_teardown(adap);
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
@@ -1747,29 +1759,10 @@ static int __process_removed_adapter(struct device_driver *d, void *data)
return 0;
}
-/**
- * i2c_del_adapter - unregister I2C adapter
- * @adap: the adapter being unregistered
- * Context: can sleep
- *
- * This unregisters an I2C adapter which was previously registered
- * by @i2c_add_adapter or @i2c_add_numbered_adapter.
- */
-void i2c_del_adapter(struct i2c_adapter *adap)
+static void i2c_deregister_clients(struct i2c_adapter *adap)
{
- struct i2c_adapter *found;
struct i2c_client *client, *next;
- /* First make sure that this adapter was ever added */
- mutex_lock(&core_lock);
- found = idr_find(&i2c_adapter_idr, adap->nr);
- mutex_unlock(&core_lock);
- if (found != adap) {
- pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
- return;
- }
-
- i2c_acpi_remove_space_handler(adap);
/* Tell drivers about this removal */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap,
@@ -1795,6 +1788,34 @@ void i2c_del_adapter(struct i2c_adapter *adap)
* them up properly, so we give them a chance to do that first. */
device_for_each_child(&adap->dev, NULL, __unregister_client);
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
+}
+
+/**
+ * i2c_del_adapter - unregister I2C adapter
+ * @adap: the adapter being unregistered
+ * Context: can sleep
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ */
+void i2c_del_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_adapter *found;
+
+ /* First make sure that this adapter was ever added */
+ mutex_lock(&core_lock);
+ found = idr_find(&i2c_adapter_idr, adap->nr);
+ if (found == adap)
+ idr_replace(&i2c_adapter_idr, NULL, adap->nr);
+ mutex_unlock(&core_lock);
+ if (found != adap) {
+ pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
+ return;
+ }
+
+ i2c_acpi_remove_space_handler(adap);
+
+ i2c_deregister_clients(adap);
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 2398eb7e12cd..dc8a6285cf3d 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -991,6 +991,8 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
if (samples && count > samples)
count = samples;
+ count = min_t(u8, count, BMC150_ACCEL_FIFO_LENGTH);
+
ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
if (ret)
return ret;
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 4717d80fc24a..7ac885d94d7f 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -147,8 +147,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
if (mask == IIO_CHAN_INFO_SCALE) {
/* Check no integer component */
if (val)
- return -EINVAL;
- ret = kxsd9_write_scale(indio_dev, val2);
+ ret = -EINVAL;
+ else
+ ret = kxsd9_write_scale(indio_dev, val2);
}
pm_runtime_put_autosuspend(st->dev);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a9dedbb8eb46..3a3dcba3db3b 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -78,6 +78,7 @@ config AD4030
config AD4062
tristate "Analog Devices AD4062 Driver"
depends on I3C
+ depends on GPIOLIB
select REGMAP_I3C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
@@ -311,6 +312,7 @@ config AD7298
config AD7380
tristate "Analog Devices AD7380 ADC driver"
depends on SPI_MASTER
+ select REGMAP
select SPI_OFFLOAD
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
@@ -414,6 +416,7 @@ config AD7766
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
+ select GPIOLIB
select REGULATOR
select REGMAP_SPI
select RATIONAL
@@ -434,6 +437,7 @@ config AD7779
depends on SPI
select CRC8
select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
select IIO_BACKEND
help
Say yes here to build support for Analog Devices AD777X family
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index a955556f9ec8..1b410291da53 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -262,11 +262,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
/*
* Read RÌ…DÌ…YÌ… pin (if possible) or status register to check if there is an
- * old event.
+ * old event. For devices with neither an RDY GPIO nor registers,
+ * ad_sd_read_reg() transmits no address byte and clocks raw MISO bytes,
+ * which is indistinguishable from reading conversion data and would
+ * partially consume a pending result. Skip the check for such devices.
+ *
+ * This is safe for all current registerless devices: ad7191 and ad7780
+ * (with powerdown GPIO) are reset between conversions by CS deassertion,
+ * so there is no stale result to drain; ad7780 (without powerdown GPIO)
+ * and max11205 are continuously-converting and cycle ~DRDY at the output
+ * data rate regardless of whether the previous result was read, so the
+ * next falling edge fires naturally.
+ *
+ * A future registerless device that holds ~DRDY asserted until data is
+ * read would be broken by this early return and would need either
+ * num_resetclks set or a rdy-gpio.
*/
if (sigma_delta->rdy_gpiod) {
pending_event = gpiod_get_value(sigma_delta->rdy_gpiod);
- } else {
+ } else if (sigma_delta->info->has_registers) {
unsigned int status_reg;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg);
@@ -274,12 +288,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
return ret;
pending_event = !(status_reg & AD_SD_REG_STATUS_RDY);
+ } else {
+ return 0;
}
if (!pending_event)
return 0;
/*
+ * With num_resetclks = 0, data_read_len is 0 and the drain sequence
+ * below would compute memset(data + 2, 0xff, 0 - 1), underflowing to
+ * SIZE_MAX and corrupting the heap. There is no safe way to drain the
+ * stale result without knowing the data register size; it will be
+ * consumed by the first ad_sd_read_reg() call in
+ * ad_sigma_delta_single_conversion().
+ */
+ if (!data_read_len)
+ return 0;
+
+ /*
* In general the size of the data register is unknown. It varies from
* device to device, might be one byte longer if CONTROL.DATA_STATUS is
* set and even varies on some devices depending on which input is
@@ -441,11 +468,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
out:
ad_sd_disable_irq(sigma_delta);
- ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
- ad_sigma_delta_disable_one(sigma_delta, chan->address);
-
out_unlock:
sigma_delta->keep_cs_asserted = false;
+ ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+ ad_sigma_delta_disable_one(sigma_delta, chan->address);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
out_release:
@@ -578,6 +604,9 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
return 0;
err_unlock:
+ sigma_delta->keep_cs_asserted = false;
+ ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+ sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
spi_unoptimize_message(&sigma_delta->sample_msg);
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c
index 43a7bc8158b5..db3a602327ff 100644
--- a/drivers/iio/adc/lpc32xx_adc.c
+++ b/drivers/iio/adc/lpc32xx_adc.c
@@ -179,6 +179,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ init_completion(&st->completion);
+
retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
LPC32XXAD_NAME, st);
if (retval < 0) {
@@ -197,8 +199,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, iodev);
- init_completion(&st->completion);
-
iodev->name = LPC32XXAD_NAME;
iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c
index 8f4ed3db94f0..753f6a0a6e7b 100644
--- a/drivers/iio/adc/nxp-sar-adc.c
+++ b/drivers/iio/adc/nxp-sar-adc.c
@@ -198,13 +198,13 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
writel(0, NXP_SAR_ADC_IMR(info->regs));
}
-static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, unsigned int cycles)
+static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, u64 cycles)
{
u64 rate;
rate = clk_get_rate(info->clk);
if (rate)
- ndelay(div64_u64(NSEC_PER_SEC, rate * cycles));
+ ndelay(div64_u64(NSEC_PER_SEC * cycles, rate));
}
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index 91995489bb1c..d47278f1c4fc 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -280,6 +280,7 @@ static int spear_adc_probe(struct platform_device *pdev)
st = iio_priv(indio_dev);
st->dev = dev;
+ init_completion(&st->completion);
mutex_init(&st->lock);
/*
@@ -326,8 +327,6 @@ static int spear_adc_probe(struct platform_device *pdev)
spear_adc_configure(st);
- init_completion(&st->completion);
-
indio_dev->name = SPEAR_ADC_MOD_NAME;
indio_dev->info = &spear_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index 2320be0efb50..82040f9395b0 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -459,7 +459,11 @@ static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev)
if (ret)
return ret;
- return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+ ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+ if (ret)
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
}
static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
index 8ea1269f74db..57eed8554bd9 100644
--- a/drivers/iio/adc/ti-ads124s08.c
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -321,7 +321,8 @@ static int ads124s_probe(struct spi_device *spi)
ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ads124s_priv->reset_gpio))
- dev_info(&spi->dev, "Reset GPIO not defined\n");
+ return dev_err_probe(&spi->dev, PTR_ERR(ads124s_priv->reset_gpio),
+ "Failed to get reset GPIO\n");
ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
index 700528c9a0a4..10e912bbf0c5 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -40,6 +40,8 @@ static void iio_hw_buf_release(struct iio_buffer *buffer)
{
struct hw_consumer_buffer *hw_buf =
iio_buffer_to_hw_consumer_buffer(buffer);
+
+ bitmap_free(buffer->scan_mask);
kfree(hw_buf);
}
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index 11d6bc1b63e6..d02f2de42327 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -4,6 +4,8 @@
*
* Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
*/
+
+#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
@@ -43,6 +45,11 @@
#define SCD30_TEMP_OFFSET_MAX 655360
#define SCD30_EXTRA_TIMEOUT_PER_S 250
+/* Floating point arithmetic macros */
+#define SCD30_FLOAT_MANTISSA_MSK GENMASK(22, 0)
+#define SCD30_FLOAT_EXP_MSK GENMASK(30, 23)
+#define SCD30_FLOAT_SIGN_MSK BIT(31)
+
enum {
SCD30_CONC,
SCD30_TEMP,
@@ -89,10 +96,14 @@ static int scd30_reset(struct scd30_state *state)
/* simplified float to fixed point conversion with a scaling factor of 0.01 */
static int scd30_float_to_fp(int float32)
{
- int fraction, shift,
- mantissa = float32 & GENMASK(22, 0),
- sign = (float32 & BIT(31)) ? -1 : 1,
- exp = (float32 & ~BIT(31)) >> 23;
+ int fraction, shift, sign;
+ int mantissa = FIELD_GET(SCD30_FLOAT_MANTISSA_MSK, float32);
+ int exp = FIELD_GET(SCD30_FLOAT_EXP_MSK, float32);
+
+ if (float32 & SCD30_FLOAT_SIGN_MSK)
+ sign = -1;
+ else
+ sign = 1;
/* special case 0 */
if (!exp && !mantissa)
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index dbc5e16fbde4..76f91696f66a 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -498,6 +498,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
u8 *outdata;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int byte_for_channel;
+ u32 tmp;
byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
ch->scan_type.shift, 8);
@@ -508,12 +509,22 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
if (err < 0)
return err;
- if (byte_for_channel == 1)
- *data = (s8)*outdata;
- else if (byte_for_channel == 2)
- *data = (s16)get_unaligned_le16(outdata);
- else if (byte_for_channel == 3)
- *data = (s32)sign_extend32(get_unaligned_le24(outdata), 23);
+ if (byte_for_channel == 1) {
+ tmp = *outdata;
+ } else if (byte_for_channel == 2) {
+ if (ch->scan_type.endianness == IIO_BE)
+ tmp = get_unaligned_be16(outdata);
+ else
+ tmp = get_unaligned_le16(outdata);
+ } else if (byte_for_channel == 3) {
+ if (ch->scan_type.endianness == IIO_BE)
+ tmp = get_unaligned_be24(outdata);
+ else
+ tmp = get_unaligned_le24(outdata);
+ } else {
+ return -EINVAL;
+ }
+ *data = sign_extend32(tmp, BYTES_TO_BITS(byte_for_channel) - 1);
return 0;
}
diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c
index a9578afa7015..6bc64f53bce9 100644
--- a/drivers/iio/dac/ad3552r-hs.c
+++ b/drivers/iio/dac/ad3552r-hs.c
@@ -549,7 +549,7 @@ static ssize_t ad3552r_hs_write_data_source(struct file *f,
guard(mutex)(&st->lock);
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -ENOSPC;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 38394b5f3275..d611341a0e2a 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -201,6 +201,9 @@ static int bmg160_get_filter(struct bmg160_data *data, int *val)
break;
}
+ if (i == ARRAY_SIZE(bmg160_samp_freq_table))
+ return -EINVAL;
+
*val = bmg160_samp_freq_table[i].filter;
return ret ? ret : IIO_VAL_INT;
@@ -218,6 +221,9 @@ static int bmg160_set_filter(struct bmg160_data *data, int val)
break;
}
+ if (i == ARRAY_SIZE(bmg160_samp_freq_table))
+ return -EINVAL;
+
ret = regmap_write(data->regmap, BMG160_REG_PMU_BW,
bmg160_samp_freq_table[i].bw_bits);
if (ret < 0) {
@@ -258,8 +264,14 @@ static int bmg160_chip_init(struct bmg160_data *data)
if (ret < 0)
return ret;
- /* Wait upto 500 ms to be ready after changing mode */
- usleep_range(500, 1000);
+ /*
+ * Wait for the chip to be ready after switching to normal mode.
+ * The BMG160 datasheet (BST-BMG160-DS000-07 Rev. 1.0, May 2013)
+ * specifies a start-up / wake-up time (tsu, twusm) of 30 ms; use
+ * BMG160_MAX_STARTUP_TIME_MS (80 ms) as a safety margin, matching
+ * what bmg160_runtime_resume() already does.
+ */
+ msleep(BMG160_MAX_STARTUP_TIME_MS);
/* Set Bandwidth */
ret = bmg160_set_bw(data, BMG160_DEF_BW);
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index d76e13cbac68..3e6a7af6ab01 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -94,7 +94,7 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
else
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
- adis->irq_flag,
+ adis->irq_flag | IRQF_NO_THREAD,
indio_dev->name,
adis->trig);
if (ret)
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 4abb83b75e2e..86f6ecfd64aa 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -788,7 +788,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
ret = devm_request_irq(&indio_dev->dev, irq,
&iio_trigger_generic_data_rdy_poll,
- irq_type, "bmi160", data->trig);
+ irq_type | IRQF_NO_THREAD,
+ "bmi160", data->trig);
if (ret)
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 532d5fdffaf8..7df920ef3cf0 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -1170,10 +1170,10 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 68a395758031..5c3840acf085 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -248,6 +248,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* compute watermark value in bytes */
wm_size = watermark * packet_size;
+ st->fifo.watermark.value = watermark;
/* changing FIFO watermark requires to turn off watermark interrupt */
ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
@@ -454,11 +455,10 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
st->fifo.nb.accel = 0;
st->fifo.nb.total = 0;
- /* compute maximum FIFO read size */
+ /* compute maximum FIFO read size (watermark for max = 0 interrupt case) */
if (max == 0)
- max_count = sizeof(st->fifo.data);
- else
- max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
+ max = st->fifo.watermark.value;
+ max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
/* read FIFO count value */
raw_fifo_count = (__be16 *)st->buffer;
@@ -574,6 +574,7 @@ int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
st->fifo.watermark.eff_gyro = 1;
st->fifo.watermark.eff_accel = 1;
+ st->fifo.watermark.value = 1;
/*
* Default FIFO configuration (bits 7 to 5)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
index ffca4da1e249..88b8b9f780af 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
@@ -34,6 +34,7 @@ struct inv_icm42600_fifo {
unsigned int accel;
unsigned int eff_gyro;
unsigned int eff_accel;
+ unsigned int value;
} watermark;
size_t count;
struct {
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 11339ddf1da3..a18dcac93929 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -755,10 +755,10 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
}
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 450cb5b47346..8261d9cf0d94 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -1660,6 +1660,26 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
return -ENODEV;
}
+ hw->settings = &st_lsm6dsx_sensor_settings[i];
+
+ if (hw->settings->shub_settings.page_mux.addr) {
+ /*
+ * If the IMU has the shub page selected on init, for example
+ * after a CPU watchdog reset while the page is selected, the
+ * regular register space is shadowed. While the regular
+ * register space is shadowed, the registers needed for
+ * initializing the IMU are not available.
+ *
+ * Unconditionally clear the shub page selection to ensure
+ * normal register access.
+ */
+ err = st_lsm6dsx_set_page(hw, false);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to clear shub page\n");
+ return err;
+ }
+ }
+
err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(hw->dev, "failed to read whoami register\n");
@@ -1672,7 +1692,6 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
}
*name = st_lsm6dsx_sensor_settings[i].id[j].name;
- hw->settings = &st_lsm6dsx_sensor_settings[i];
return 0;
}
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 10e689f49441..cd697fbeae47 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -156,7 +156,7 @@ static ssize_t iio_backend_debugfs_write_reg(struct file *file,
ssize_t rc;
int ret;
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -ENOSPC;
rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, count);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 22eefd048ba9..15b56f8972fc 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -418,7 +418,7 @@ static ssize_t iio_debugfs_write_reg(struct file *file,
char buf[80];
int ret;
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -EINVAL;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index a0d6fcf2a9c9..e6730f52262a 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -207,6 +207,8 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
goto unlock;
}
+ kfifo_reset_out(&ev_int->det_events);
+
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
@@ -214,10 +216,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
if (fd < 0) {
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
- } else {
- kfifo_reset_out(&ev_int->det_events);
}
-
unlock:
mutex_unlock(&iio_dev_opaque->mlock);
return fd;
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index eff33e456c70..a28f308bc14e 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -45,6 +45,7 @@ config ADUX1020
config AL3000A
tristate "AL3000a ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3000a
@@ -55,6 +56,7 @@ config AL3000A
config AL3010
tristate "AL3010 ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3010
@@ -65,6 +67,7 @@ config AL3010
config AL3320A
tristate "AL3320A ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3320A
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
index 0932fa2b49fa..0e72906c637f 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -42,7 +42,7 @@ enum al3xxxx_range {
};
static const int al3010_scales[][2] = {
- {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
+ { 1, 187200 }, { 0, 296800 }, { 0, 74200 }, { 0, 18600 },
};
static const struct regmap_config al3010_regmap_config = {
@@ -111,7 +111,8 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3010_data *data = iio_priv(indio_dev);
- int ret, gain, raw;
+ int ret, gain;
+ __le16 raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -120,11 +121,12 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3010_REG_DATA_LOW
* - high byte of output is stored at AL3010_REG_DATA_LOW + 1
*/
- ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw);
+ ret = regmap_bulk_read(data->regmap, AL3010_REG_DATA_LOW,
+ &raw, sizeof(raw));
if (ret)
return ret;
- *val = raw;
+ *val = le16_to_cpu(raw);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c
index 63f5a85912fc..b9076f434417 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -135,7 +135,8 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3320a_data *data = iio_priv(indio_dev);
- int ret, gain, raw;
+ int ret, gain;
+ __le16 raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -144,11 +145,12 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3320A_REG_DATA_LOW
* - high byte of output is stored at AL3320A_REG_DATA_LOW + 1
*/
- ret = regmap_read(data->regmap, AL3320A_REG_DATA_LOW, &raw);
+ ret = regmap_bulk_read(data->regmap, AL3320A_REG_DATA_LOW,
+ &raw, sizeof(raw));
if (ret)
return ret;
- *val = raw;
+ *val = le16_to_cpu(raw);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index a0d8a58f2704..886accf5e859 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -258,7 +258,7 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev,
case IIO_LIGHT:
ret = gp2ap002_get_lux(gp2ap002);
if (ret < 0)
- return ret;
+ goto out;
*val = ret;
ret = IIO_VAL_INT;
goto out;
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index 53bc455b7bad..0d35d23da091 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -366,8 +366,10 @@ static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
ret = wait_event_timeout(opt->result_ready_queue,
opt->result_ready,
msecs_to_jiffies(OPT3001_RESULT_READY_LONG));
- if (ret == 0)
- return -ETIMEDOUT;
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ goto err;
+ }
} else {
/* Sleep for result ready time */
timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ?
diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c
index c5557867ea43..c5ccd833dde6 100644
--- a/drivers/iio/light/tsl2591.c
+++ b/drivers/iio/light/tsl2591.c
@@ -1137,10 +1137,8 @@ static int tsl2591_probe(struct i2c_client *client)
NULL, tsl2591_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tsl2591_irq", indio_dev);
- if (ret) {
- dev_err_probe(&client->dev, ret, "IRQ request error\n");
- return -EINVAL;
- }
+ if (ret)
+ return ret;
indio_dev->info = &tsl2591_info;
} else {
indio_dev->info = &tsl2591_info_no_irq;
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 6bcacae3863c..da8c32cabfd6 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -875,9 +875,11 @@ static irqreturn_t veml6030_event_handler(int irq, void *private)
else
evtdir = IIO_EV_DIR_FALLING;
- iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
- 0, IIO_EV_TYPE_THRESH, evtdir),
- iio_get_time_ns(indio_dev));
+ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ evtdir),
+ iio_get_time_ns(indio_dev));
return IRQ_HANDLED;
}
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index b648b0afa573..b3468756bdf1 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -784,6 +784,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
exit:
mutex_unlock(&data->lock);
+ pm_runtime_put_autosuspend(&data->client->dev);
dev_err(&client->dev, "Error in reading axis\n");
return ret;
}
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 9b489766e457..0ebe0b682caa 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1910,7 +1910,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
u32 comp_press;
s32 comp_temp;
aligned_s64 timestamp;
- } buffer;
+ } buffer = { };
int ret;
guard(mutex)(&data->lock);
diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
index 830a5065c008..16e112b796ba 100644
--- a/drivers/iio/pressure/mpl115.c
+++ b/drivers/iio/pressure/mpl115.c
@@ -106,18 +106,18 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
pm_runtime_get_sync(data->dev);
ret = mpl115_comp_pressure(data, val, val2);
+ pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
- pm_runtime_put_autosuspend(data->dev);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_RAW:
pm_runtime_get_sync(data->dev);
/* temperature -5.35 C / LSB, 472 LSB is 25 C */
ret = mpl115_read_temp(data);
+ pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
- pm_runtime_put_autosuspend(data->dev);
*val = ret >> 6;
return IIO_VAL_INT;
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
index ad3e46d47fa8..6c6e6dab045f 100644
--- a/drivers/iio/proximity/vl53l0x-i2c.c
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -87,15 +87,14 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv)
ret = i2c_smbus_read_i2c_block_data(data->client,
VL_REG_RESULT_RANGE_STATUS,
sizeof(buffer), buffer);
- if (ret < 0)
- return ret;
- else if (ret != 12)
- return -EREMOTEIO;
+ if (ret != 12)
+ goto done;
scan.chan = get_unaligned_be16(&buffer[10]);
iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
iio_get_time_ns(indio_dev));
+done:
iio_trigger_notify_done(indio_dev->trig);
vl53l0x_clear_irq(data);
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index 774728c804c0..1be19fe8aa3f 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -1334,7 +1334,7 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
if (ret < 0)
- return ret;
+ goto error_ret;
st->sample.fault = reg_val;
}
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 07d6e65709f7..0850bf691820 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MAX31865) += max31865.o
obj-$(CONFIG_MCP9600) += mcp9600.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
-obj-$(CONFIG_MLX90632) += mlx90635.o
+obj-$(CONFIG_MLX90635) += mlx90635.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TMP117) += tmp117.o
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index 38e6f8dfd3b8..2bc5cd46a72f 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -741,7 +741,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
struct ltc2983_rtd *rtd;
int ret = 0;
struct device *dev = &st->spi->dev;
- u32 excitation_current = 0, n_wires = 0;
+ u32 excitation_current = 0, n_wires = 2;
rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
if (!rtd)
@@ -1177,12 +1177,11 @@ static int ltc2983_chan_read(struct ltc2983_data *st,
start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan);
dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n",
sensor->chan, start_conversion);
+ reinit_completion(&st->completion);
/* start conversion */
ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion);
if (ret)
return ret;
-
- reinit_completion(&st->completion);
/*
* wait for conversion to complete.
* 300 ms should be more than enough to complete the conversion.
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index d8d8c8936d17..bf62143fa719 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -350,7 +350,7 @@ static int tmp006_probe(struct i2c_client *client)
data->drdy_trig->ops = &tmp006_trigger_ops;
iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
- ret = iio_trigger_register(data->drdy_trig);
+ ret = devm_iio_trigger_register(&client->dev, data->drdy_trig);
if (ret)
return ret;
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 27992c38ad90..d9306c0414b5 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -438,7 +438,7 @@ static int addr6_resolve(struct sockaddr *src_sock,
static bool is_dst_local(const struct dst_entry *dst)
{
if (dst->ops->family == AF_INET)
- return !!(dst_rtable(dst)->rt_type & RTN_LOCAL);
+ return dst_rtable(dst)->rt_type == RTN_LOCAL;
else if (dst->ops->family == AF_INET6)
return !!(dst_rt6_info(dst)->rt6i_flags & RTF_LOCAL);
else
diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c
index 34d03584160c..b566d163c5aa 100644
--- a/drivers/infiniband/sw/siw/siw_qp_rx.c
+++ b/drivers/infiniband/sw/siw/siw_qp_rx.c
@@ -844,6 +844,15 @@ int siw_proc_rresp(struct siw_qp *qp)
}
mem_p = *mem;
+ if (unlikely(wqe->processed + srx->fpdu_part_rem > wqe->bytes)) {
+ siw_dbg_qp(qp, "rresp len: %d + %d > %d\n",
+ wqe->processed, srx->fpdu_part_rem, wqe->bytes);
+ wqe->wc_status = SIW_WC_LOC_LEN_ERR;
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF,
+ DDP_ECODE_T_BASE_BOUNDS, 0);
+ return -EINVAL;
+ }
bytes = min(srx->fpdu_part_rem, srx->skb_new);
rv = siw_rx_data(mem_p, srx, &frx->pbl_idx,
sge->laddr + wqe->processed, bytes);
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
index 6482ad859bd1..f81e122a3ccb 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
@@ -225,8 +225,9 @@ static int rdma_write_sg(struct rtrs_srv_op *id)
/* WR will fail with length error
* if this is 0
*/
- if (plist->length == 0) {
- rtrs_err(s, "Invalid RDMA-Write sg list length 0\n");
+ if (plist->length == 0 || plist->length > max_chunk_size) {
+ rtrs_err(s, "Invalid RDMA-Write sg list length %u\n",
+ plist->length);
return -EINVAL;
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index fd1cd731d781..effa76bfd8f9 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -186,14 +186,18 @@ void iforce_process_packet(struct iforce *iforce,
/* Check if an effect was just started or stopped */
i = data[1] & 0x7f;
- if (data[1] & 0x80) {
- if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report play event */
- input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ if (i < IFORCE_EFFECTS_MAX) {
+ if (data[1] & 0x80) {
+ if (!test_and_set_bit(FF_CORE_IS_PLAYED,
+ iforce->core_effects[i].flags)) {
+ /* Report play event */
+ input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ }
+ } else if (test_and_clear_bit(FF_CORE_IS_PLAYED,
+ iforce->core_effects[i].flags)) {
+ /* Report stop event */
+ input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
- } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report stop event */
- input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
for (j = 3; j < len; j += 2)
diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c
index 7f36f73844a9..6293b6e8148b 100644
--- a/drivers/input/joystick/maplecontrol.c
+++ b/drivers/input/joystick/maplecontrol.c
@@ -112,6 +112,8 @@ static int probe_maple_controller(struct device *dev)
pad->dev = idev;
pad->mdev = mdev;
+ maple_set_drvdata(mdev, pad);
+
idev->open = dc_pad_open;
idev->close = dc_pad_close;
@@ -146,7 +148,6 @@ static int probe_maple_controller(struct device *dev)
goto fail;
mdev->driver = mdrv;
- maple_set_drvdata(mdev, pad);
return 0;
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 80a5181313e1..3d5538dd4f23 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -166,6 +166,8 @@ static int probe_maple_kbd(struct device *dev)
kbd->dev = idev;
memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode));
+ maple_set_drvdata(mdev, kbd);
+
idev->name = mdev->product_name;
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
idev->keycode = kbd->keycode;
@@ -190,8 +192,6 @@ static int probe_maple_kbd(struct device *dev)
mdev->driver = mdrv;
- maple_set_drvdata(mdev, kbd);
-
return error;
fail_register:
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 5cba02a156ce..edb0a28d25aa 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -428,8 +428,17 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
if (error)
return error;
}
- data->width_x = data->max_x / x_traces;
- data->width_y = data->max_y / y_traces;
+
+ if (!x_traces || !y_traces) {
+ dev_warn(&client->dev,
+ "invalid trace numbers: x=%u, y=%u\n",
+ x_traces, y_traces);
+ data->width_x = 1;
+ data->width_y = 1;
+ } else {
+ data->width_x = data->max_x / x_traces;
+ data->width_y = data->max_y / y_traces;
+ }
if (device_property_read_u32(&client->dev,
"touchscreen-x-mm", &x_mm) ||
@@ -443,8 +452,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
} else {
- data->x_res = (data->max_x + 1) / x_mm;
- data->y_res = (data->max_y + 1) / y_mm;
+ if (unlikely(x_mm == 0 || y_mm == 0)) {
+ dev_warn(&client->dev,
+ "invalid physical dimensions: x_mm=%u, y_mm=%u\n",
+ x_mm, y_mm);
+ data->x_res = 1;
+ data->y_res = 1;
+ } else {
+ data->x_res = (data->max_x + 1) / x_mm;
+ data->y_res = (data->max_y + 1) / y_mm;
+ }
}
if (device_property_read_bool(&client->dev, "elan,clickpad"))
@@ -956,6 +973,7 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
if (data->report_features & ETP_FEATURE_REPORT_MK) {
unsigned int mk_x, mk_y, area_x, area_y;
+ int adj_width_x, adj_width_y;
u8 mk_data = high_precision ?
packet[ETP_MK_DATA_OFFSET + contact_num] :
finger_data[3];
@@ -967,8 +985,14 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
* To avoid treating large finger as palm, let's reduce
* the width x and y per trace.
*/
- area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
- area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
+
+ adj_width_x = data->width_x > ETP_FWIDTH_REDUCE ?
+ data->width_x - ETP_FWIDTH_REDUCE : 0;
+ adj_width_y = data->width_y > ETP_FWIDTH_REDUCE ?
+ data->width_y - ETP_FWIDTH_REDUCE : 0;
+
+ area_x = mk_x * adj_width_x;
+ area_y = mk_y * adj_width_y;
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index c99f7e234219..0c8f7d1b02aa 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -48,7 +48,7 @@ static void dc_mouse_callback(struct mapleq *mq)
static int dc_mouse_open(struct input_dev *dev)
{
- struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev));
+ struct dc_mouse *mse = input_get_drvdata(dev);
maple_getcond_callback(mse->mdev, dc_mouse_callback, HZ/50,
MAPLE_FUNC_MOUSE);
@@ -58,7 +58,7 @@ static int dc_mouse_open(struct input_dev *dev)
static void dc_mouse_close(struct input_dev *dev)
{
- struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev));
+ struct dc_mouse *mse = input_get_drvdata(dev);
maple_getcond_callback(mse->mdev, dc_mouse_callback, 0,
MAPLE_FUNC_MOUSE);
@@ -88,6 +88,9 @@ static int probe_maple_mouse(struct device *dev)
mse->dev = input_dev;
mse->mdev = mdev;
+ maple_set_drvdata(mdev, mse);
+
+ input_set_drvdata(input_dev, mse);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
@@ -102,12 +105,12 @@ static int probe_maple_mouse(struct device *dev)
goto fail_register;
mdev->driver = mdrv;
- maple_set_drvdata(mdev, mse);
return error;
fail_register:
input_free_device(input_dev);
+ maple_set_drvdata(mdev, NULL);
fail_nomem:
kfree(mse);
fail:
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 687cb987bc13..ade57e2a7201 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -455,11 +455,13 @@ static int __init rmi_bus_init(void)
if (error) {
pr_err("%s: error registering the RMI physical driver: %d\n",
__func__, error);
- goto err_unregister_bus;
+ goto err_unregister_function_handlers;
}
return 0;
+err_unregister_function_handlers:
+ rmi_unregister_function_handlers();
err_unregister_bus:
bus_unregister(&rmi_bus_type);
return error;
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 35045f161dc2..b2155c8e20e7 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -233,7 +233,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END);
f30->gpioled_key_map = devm_kcalloc(&fn->dev,
- button_count,
+ f30->gpioled_count,
sizeof(f30->gpioled_key_map[0]),
GFP_KERNEL);
if (!f30->gpioled_key_map) {
diff --git a/drivers/input/rmi4/rmi_f3a.c b/drivers/input/rmi4/rmi_f3a.c
index 0e8baed84dbb..a0777644eef0 100644
--- a/drivers/input/rmi4/rmi_f3a.c
+++ b/drivers/input/rmi4/rmi_f3a.c
@@ -132,7 +132,7 @@ static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a,
int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END);
f3a->gpio_key_map = devm_kcalloc(&fn->dev,
- button_count,
+ f3a->gpio_count,
sizeof(f3a->gpio_key_map[0]),
GFP_KERNEL);
if (!f3a->gpio_key_map) {
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 22b2f57fd91f..bf9b993f5733 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -219,6 +219,7 @@ static void gscps2_read_data(struct gscps2port *ps2port)
ps2port->buffer[ps2port->append].str = status;
ps2port->buffer[ps2port->append].data =
gscps2_readb_input(ps2port->addr);
+ ps2port->append = (ps2port->append + 1) & BUFFER_SIZE;
} while (true);
}
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 4b39f7212d35..1ae1ae42582a 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -325,7 +325,6 @@ struct ser_req {
u8 ref_on;
u8 command;
u8 ref_off;
- u16 scratch;
struct spi_message msg;
struct spi_transfer xfer[8];
/*
@@ -333,6 +332,7 @@ struct ser_req {
* transfer buffers to live in their own cache lines.
*/
__be16 sample ____cacheline_aligned;
+ u16 scratch;
};
struct ads7845_ser_req {
@@ -403,8 +403,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
spi_message_add_tail(&req->xfer[5], &req->msg);
/* clear the command register */
- req->scratch = 0;
- req->xfer[6].tx_buf = &req->scratch;
+ req->xfer[6].rx_buf = &req->scratch;
req->xfer[6].len = 1;
spi_message_add_tail(&req->xfer[6], &req->msg);
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index f8798d11ec03..17fcfe45988c 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1057,7 +1057,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
}
ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
- ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
+ ts->max_touch_num = min(ts->config[MAX_CONTACTS_LOC] & 0x0f,
+ GOODIX_MAX_CONTACTS);
x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]);
y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]);
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index af462086a65c..41859bfa2844 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -165,7 +165,7 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
unsigned int x;
unsigned int y;
- if (touch->id > MMS114_MAX_TOUCH) {
+ if (touch->id == 0 || touch->id > MMS114_MAX_TOUCH) {
dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id);
return;
}
@@ -217,7 +217,9 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
struct mms114_data *data = dev_id;
struct i2c_client *client = data->client;
struct mms114_touch touch[MMS114_MAX_TOUCH];
+ struct mms114_touch *t;
int packet_size;
+ int event_size;
int touch_size;
int index;
int error;
@@ -226,11 +228,19 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
if (packet_size <= 0)
goto out;
+ if (packet_size > sizeof(touch)) {
+ dev_err(&client->dev, "Invalid packet size %d (max %zu)\n",
+ packet_size, sizeof(touch));
+ goto out;
+ }
+
/* MMS136 has slightly different event size */
if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136)
- touch_size = packet_size / MMS136_EVENT_SIZE;
+ event_size = MMS136_EVENT_SIZE;
else
- touch_size = packet_size / MMS114_EVENT_SIZE;
+ event_size = MMS114_EVENT_SIZE;
+
+ touch_size = packet_size / event_size;
error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size,
(u8 *)touch);
@@ -238,18 +248,20 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
goto out;
for (index = 0; index < touch_size; index++) {
- switch (touch[index].type) {
+ t = (struct mms114_touch *)((u8 *)touch + index * event_size);
+
+ switch (t->type) {
case MMS114_TYPE_TOUCHSCREEN:
- mms114_process_mt(data, touch + index);
+ mms114_process_mt(data, t);
break;
case MMS114_TYPE_TOUCHKEY:
- mms114_process_touchkey(data, touch + index);
+ mms114_process_touchkey(data, t);
break;
default:
dev_err(&client->dev, "Wrong touch type (%d)\n",
- touch[index].type);
+ t->type);
break;
}
}
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 099fd88e65d8..3ed33378dfcd 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -63,12 +63,15 @@ static irqreturn_t tw_interrupt(struct serio *serio,
if (data) { /* touch */
tw->touched = 1;
tw->data[tw->idx++] = data;
- /* verify length and that the two Y's are the same */
- if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
- input_report_abs(dev, ABS_X, tw->data[0]);
- input_report_abs(dev, ABS_Y, tw->data[1]);
- input_report_key(dev, BTN_TOUCH, 1);
- input_sync(dev);
+ /* a full packet ends the accumulation, valid or not */
+ if (tw->idx == TW_LENGTH) {
+ /* report only if the two Y's are the same */
+ if (tw->data[1] == tw->data[2]) {
+ input_report_abs(dev, ABS_X, tw->data[0]);
+ input_report_abs(dev, ABS_Y, tw->data[1]);
+ input_report_key(dev, BTN_TOUCH, 1);
+ input_sync(dev);
+ }
tw->idx = 0;
}
} else if (tw->touched) { /* untouch */
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 57dc8fabc7d9..15ffc4742183 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1774,7 +1774,8 @@ void amd_iommu_domain_flush_pages(struct protection_domain *domain,
{
lockdep_assert_held(&domain->lock);
- if (likely(!amd_iommu_np_cache)) {
+ if (likely(!amd_iommu_np_cache) ||
+ size >= (1ULL<<52)) {
__domain_flush_pages(domain, address, size);
/* Wait until IOMMU TLB and all device IOTLB flushes are complete */
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index ef145560aa98..775f1c4ae346 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1254,18 +1254,29 @@ void intel_iommu_disable_iopf(struct device *dev);
static inline int iopf_for_domain_set(struct iommu_domain *domain,
struct device *dev)
{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+
if (!domain || !domain->iopf_handler)
return 0;
+ /* SVA with non-IOMMU/PRI IOPF handling is allowed. */
+ if (domain->type == IOMMU_DOMAIN_SVA && !info->pri_supported)
+ return 0;
+
return intel_iommu_enable_iopf(dev);
}
static inline void iopf_for_domain_remove(struct iommu_domain *domain,
struct device *dev)
{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+
if (!domain || !domain->iopf_handler)
return;
+ if (domain->type == IOMMU_DOMAIN_SVA && !info->pri_supported)
+ return;
+
intel_iommu_disable_iopf(dev);
}
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 57cd1db7207a..fea10acd4f02 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -164,12 +164,9 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
if (IS_ERR(dev_pasid))
return PTR_ERR(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;
- }
+ 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;
@@ -184,8 +181,7 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
return 0;
out_unwind_iopf:
- if (info->pri_supported)
- iopf_for_domain_replace(old, domain, dev);
+ 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/iommufd/driver.c b/drivers/iommu/iommufd/driver.c
index 61e6b02601d1..3b8067976eac 100644
--- a/drivers/iommu/iommufd/driver.c
+++ b/drivers/iommu/iommufd/driver.c
@@ -149,15 +149,18 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu,
goto out_unlock_veventqs;
}
- spin_lock(&veventq->common.lock);
- if (veventq->num_events == veventq->depth) {
+ /* Pre-allocate to avoid GFP_ATOMIC; use GFP_NOWAIT to avoid sleeping */
+ vevent = kzalloc_flex(*vevent, event_data, data_len, GFP_NOWAIT);
+ if (!vevent) {
+ spin_lock(&veventq->common.lock);
vevent = &veventq->lost_events_header;
+ rc = -ENOMEM;
goto out_set_header;
}
- vevent = kzalloc_flex(*vevent, event_data, data_len, GFP_ATOMIC);
- if (!vevent) {
- rc = -ENOMEM;
+ spin_lock(&veventq->common.lock);
+ if (veventq->num_events == veventq->depth) {
+ kfree(vevent);
vevent = &veventq->lost_events_header;
goto out_set_header;
}
diff --git a/drivers/iommu/iommufd/eventq.c b/drivers/iommu/iommufd/eventq.c
index 710eef0b6004..5129e3bf5461 100644
--- a/drivers/iommu/iommufd/eventq.c
+++ b/drivers/iommu/iommufd/eventq.c
@@ -139,9 +139,14 @@ static ssize_t iommufd_fault_fops_read(struct file *filep, char __user *buf,
mutex_lock(&fault->mutex);
while ((group = iommufd_fault_deliver_fetch(fault))) {
+ size_t group_done = done;
+
if (done >= count ||
group->fault_count * fault_size > count - done) {
iommufd_fault_deliver_restore(fault, group);
+ /* Read count doesn't fit the first fault group */
+ if (done == 0)
+ rc = -EINVAL;
break;
}
@@ -157,14 +162,17 @@ static ssize_t iommufd_fault_fops_read(struct file *filep, char __user *buf,
iommufd_compose_fault_message(&iopf->fault,
&data, idev,
group->cookie);
- if (copy_to_user(buf + done, &data, fault_size)) {
+ if (copy_to_user(buf + group_done, &data, fault_size)) {
xa_erase(&fault->response, group->cookie);
iommufd_fault_deliver_restore(fault, group);
rc = -EFAULT;
break;
}
- done += fault_size;
+ group_done += fault_size;
}
+ if (rc)
+ break;
+ done = group_done;
}
mutex_unlock(&fault->mutex);
@@ -264,8 +272,10 @@ iommufd_veventq_deliver_fetch(struct iommufd_veventq *veventq)
/* Make a copy of the lost_events_header for copy_to_user */
if (next == &veventq->lost_events_header) {
vevent = kzalloc_obj(*vevent, GFP_ATOMIC);
- if (!vevent)
+ if (!vevent) {
+ vevent = ERR_PTR(-ENOMEM);
goto out_unlock;
+ }
}
list_del(&next->node);
if (vevent)
@@ -310,8 +320,17 @@ static ssize_t iommufd_veventq_fops_read(struct file *filep, char __user *buf,
if (*ppos)
return -ESPIPE;
+ /* Minimum read count is a vEVENT header */
+ if (count < sizeof(*hdr))
+ return -EINVAL;
while ((cur = iommufd_veventq_deliver_fetch(veventq))) {
+ if (IS_ERR(cur)) {
+ if (done == 0)
+ rc = PTR_ERR(cur);
+ break;
+ }
+
/* Validate the remaining bytes against the header size */
if (done >= count || sizeof(*hdr) > count - done) {
iommufd_veventq_deliver_restore(veventq, cur);
@@ -321,8 +340,11 @@ static ssize_t iommufd_veventq_fops_read(struct file *filep, char __user *buf,
/* If being a normal vEVENT, validate against the full size */
if (!vevent_for_lost_events_header(cur) &&
- sizeof(hdr) + cur->data_len > count - done) {
+ sizeof(*hdr) + cur->data_len > count - done) {
iommufd_veventq_deliver_restore(veventq, cur);
+ /* Read count doesn't fit a single normal vEVENT */
+ if (done == 0)
+ rc = -EINVAL;
break;
}
@@ -336,6 +358,7 @@ static ssize_t iommufd_veventq_fops_read(struct file *filep, char __user *buf,
if (cur->data_len &&
copy_to_user(buf + done, cur->event_data, cur->data_len)) {
iommufd_veventq_deliver_restore(veventq, cur);
+ done -= sizeof(*hdr);
rc = -EFAULT;
break;
}
@@ -473,6 +496,9 @@ int iommufd_fault_iopf_handler(struct iopf_group *group)
static const struct file_operations iommufd_veventq_fops =
INIT_EVENTQ_FOPS(iommufd_veventq_fops_read, NULL);
+/* An arbitrary upper bound for veventq_depth that fits all existing HWs */
+#define VEVENTQ_MAX_DEPTH (1U << 19)
+
int iommufd_veventq_alloc(struct iommufd_ucmd *ucmd)
{
struct iommu_veventq_alloc *cmd = ucmd->cmd;
@@ -484,7 +510,7 @@ int iommufd_veventq_alloc(struct iommufd_ucmd *ucmd)
if (cmd->flags || cmd->__reserved ||
cmd->type == IOMMU_VEVENTQ_TYPE_DEFAULT)
return -EOPNOTSUPP;
- if (!cmd->veventq_depth)
+ if (!cmd->veventq_depth || cmd->veventq_depth > VEVENTQ_MAX_DEPTH)
return -EINVAL;
viommu = iommufd_get_viommu(ucmd, cmd->viommu_id);
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index fe789c2dc0c9..623cc608ca0c 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -489,6 +489,9 @@ int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd)
return rc;
}
+/* An arbitrary entry_num cap, far above any realistic invalidation batch */
+#define IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX (1U << 19)
+
int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd)
{
struct iommu_hwpt_invalidate *cmd = ucmd->cmd;
@@ -507,7 +510,13 @@ int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd)
goto out;
}
- if (cmd->entry_num && (!cmd->data_uptr || !cmd->entry_len)) {
+ /*
+ * Bound entry_num and entry_len so a single call cannot pin the CPU;
+ * entry_len also caps the copy_struct_from_user() trailing-zero scan.
+ */
+ if (cmd->entry_num &&
+ (!cmd->data_uptr || !cmd->entry_len || cmd->entry_len > PAGE_SIZE ||
+ cmd->entry_num > IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX)) {
rc = -EINVAL;
goto out;
}
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 6ac1965199e9..43fbc5bed8de 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -602,7 +602,7 @@ struct iommufd_vevent {
struct iommufd_vevent_header header;
struct list_head node; /* for iommufd_eventq::deliver */
ssize_t data_len;
- u64 event_data[] __counted_by(data_len);
+ u8 event_data[] __counted_by(data_len);
};
#define vevent_for_lost_events_header(vevent) \
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index a529174c94cf..c23c03f0cb6e 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1816,8 +1816,11 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para
goto out_argv;
table = dm_get_live_table(md, &srcu_idx);
- if (!table)
+ if (!table) {
+ DMERR("The device has no table.");
+ r = -EINVAL;
goto out_table;
+ }
if (dm_deleting_md(md)) {
r = -ENXIO;
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 8c684756d5fc..d147ec483081 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1202,7 +1202,8 @@ static int mtk_jpeg_release(struct file *file)
struct mtk_jpeg_dev *jpeg = video_drvdata(file);
struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file);
- cancel_work_sync(&ctx->jpeg_work);
+ if (jpeg->variant->jpeg_worker)
+ cancel_work_sync(&ctx->jpeg_work);
mutex_lock(&jpeg->lock);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
index 4bf8570e1b9e..2d639b789910 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -556,8 +556,8 @@ static void mxc_isi_remove(struct platform_device *pdev)
mxc_isi_pipe_cleanup(pipe);
}
- mxc_isi_crossbar_cleanup(&isi->crossbar);
mxc_isi_v4l2_cleanup(isi);
+ mxc_isi_crossbar_cleanup(&isi->crossbar);
}
static const struct of_device_id mxc_isi_of_match[] = {
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index 39430dd44e30..56fb7cceafc6 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -195,7 +195,6 @@ static int ec_device_probe(struct platform_device *pdev)
if (!ec)
return retval;
- dev_set_drvdata(dev, ec);
ec->ec_dev = dev_get_drvdata(dev->parent);
ec->dev = dev;
ec->cmd_offset = ec_platform->cmd_offset;
@@ -237,6 +236,8 @@ static int ec_device_probe(struct platform_device *pdev)
if (retval)
goto failed;
+ dev_set_drvdata(dev, ec);
+
/* check whether this EC is a sensor hub. */
if (cros_ec_get_sensor_count(ec) > 0) {
retval = mfd_add_hotplug_devices(ec->dev,
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index ee9c48f7f68f..0dd0a30c3db4 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -276,6 +276,14 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
"Received header: %6phC. Package length: %i\n",
header_start, skb->len - KALMIA_HEADER_LENGTH);
+ /* both framing headers must be present before we subtract
+ * them, otherwise usb_packet_length underflows and the
+ * device-supplied ether_packet_length drives an out of bounds
+ * access below
+ */
+ if (skb->len < 2 * KALMIA_HEADER_LENGTH)
+ return 0;
+
/* subtract start header and end header */
usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH);
ether_packet_length = get_unaligned_le16(&header_start[2]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 3d74fabe7408..a326f4c95c7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -1508,6 +1508,9 @@ static void mt7921_channel_switch_rx_beacon(struct ieee80211_hw *hw,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval = vif->bss_conf.beacon_int;
+ if (!dev->new_ctx)
+ return;
+
if (cfg80211_chandef_identical(&chsw->chandef,
&dev->new_ctx->def) &&
chsw->count) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 79cc30a3b29e..9dc5ee51eb9f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -2403,6 +2403,9 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
if (ieee80211_vif_is_mld(vif))
return;
+ if (!dev->new_ctx)
+ return;
+
beacon_interval = vif->bss_conf.beacon_int;
if (cfg80211_chandef_identical(&chsw->chandef,
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 70feab97dccb..486c1774fb97 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3363,7 +3363,8 @@ static bool rtw89_core_skb_pn_valid(struct rtw89_dev *rtwdev,
last_pn = tid_stats->last_pn;
if (pn > last_pn) {
- if (ieee80211_sn_less(mpdu_sn, tid_stats->last_sn)) {
+ if (last_pn != -1LL &&
+ ieee80211_sn_less(mpdu_sn, tid_stats->last_sn)) {
dev_kfree_skb_any(skb);
return false;
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 501c3af1da01..0672d13d13a6 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -964,7 +964,8 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
rtw89_err(rtwdev, "failed to add key to sec cam\n");
return ret;
}
- rtw89_core_tid_rx_stats_reset(rtwdev);
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ rtw89_core_tid_rx_stats_reset(rtwdev);
break;
case DISABLE_KEY:
flush_work(&rtwdev->txq_work);
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
index 9935da48a52e..15d99d08f84f 100644
--- a/drivers/ntb/hw/epf/ntb_hw_epf.c
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -92,6 +92,7 @@ struct ntb_epf_dev {
int db_val;
u64 db_valid_mask;
+ int irq_base;
};
#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
@@ -318,7 +319,7 @@ static irqreturn_t ntb_epf_vec_isr(int irq, void *dev)
struct ntb_epf_dev *ndev = dev;
int irq_no;
- irq_no = irq - pci_irq_vector(ndev->ntb.pdev, 0);
+ irq_no = irq - ndev->irq_base;
ndev->db_val = irq_no + 1;
if (irq_no == 0)
@@ -350,12 +351,13 @@ static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max)
argument &= ~MSIX_ENABLE;
}
+ ndev->irq_base = pci_irq_vector(pdev, 0);
for (i = 0; i < irq; i++) {
ret = request_irq(pci_irq_vector(pdev, i), ntb_epf_vec_isr,
0, "ntb_epf", ndev);
if (ret) {
dev_err(dev, "Failed to request irq\n");
- goto err_request_irq;
+ goto err_free_irq;
}
}
@@ -365,16 +367,14 @@ static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max)
argument | irq);
if (ret) {
dev_err(dev, "Failed to configure doorbell\n");
- goto err_configure_db;
+ goto err_free_irq;
}
return 0;
-err_configure_db:
- for (i = 0; i < ndev->db_count + 1; i++)
+err_free_irq:
+ while (i--)
free_irq(pci_irq_vector(pdev, i), ndev);
-
-err_request_irq:
pci_free_irq_vectors(pdev);
return ret;
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 263161cb8ac0..9d3ac937f594 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -511,6 +511,12 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
ns = nvme_find_path(head);
if (likely(ns)) {
bio_set_dev(bio, ns->disk->part0);
+ /*
+ * Use BIO_REMAPPED to skip bio_check_eod() when this bio
+ * enters submit_bio_noacct() for the per-path device. The EOD
+ * check already passed on the multipath head.
+ */
+ bio_set_flag(bio, BIO_REMAPPED);
bio->bi_opf |= REQ_NVME_MPATH;
trace_block_bio_remap(bio, disk_devt(ns->head->disk),
bio->bi_iter.bi_sector);
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index e9b35549e254..114869d16a1f 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
u64 offset = nvmet_get_log_page_offset(req->cmd);
size_t data_len = nvmet_get_log_page_len(req->cmd);
size_t alloc_len;
+ size_t copy_len;
struct nvmet_subsys_link *p;
struct nvmet_port *r;
u32 numrec = 0;
@@ -242,7 +243,27 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
up_read(&nvmet_config_sem);
- status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);
+ /*
+ * Validate the host-supplied log page offset before copying out.
+ * Without this check, the host controls a 64-bit byte offset into
+ * a small kzalloc'd buffer: a value past the log page lets the
+ * subsequent memcpy read adjacent kernel heap, and a value aimed
+ * at unmapped kernel memory faults the in-kernel copy and crashes
+ * the target host. The Discovery controller is unauthenticated,
+ * so the bug is reachable from any reachable fabric peer.
+ */
+ if (offset > alloc_len) {
+ req->error_loc =
+ offsetof(struct nvme_get_log_page_command, lpo);
+ status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+ goto out_free_buffer;
+ }
+
+ copy_len = min_t(size_t, data_len, alloc_len - offset);
+ status = nvmet_copy_to_sgl(req, 0, buffer + offset, copy_len);
+ if (!status && copy_len < data_len)
+ status = nvmet_zero_sgl(req, copy_len, data_len - copy_len);
+out_free_buffer:
kfree(buffer);
out:
nvmet_req_complete(req, status);
diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c
index f1e613e7c63e..0a85acf1e5c7 100644
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -132,13 +132,22 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
return 0;
}
-static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
+static u8 nvmet_auth_reply(struct nvmet_req *req, void *d, u32 tl)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvmf_auth_dhchap_reply_data *data = d;
- u16 dhvlen = le16_to_cpu(data->dhvlen);
+ u16 dhvlen;
u8 *response;
+ if (tl < sizeof(*data))
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
+ dhvlen = le16_to_cpu(data->dhvlen);
+
+ /* Validate that hl and dhvlen fit within the transfer length */
+ if (sizeof(*data) + 2 * (size_t)data->hl + dhvlen > tl)
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n",
__func__, ctrl->cntlid, req->sq->qid,
data->hl, data->cvalid, dhvlen);
@@ -338,7 +347,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
switch (data->auth_id) {
case NVME_AUTH_DHCHAP_MESSAGE_REPLY:
- dhchap_status = nvmet_auth_reply(req, d);
+ dhchap_status = nvmet_auth_reply(req, d, tl);
if (dhchap_status == 0)
req->sq->dhchap_step =
NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1;
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index e6e2c3f9afdf..ac26f4f774c4 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1598,8 +1598,10 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
pending++;
}
mutex_unlock(&nvmet_rdma_queue_mutex);
- if (pending > NVMET_RDMA_BACKLOG)
- return NVME_SC_CONNECT_CTRL_BUSY;
+ if (pending > NVMET_RDMA_BACKLOG) {
+ ret = NVME_SC_CONNECT_CTRL_BUSY;
+ goto put_device;
+ }
}
ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index f96adfd5b219..c02e20632fa6 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -673,7 +673,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
*/
if (unlikely(opp_table->regulator_count == -1)) {
opp_table->regulator_count = 0;
- return 0;
+ goto free_microwatt;
}
for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
@@ -696,6 +696,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
opp->supplies[i].u_watt = microwatt[i];
}
+free_microwatt:
kfree(microwatt);
free_microamp:
kfree(microamp);
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index e35044cc5218..38b2d8262e51 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -137,6 +137,7 @@ struct imx_pcie_drvdata {
const u32 mode_off[IMX_PCIE_MAX_INSTANCES];
const u32 mode_mask[IMX_PCIE_MAX_INSTANCES];
const struct pci_epc_features *epc_features;
+ int (*select_ref_clk_src)(struct imx_pcie *pcie);
int (*init_phy)(struct imx_pcie *pcie);
int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable);
int (*core_reset)(struct imx_pcie *pcie, bool assert);
@@ -247,11 +248,27 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie)
return imx_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
}
-static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
+static int imx95_pcie_select_ref_clk_src(struct imx_pcie *imx_pcie)
{
bool ext = imx_pcie->enable_ext_refclk;
/*
+ * Regarding the Signal Descriptions of i.MX95 PCIe PHY, ref_use_pad is
+ * used to select reference clock connected to a pair of pads.
+ *
+ * Any change in this input must be followed by phy_reset assertion.
+ */
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL,
+ IMX95_PCIE_REF_USE_PAD,
+ ext ? IMX95_PCIE_REF_USE_PAD : 0);
+
+ return 0;
+}
+
+static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
+{
+ /*
* ERR051624: The Controller Without Vaux Cannot Exit L23 Ready
* Through Beacon or PERST# De-assertion
*
@@ -269,13 +286,6 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
IMX95_PCIE_PHY_CR_PARA_SEL,
IMX95_PCIE_PHY_CR_PARA_SEL);
- regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL,
- IMX95_PCIE_REF_USE_PAD,
- ext ? IMX95_PCIE_REF_USE_PAD : 0);
- regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0,
- IMX95_PCIE_REF_CLKEN,
- ext ? 0 : IMX95_PCIE_REF_CLKEN);
-
return 0;
}
@@ -665,14 +675,6 @@ static int imx_pcie_attach_pd(struct device *dev)
return 0;
}
-static int imx6sx_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
-{
- regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6SX_GPR12_PCIE_TEST_POWERDOWN,
- enable ? 0 : IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
- return 0;
-}
-
static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
if (enable) {
@@ -732,7 +734,29 @@ static void imx95_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable)
static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
+ bool ext = imx_pcie->enable_ext_refclk;
+
imx95_pcie_clkreq_override(imx_pcie, enable);
+ /*
+ * The ref_clk_en signal must remain de-asserted until the
+ * reference clock is running at appropriate frequency, at which
+ * point this bit can be asserted. For lower power states where
+ * the reference clock to the PHY is disabled, it may also be
+ * de-asserted.
+ * +------------------- -+--------+----------------+
+ * | External clock mode | Enable | PCIE_REF_CLKEN |
+ * +---------------------+--------+----------------+
+ * | TRUE | X | 1b'0 |
+ * +---------------------+--------+----------------+
+ * | FALSE | TRUE | 1b'1 |
+ * +---------------------+--------+----------------+
+ * | FALSE | FALSE | 1b'0 |
+ * +---------------------+--------+----------------+
+ */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0,
+ IMX95_PCIE_REF_CLKEN,
+ ext || !enable ? 0 : IMX95_PCIE_REF_CLKEN);
+
return 0;
}
@@ -786,6 +810,9 @@ static int imx6sx_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
if (assert)
regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
+ else
+ regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
/* Force PCIe PHY reset */
regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5, IMX6SX_GPR5_PCIE_BTNRST_RESET,
@@ -1256,6 +1283,9 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
pp->bridge->disable_device = imx_pcie_disable_device;
}
+ if (imx_pcie->drvdata->select_ref_clk_src)
+ imx_pcie->drvdata->select_ref_clk_src(imx_pcie);
+
imx_pcie_assert_core_reset(imx_pcie);
imx_pcie_assert_perst(imx_pcie, true);
@@ -1877,7 +1907,6 @@ static const struct imx_pcie_drvdata drvdata[] = {
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.init_phy = imx6sx_pcie_init_phy,
- .enable_ref_clk = imx6sx_pcie_enable_ref_clk,
.core_reset = imx6sx_pcie_core_reset,
.ops = &imx_pcie_host_ops,
},
@@ -1967,6 +1996,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
.core_reset = imx95_pcie_core_reset,
.init_phy = imx95_pcie_init_phy,
+ .select_ref_clk_src = imx95_pcie_select_ref_clk_src,
.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
.enable_ref_clk = imx95_pcie_enable_ref_clk,
.clr_clkreq_override = imx95_pcie_clr_clkreq_override,
@@ -2022,6 +2052,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.ltssm_mask = IMX95_PCIE_LTSSM_EN,
.mode_off[0] = IMX95_PE0_GEN_CTRL_1,
.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
+ .select_ref_clk_src = imx95_pcie_select_ref_clk_src,
.init_phy = imx95_pcie_init_phy,
.core_reset = imx95_pcie_core_reset,
.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index af6bf5cce65b..7d8eaef436ef 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1674,6 +1674,12 @@ static int qcom_pcie_ecam_host_init(struct pci_config_window *cfg)
pci->dbi_base = cfg->win;
pp->num_vectors = MSI_DEF_NUM_VECTORS;
+ /*
+ * dw_pcie_msi_host_init() is called directly here, bypassing
+ * dw_pcie_host_init() where pp->lock is normally initialized.
+ */
+ raw_spin_lock_init(&pp->lock);
+
ret = dw_pcie_msi_host_init(pp);
if (ret)
return ret;
diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c
index d6258c1cffe5..99952fb7189b 100644
--- a/drivers/pci/controller/pci-host-common.c
+++ b/drivers/pci/controller/pci-host-common.c
@@ -68,6 +68,10 @@ int pci_host_common_init(struct platform_device *pdev,
if (IS_ERR(cfg))
return PTR_ERR(cfg);
+ /* Do not reassign bus numbers if probe only */
+ if (!pci_has_flag(PCI_PROBE_ONLY))
+ pci_add_flags(PCI_REASSIGN_ALL_BUS);
+
bridge->sysdata = cfg;
bridge->ops = (struct pci_ops *)&ops->pci_ops;
bridge->enable_device = ops->enable_device;
diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
index bc630ab8a283..9609e6f50b98 100644
--- a/drivers/pci/controller/pci-loongson.c
+++ b/drivers/pci/controller/pci-loongson.c
@@ -176,6 +176,42 @@ static void loongson_pci_msi_quirk(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_PCIE_PORT5, loongson_pci_msi_quirk);
+/*
+ * Older steppings of the Loongson-3C6000 series incorrectly report the
+ * supported link speeds on their PCIe bridges (device IDs 0x3c19,
+ * 0x3c29) as only 2.5 GT/s, despite the upstream bus supporting speeds
+ * from 2.5 GT/s up to 16 GT/s.
+ */
+static void loongson_pci_bridge_speed_quirk(struct pci_dev *pdev)
+{
+ u8 old_supported_speeds = pdev->supported_speeds;
+
+ switch (pdev->bus->max_bus_speed) {
+ case PCIE_SPEED_16_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_16_0GB;
+ fallthrough;
+ case PCIE_SPEED_8_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_8_0GB;
+ fallthrough;
+ case PCIE_SPEED_5_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_5_0GB;
+ fallthrough;
+ case PCIE_SPEED_2_5GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_2_5GB;
+ break;
+ default:
+ pci_warn(pdev, "unexpected max bus speed");
+
+ return;
+ }
+
+ if (pdev->supported_speeds != old_supported_speeds)
+ pci_info(pdev, "fixed up supported link speeds: 0x%x => 0x%x",
+ old_supported_speeds, pdev->supported_speeds);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON, 0x3c19, loongson_pci_bridge_speed_quirk);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON, 0x3c29, loongson_pci_bridge_speed_quirk);
+
static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus)
{
struct pci_config_window *cfg;
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
index 3dbb7adc421c..76f3823d9613 100644
--- a/drivers/pci/controller/pcie-altera.c
+++ b/drivers/pci/controller/pcie-altera.c
@@ -864,11 +864,25 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
return 0;
}
+static void altera_pcie_disable_irq(struct altera_pcie *pcie)
+{
+ if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
+ pcie->pcie_data->version == ALTERA_PCIE_V2) {
+ /* Disable all P2A interrupts */
+ cra_writel(pcie, 0, P2A_INT_ENABLE);
+ } else if (pcie->pcie_data->version == ALTERA_PCIE_V3) {
+ /* Disable port-level interrupts (CFG_AER, etc.) */
+ writel(0, pcie->hip_base +
+ pcie->pcie_data->port_conf_offset +
+ pcie->pcie_data->port_irq_enable_offset);
+ }
+}
+
static void altera_pcie_irq_teardown(struct altera_pcie *pcie)
{
+ altera_pcie_disable_irq(pcie);
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
irq_domain_remove(pcie->irq_domain);
- irq_dispose_mapping(pcie->irq);
}
static int altera_pcie_parse_dt(struct altera_pcie *pcie)
@@ -891,7 +905,6 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
if (pcie->irq < 0)
return pcie->irq;
- irq_set_chained_handler_and_data(pcie->irq, pcie->pcie_data->ops->rp_isr, pcie);
return 0;
}
@@ -1020,6 +1033,14 @@ static int altera_pcie_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * The chained handler uses pcie->irq_domain, so set it only after the
+ * INTx domain has been created.
+ */
+ irq_set_chained_handler_and_data(pcie->irq,
+ pcie->pcie_data->ops->rp_isr,
+ pcie);
+
if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
pcie->pcie_data->version == ALTERA_PCIE_V2) {
/* clear all interrupts */
@@ -1037,7 +1058,16 @@ static int altera_pcie_probe(struct platform_device *pdev)
bridge->busnr = pcie->root_bus_nr;
bridge->ops = &altera_pcie_ops;
- return pci_host_probe(bridge);
+ ret = pci_host_probe(bridge);
+ if (ret)
+ goto err_teardown_irq;
+
+ return 0;
+
+err_teardown_irq:
+ altera_pcie_irq_teardown(pcie);
+
+ return ret;
}
static void altera_pcie_remove(struct platform_device *pdev)
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 75722524fe74..907ae4285ecb 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -529,23 +529,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
}
-static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+static void mtk_pcie_irq_teardown_port(struct mtk_pcie_port *port)
{
- struct mtk_pcie_port *port, *tmp;
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
- irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+ if (port->irq_domain)
+ irq_domain_remove(port->irq_domain);
- if (port->irq_domain)
- irq_domain_remove(port->irq_domain);
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ if (port->inner_domain)
+ irq_domain_remove(port->inner_domain);
+ }
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- if (port->inner_domain)
- irq_domain_remove(port->inner_domain);
- }
+ irq_dispose_mapping(port->irq);
+}
- irq_dispose_mapping(port->irq);
- }
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+ struct mtk_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_irq_teardown_port(port);
}
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -865,7 +869,7 @@ static int mtk_pcie_startup_port_an7583(struct mtk_pcie_port *port)
return mtk_pcie_startup_port_v2(port);
}
-static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
+static int mtk_pcie_enable_port(struct mtk_pcie_port *port)
{
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
@@ -874,7 +878,7 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
err = clk_prepare_enable(port->sys_ck);
if (err) {
dev_err(dev, "failed to enable sys_ck%d clock\n", port->slot);
- goto err_sys_clk;
+ return err;
}
err = clk_prepare_enable(port->ahb_ck);
@@ -922,11 +926,15 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
goto err_phy_on;
}
- if (!pcie->soc->startup(port))
- return;
+ err = pcie->soc->startup(port);
+ if (err) {
+ dev_info(dev, "Port%d link down\n", port->slot);
+ goto err_soc_startup;
+ }
- dev_info(dev, "Port%d link down\n", port->slot);
+ return 0;
+err_soc_startup:
phy_power_off(port->phy);
err_phy_on:
phy_exit(port->phy);
@@ -942,8 +950,8 @@ err_aux_clk:
clk_disable_unprepare(port->ahb_ck);
err_ahb_clk:
clk_disable_unprepare(port->sys_ck);
-err_sys_clk:
- mtk_pcie_port_free(port);
+
+ return err;
}
static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
@@ -1109,8 +1117,13 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return err;
/* enable each port, and then check link status */
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err) {
+ mtk_pcie_irq_teardown_port(port);
+ mtk_pcie_port_free(port);
+ }
+ }
/* power down PCIe subsys if slots are all empty (link down) */
if (list_empty(&pcie->ports))
@@ -1209,14 +1222,18 @@ static int mtk_pcie_resume_noirq(struct device *dev)
{
struct mtk_pcie *pcie = dev_get_drvdata(dev);
struct mtk_pcie_port *port, *tmp;
+ int err;
if (list_empty(&pcie->ports))
return 0;
clk_prepare_enable(pcie->free_ck);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err)
+ mtk_pcie_port_free(port);
+ }
/* In case of EP was removed while system suspend. */
if (list_empty(&pcie->ports))
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 91ac4e37ecb9..08df9bace13d 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -938,12 +938,18 @@ static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
return;
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);
for (i = 0; i < nbars; i++, pos += 8) {
int bar_idx, size;
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index caaed1a01dc0..dd0025d3914e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -80,11 +80,10 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta)
* Restrict the speed to 2.5GT/s then with the Target Link Speed field,
* request a retrain and check the result.
*
- * If this turns out successful and we know by the Vendor:Device ID it is
- * safe to do so, then lift the restriction, letting the devices negotiate
- * a higher speed. Also check for a similar 2.5GT/s speed restriction the
- * firmware may have already arranged and lift it with ports that already
- * report their data link being up.
+ * If this turns out successful, or where a 2.5GT/s speed restriction has
+ * been previously arranged by the firmware and the port reports its link
+ * already being up, lift the restriction, in a hope it is safe to do so,
+ * letting the devices negotiate a higher speed.
*
* Otherwise revert the speed to the original setting and request a retrain
* again to remove any residual state, ignoring the result as it's supposed
@@ -95,52 +94,38 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta)
*/
int pcie_failed_link_retrain(struct pci_dev *dev)
{
- static const struct pci_device_id ids[] = {
- { PCI_VDEVICE(ASMEDIA, 0x2824) }, /* ASMedia ASM2824 */
- {}
- };
- u16 lnksta, lnkctl2;
+ u16 lnksta, lnkctl2, oldlnkctl2;
int ret = -ENOTTY;
+ u32 lnkcap;
if (!pci_is_pcie(dev) || !pcie_downstream_port(dev) ||
!pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting)
return ret;
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+ pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2);
if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) {
- u16 oldlnkctl2;
-
pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
-
- pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2);
ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false);
- if (ret) {
- pci_info(dev, "retraining failed\n");
- pcie_set_target_speed(dev, PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2),
- true);
- return ret;
- }
-
- pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+ if (ret)
+ goto err;
}
pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2);
-
- if ((lnksta & PCI_EXP_LNKSTA_DLLLA) &&
- (lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
- pci_match_id(ids, dev)) {
- u32 lnkcap;
-
+ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
+ (lnkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n");
- pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
ret = pcie_set_target_speed(dev, PCIE_LNKCAP_SLS2SPEED(lnkcap), false);
- if (ret) {
- pci_info(dev, "retraining failed\n");
- return ret;
- }
+ if (ret)
+ goto err;
}
return ret;
+err:
+ pci_info(dev, "retraining failed\n");
+ pcie_set_target_speed(dev, PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2), true);
+ return ret;
}
static ktime_t fixup_debug_start(struct pci_dev *dev,
diff --git a/drivers/pci/rebar.c b/drivers/pci/rebar.c
index 39f8cf3b70d5..11965947c4cb 100644
--- a/drivers/pci/rebar.c
+++ b/drivers/pci/rebar.c
@@ -231,6 +231,9 @@ void pci_restore_rebar_state(struct pci_dev *pdev)
return;
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);
for (i = 0; i < nbars; i++, pos += 8) {
@@ -238,6 +241,9 @@ void pci_restore_rebar_state(struct pci_dev *pdev)
int bar_idx, size;
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
res = pci_resource_n(pdev, bar_idx);
size = pci_rebar_bytes_to_size(resource_size(res));
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index f5305c8fdca4..6e5cc4086a9e 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -197,13 +197,14 @@
enum cmn_model {
CMN600 = 1,
CMN650 = 2,
- CMN700 = 4,
- CI700 = 8,
+ CI700 = 4,
+ CMN700 = 8,
CMNS3 = 16,
/* ...and then we can use bitmap tricks for commonality */
CMN_ANY = -1,
NOT_CMN600 = -2,
- CMN_650ON = CMN650 | CMN700 | CMNS3,
+ CMN_700ON = ~(CMN700 - 1),
+ CMN_650ON = CMN_700ON | CMN650,
};
/* Actual part numbers and revision IDs defined by the hardware */
@@ -919,14 +920,14 @@ static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_DVM(NOT_CMN600, txsnp_stall, 0x0a),
CMN_EVENT_DVM(NOT_CMN600, trkfull, 0x0b),
CMN_EVENT_DVM_OCC(NOT_CMN600, trk_occupancy, 0x0c),
- CMN_EVENT_DVM_OCC(CMN700, trk_occupancy_cxha, 0x0d),
- CMN_EVENT_DVM_OCC(CMN700, trk_occupancy_pdn, 0x0e),
- CMN_EVENT_DVM(CMN700, trk_alloc, 0x0f),
- CMN_EVENT_DVM(CMN700, trk_cxha_alloc, 0x10),
- CMN_EVENT_DVM(CMN700, trk_pdn_alloc, 0x11),
- CMN_EVENT_DVM(CMN700, txsnp_stall_limit, 0x12),
- CMN_EVENT_DVM(CMN700, rxsnp_stall_starv, 0x13),
- CMN_EVENT_DVM(CMN700, txsnp_sync_stall_op, 0x14),
+ CMN_EVENT_DVM_OCC(CMN_700ON, trk_occupancy_cxha, 0x0d),
+ CMN_EVENT_DVM_OCC(CMN_700ON, trk_occupancy_pdn, 0x0e),
+ CMN_EVENT_DVM(CMN_700ON, trk_alloc, 0x0f),
+ CMN_EVENT_DVM(CMN_700ON, trk_cxha_alloc, 0x10),
+ CMN_EVENT_DVM(CMN_700ON, trk_pdn_alloc, 0x11),
+ CMN_EVENT_DVM(CMN_700ON, txsnp_stall_limit, 0x12),
+ CMN_EVENT_DVM(CMN_700ON, rxsnp_stall_starv, 0x13),
+ CMN_EVENT_DVM(CMN_700ON, txsnp_sync_stall_op, 0x14),
CMN_EVENT_HNF(CMN_ANY, cache_miss, 0x01),
CMN_EVENT_HNF(CMN_ANY, slc_sf_cache_access, 0x02),
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 085093506dda..6b4bac5f7051 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -7,11 +7,13 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/string_choices.h>
#include <linux/suspend.h>
@@ -230,6 +232,7 @@ static const struct dmi_system_id dmi_auto_add_switch[] = {
};
struct intel_hid_priv {
+ struct mutex mutex; /* Avoid notify_handler() racing with itself */
struct input_dev *input_dev;
struct input_dev *array;
struct input_dev *switches;
@@ -565,6 +568,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
struct key_entry *ke;
int err;
+ guard(mutex)(&priv->mutex);
+
/*
* Some convertible have unreliable VGBS return which could cause incorrect
* SW_TABLET_MODE report, in these cases we enable support when receiving
@@ -720,6 +725,10 @@ static int intel_hid_probe(struct platform_device *device)
return -ENOMEM;
dev_set_drvdata(&device->dev, priv);
+ err = devm_mutex_init(&device->dev, &priv->mutex);
+ if (err)
+ return err;
+
/* See dual_accel_detect.h for more info on the dual_accel check. */
if (enable_sw_tablet_mode == TABLET_SW_AUTO) {
if (dmi_check_system(dmi_vgbs_allow_list))
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
index 6d609c42e479..c005e65ba0ec 100644
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -345,8 +345,10 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
for_each_child_of_node_scoped(np, child) {
ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
/* abort on any mem issue */
- if (ret == -ENOMEM)
+ if (ret == -ENOMEM) {
+ of_node_put(np);
return ret;
+ }
}
of_node_put(np);
/*
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index e201309f8aae..e14753144e19 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -647,7 +647,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
tx->sgl, tx->nents, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
- dmaengine_terminate_all(controller->dma_tx);
+ dmaengine_terminate_sync(controller->dma_rx);
return -EINVAL;
}
@@ -668,8 +668,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
transfer_timeout);
if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n");
- dmaengine_terminate_all(controller->dma_tx);
- dmaengine_terminate_all(controller->dma_rx);
+ dmaengine_terminate_sync(controller->dma_tx);
+ dmaengine_terminate_sync(controller->dma_rx);
fsl_lpspi_reset(fsl_lpspi);
return -ETIMEDOUT;
}
@@ -678,8 +678,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
transfer_timeout);
if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n");
- dmaengine_terminate_all(controller->dma_tx);
- dmaengine_terminate_all(controller->dma_rx);
+ dmaengine_terminate_sync(controller->dma_tx);
+ dmaengine_terminate_sync(controller->dma_rx);
fsl_lpspi_reset(fsl_lpspi);
return -ETIMEDOUT;
}
@@ -688,8 +688,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA TX interrupted\n");
- dmaengine_terminate_all(controller->dma_tx);
- dmaengine_terminate_all(controller->dma_rx);
+ dmaengine_terminate_sync(controller->dma_tx);
+ dmaengine_terminate_sync(controller->dma_rx);
fsl_lpspi_reset(fsl_lpspi);
return -EINTR;
}
@@ -698,8 +698,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA RX interrupted\n");
- dmaengine_terminate_all(controller->dma_tx);
- dmaengine_terminate_all(controller->dma_rx);
+ dmaengine_terminate_sync(controller->dma_tx);
+ dmaengine_terminate_sync(controller->dma_rx);
fsl_lpspi_reset(fsl_lpspi);
return -EINTR;
}
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index 6cda5925fa45..584751516b69 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -5020,7 +5020,6 @@ static int load_primary_binaries(
struct ia_css_capture_settings *mycs;
unsigned int i;
bool need_extra_yuv_scaler = false;
- struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES];
IA_CSS_ENTER_PRIVATE("");
assert(pipe);
@@ -5189,15 +5188,16 @@ static int load_primary_binaries(
/* Primary */
for (i = 0; i < mycs->num_primary_stage; i++) {
+ struct ia_css_binary_descr prim_descr;
struct ia_css_frame_info *local_vf_info = NULL;
if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
(i == mycs->num_primary_stage - 1))
local_vf_info = &vf_info;
- ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
+ ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr,
&prim_in_info, &prim_out_info,
local_vf_info, i);
- err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
+ err = ia_css_binary_find(&prim_descr, &mycs->primary_binary[i]);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c
index 2c48d57a3180..92cce31e35c5 100644
--- a/drivers/staging/media/ipu3/ipu3-css-params.c
+++ b/drivers/staging/media/ipu3/ipu3-css-params.c
@@ -1770,6 +1770,8 @@ static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe,
acc->stripe.bds_out_stripes[0].width =
ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
} else {
+ u32 offset;
+
/* Image processing is divided into two stripes */
acc->stripe.bds_out_stripes[0].width =
acc->stripe.bds_out_stripes[1].width =
@@ -1788,8 +1790,10 @@ static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe,
acc->stripe.bds_out_stripes[1].width += f;
}
/* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
- acc->stripe.bds_out_stripes[1].offset =
- acc->stripe.bds_out_stripes[0].width - 2 * f;
+ offset = acc->stripe.bds_out_stripes[0].width - 2 * f;
+ if (offset > 65535)
+ return -EINVAL;
+ acc->stripe.bds_out_stripes[1].offset = offset;
}
acc->stripe.effective_stripes[0].height =
diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c
index c771e763f8c5..310e3f24e571 100644
--- a/drivers/staging/media/ipu7/ipu7.c
+++ b/drivers/staging/media/ipu7/ipu7.c
@@ -2169,21 +2169,18 @@ ipu7_isys_init(struct pci_dev *pdev, struct device *parent,
isys_adev->mmu = ipu7_mmu_init(dev, base, ISYS_MMID,
&ipdata->hw_variant);
if (IS_ERR(isys_adev->mmu)) {
- dev_err_probe(dev, PTR_ERR(isys_adev->mmu),
- "ipu7_mmu_init(isys_adev->mmu) failed\n");
+ ret = dev_err_probe(dev, PTR_ERR(isys_adev->mmu),
+ "ipu7_mmu_init(isys_adev->mmu) failed\n");
put_device(&isys_adev->auxdev.dev);
- kfree(pdata);
- return ERR_CAST(isys_adev->mmu);
+ return ERR_PTR(ret);
}
isys_adev->mmu->dev = &isys_adev->auxdev.dev;
isys_adev->subsys = IPU_IS;
ret = ipu7_bus_add_device(isys_adev);
- if (ret) {
- kfree(pdata);
+ if (ret)
return ERR_PTR(ret);
- }
return isys_adev;
}
@@ -2216,21 +2213,18 @@ ipu7_psys_init(struct pci_dev *pdev, struct device *parent,
psys_adev->mmu = ipu7_mmu_init(&pdev->dev, base, PSYS_MMID,
&ipdata->hw_variant);
if (IS_ERR(psys_adev->mmu)) {
- dev_err_probe(&pdev->dev, PTR_ERR(psys_adev->mmu),
- "ipu7_mmu_init(psys_adev->mmu) failed\n");
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(psys_adev->mmu),
+ "ipu7_mmu_init(psys_adev->mmu) failed\n");
put_device(&psys_adev->auxdev.dev);
- kfree(pdata);
- return ERR_CAST(psys_adev->mmu);
+ return ERR_PTR(ret);
}
psys_adev->mmu->dev = &psys_adev->auxdev.dev;
psys_adev->subsys = IPU_PS;
ret = ipu7_bus_add_device(psys_adev);
- if (ret) {
- kfree(pdata);
+ if (ret)
return ERR_PTR(ret);
- }
return psys_adev;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index 72b7f731dd47..3c1f0068cd92 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -583,9 +583,14 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len)
cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
while (cnt < in_len) {
+ if (cnt + 2 > in_len)
+ break;
+ if (cnt + 2 + in_ie[cnt + 1] > in_len)
+ break;
authmode = in_ie[cnt];
if (authmode == WLAN_EID_BSS_AC_ACCESS_DELAY &&
+ in_ie[cnt + 1] >= 8 &&
(!memcmp(&in_ie[cnt + 6], wapi_oui1, 4) ||
!memcmp(&in_ie[cnt + 6], wapi_oui2, 4))) {
if (wapi_ie)
@@ -616,9 +621,14 @@ void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie
cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
while (cnt < in_len) {
+ if (cnt + 2 > in_len)
+ break;
+ if (cnt + 2 + in_ie[cnt + 1] > in_len)
+ break;
authmode = in_ie[cnt];
if ((authmode == WLAN_EID_VENDOR_SPECIFIC) &&
+ in_ie[cnt + 1] >= 4 &&
(!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
if (wpa_ie)
memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
@@ -699,6 +709,9 @@ u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_att
if (len_attr)
*len_attr = 0;
+ if (wps_ielen < 6)
+ return attr_ptr;
+
if ((wps_ie[0] != WLAN_EID_VENDOR_SPECIFIC) ||
(memcmp(wps_ie + 2, wps_oui, 4))) {
return attr_ptr;
@@ -709,6 +722,8 @@ u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_att
while (attr_ptr - wps_ie < wps_ielen) {
/* 4 = 2(Attribute ID) + 2(Length) */
+ if (attr_ptr + 4 > wps_ie + wps_ielen)
+ break;
u16 attr_id = get_unaligned_be16(attr_ptr);
u16 attr_data_len = get_unaligned_be16(attr_ptr + 2);
u16 attr_len = attr_data_len + 4;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 5f00fe282d1b..e78450402d19 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -687,6 +687,9 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
return _FAIL;
+ if (len < WLAN_HDR_A3_LEN)
+ return _FAIL;
+
sa = GetAddr2Ptr(pframe);
auth_mode = psecuritypriv->dot11AuthAlgrthm;
@@ -698,6 +701,9 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
prxattrib->hdrlen = WLAN_HDR_A3_LEN;
prxattrib->encrypt = _WEP40_;
+ if (len < WLAN_HDR_A3_LEN + 8)
+ return _FAIL;
+
iv = pframe+prxattrib->hdrlen;
prxattrib->key_index = ((iv[3]>>6)&0x3);
@@ -802,7 +808,7 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_, WLAN_EID_CHALLENGE, (int *)&ie_len,
len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4);
- if (!p || ie_len <= 0) {
+ if (!p || ie_len != 128) {
status = WLAN_STATUS_CHALLENGE_FAIL;
goto auth_fail;
}
@@ -1400,7 +1406,11 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
/* to handle HT, WMM, rate adaptive, update MAC reg */
/* for not to handle the synchronous IO in the tasklet */
for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) {
+ if (i + sizeof(*pIE) > pkt_len)
+ break;
pIE = (struct ndis_80211_var_ie *)(pframe + i);
+ if (i + sizeof(*pIE) + pIE->length > pkt_len)
+ break;
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
@@ -2925,7 +2935,11 @@ void issue_assocreq(struct adapter *padapter)
/* vendor specific IE, such as WPA, WMM, WPS */
for (i = sizeof(struct ndis_802_11_fix_ie); i < pmlmeinfo->network.ie_length;) {
+ if (i + sizeof(*pIE) > pmlmeinfo->network.ie_length)
+ break;
pIE = (struct ndis_80211_var_ie *)(pmlmeinfo->network.ies + i);
+ if (i + sizeof(*pIE) + pIE->length > pmlmeinfo->network.ie_length)
+ break;
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
@@ -5318,7 +5332,11 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
/* sizeof(struct ndis_802_11_fix_ie) */
for (i = _FIXED_IE_LENGTH_; i < pnetwork->ie_length;) {
+ if (i + sizeof(*pIE) > pnetwork->ie_length)
+ break;
pIE = (struct ndis_80211_var_ie *)(pnetwork->ies + i);
+ if (i + sizeof(*pIE) + pIE->length > pnetwork->ie_length)
+ break;
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:/* Get WMM IE. */
diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
index 6a7c09db4cd9..94bbe7ac13ac 100644
--- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
@@ -936,7 +936,8 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE)
pmlmeinfo->HT_caps_enable = 1;
- for (i = 0; i < (pIE->length); i++) {
+ for (i = 0; i < umin(pIE->length,
+ sizeof(pmlmeinfo->HT_caps.u.HT_cap)); i++) {
if (i != 2) {
/* Commented by Albert 2010/07/12 */
/* Got the endian issue here. */
@@ -1289,7 +1290,11 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN);
for (i = 0; i < len;) {
+ if (i + sizeof(*pIE) > len)
+ break;
pIE = (struct ndis_80211_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i);
+ if (i + sizeof(*pIE) + pIE->length > len)
+ break;
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
@@ -1314,7 +1319,7 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
break;
}
- i += (pIE->length + 2);
+ i += sizeof(*pIE) + pIE->length;
}
}
@@ -1330,15 +1335,23 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
for (i = sizeof(struct ndis_802_11_fix_ie); i < pmlmeinfo->network.ie_length;) {
pIE = (struct ndis_80211_var_ie *)(pmlmeinfo->network.ies + i);
+ if (i + sizeof(*pIE) > pmlmeinfo->network.ie_length)
+ break;
+ if (i + sizeof(*pIE) + pIE->length > pmlmeinfo->network.ie_length)
+ break;
+
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
- if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4)))
+ if (pIE->length >= 16 &&
+ !memcmp(pIE->data, RTW_WPA_OUI, 4) &&
+ !memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))
return true;
break;
case WLAN_EID_RSN:
- if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
+ if (pIE->length >= 12 &&
+ !memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
return true;
break;
@@ -1346,7 +1359,7 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
break;
}
- i += (pIE->length + 2);
+ i += sizeof(*pIE) + pIE->length;
}
return false;
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index fd3bae31b0ed..e7ba5ccfa03c 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -1445,6 +1445,10 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
pwpa = rtw_get_wpa_ie(buf, &wpa_ielen, ielen);
if (pwpa && wpa_ielen > 0) {
+ if (wpa_ielen + 2 > sizeof(padapter->securitypriv.supplicant_ie)) {
+ ret = -EINVAL;
+ goto exit;
+ }
if (rtw_parse_wpa_ie(pwpa, wpa_ielen + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
@@ -1454,6 +1458,10 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen);
if (pwpa2 && wpa2_ielen > 0) {
+ if (wpa2_ielen + 2 > sizeof(padapter->securitypriv.supplicant_ie)) {
+ ret = -EINVAL;
+ goto exit;
+ }
if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
index dc0b77f38b1a..9bdb67a8a408 100644
--- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
@@ -24,9 +24,11 @@ void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
int _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, unsigned int rlen)
{
int ret;
+ unsigned int remain = rtw_remainder_len(pfile);
- if (rtw_remainder_len(pfile) < rlen)
- return -EINVAL;
+ /* clamp to bytes remaining; the coalesce loop relies on short reads */
+ if (rlen > remain)
+ rlen = remain;
if (rmem) {
ret = skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, rlen);
diff --git a/drivers/staging/vme_user/vme_fake.c b/drivers/staging/vme_user/vme_fake.c
index 8abaa3165fbb..434cf760ade6 100644
--- a/drivers/staging/vme_user/vme_fake.c
+++ b/drivers/staging/vme_user/vme_fake.c
@@ -1239,6 +1239,7 @@ static void __exit fake_exit(void)
{
struct list_head *pos = NULL;
struct list_head *tmplist;
+ struct vme_lm_resource *lm;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
int i;
@@ -1269,6 +1270,13 @@ static void __exit fake_exit(void)
fake_crcsr_exit(fake_bridge);
/* resources are stored in link list */
+ list_for_each_safe(pos, tmplist, &fake_bridge->lm_resources) {
+ lm = list_entry(pos, struct vme_lm_resource, list);
+ list_del(pos);
+ kfree(lm);
+ }
+
+ /* resources are stored in link list */
list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) {
slave_image = list_entry(pos, struct vme_slave_resource, list);
list_del(pos);
diff --git a/drivers/staging/vme_user/vme_tsi148.c b/drivers/staging/vme_user/vme_tsi148.c
index 4cf3486646ce..c695ad9b4ca2 100644
--- a/drivers/staging/vme_user/vme_tsi148.c
+++ b/drivers/staging/vme_user/vme_tsi148.c
@@ -2534,6 +2534,7 @@ static void tsi148_remove(struct pci_dev *pdev)
{
struct list_head *pos = NULL;
struct list_head *tmplist;
+ struct vme_lm_resource *lm;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
@@ -2591,6 +2592,13 @@ static void tsi148_remove(struct pci_dev *pdev)
tsi148_crcsr_exit(tsi148_bridge, pdev);
/* resources are stored in link list */
+ list_for_each_safe(pos, tmplist, &tsi148_bridge->lm_resources) {
+ lm = list_entry(pos, struct vme_lm_resource, list);
+ list_del(pos);
+ kfree(lm);
+ }
+
+ /* resources are stored in link list */
list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
list_del(pos);
diff --git a/drivers/staging/vme_user/vme_user.c b/drivers/staging/vme_user/vme_user.c
index 11e25c2f6b0a..a472a38ef613 100644
--- a/drivers/staging/vme_user/vme_user.c
+++ b/drivers/staging/vme_user/vme_user.c
@@ -156,6 +156,17 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf,
{
void *image_ptr;
+ /*
+ * The slave window (image_size) can exceed the fixed kern_buf
+ * (size_buf == PCI_BUF_SIZE), so bound the copy to kern_buf.
+ * *ppos is >= 0 here (checked by the caller), so the
+ * subtraction below cannot wrap.
+ */
+ if (*ppos >= image[minor].size_buf)
+ return 0;
+ if (count > image[minor].size_buf - *ppos)
+ count = image[minor].size_buf - *ppos;
+
image_ptr = image[minor].kern_buf + *ppos;
if (copy_to_user(buf, image_ptr, (unsigned long)count))
return -EFAULT;
@@ -168,6 +179,17 @@ static ssize_t buffer_from_user(unsigned int minor, const char __user *buf,
{
void *image_ptr;
+ /*
+ * The slave window (image_size) can exceed the fixed kern_buf
+ * (size_buf == PCI_BUF_SIZE), so bound the copy to kern_buf.
+ * *ppos is >= 0 here (checked by the caller), so the
+ * subtraction below cannot wrap.
+ */
+ if (*ppos >= image[minor].size_buf)
+ return 0;
+ if (count > image[minor].size_buf - *ppos)
+ count = image[minor].size_buf - *ppos;
+
image_ptr = image[minor].kern_buf + *ppos;
if (copy_from_user(image_ptr, buf, (unsigned long)count))
return -EFAULT;
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 8ec03863606e..f88809ff370b 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
+#include <linux/util_macros.h>
#include <linux/dma/hsu.h>
@@ -368,8 +369,16 @@ static const struct mid8250_board dnv_board = {
.freq = 133333333,
.base_baud = 115200,
.bar = 1,
- .setup = dnv_setup,
- .exit = dnv_exit,
+ /*
+ * Errata:
+ * HSUART May Stop Functioning when DMA is Active.
+ *
+ * - Denverton document #572409, rev 3.4, DNV60
+ * - Ice Lake Xeon D document #714070, ICXD65
+ * - Snowridge document #731931, SNR44
+ */
+ .setup = PTR_IF(false, dnv_setup),
+ .exit = PTR_IF(false, dnv_exit),
};
static const struct pci_device_id pci_ids[] = {
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index dfdea0842149..763a3f1b7be0 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -765,16 +765,22 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
/*
* Compute xterm-style modifier parameter for CSI sequences.
* Returns 1 + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0)
+ *
+ * Only the canonical modifier weights are counted. The left/right variants
+ * (KG_SHIFTL, KG_SHIFTR, KG_CTRLL, KG_CTRLR) and KG_ALTGR are commonly
+ * repurposed as keymap layout-group or level selectors rather than as plain
+ * modifiers (for instance XKB-derived keymaps select the layout group with
+ * KG_SHIFTL/KG_SHIFTR), so counting them would encode a spurious modifier.
*/
static int csi_modifier_param(void)
{
int mod = 1;
- if (shift_state & (BIT(KG_SHIFT) | BIT(KG_SHIFTL) | BIT(KG_SHIFTR)))
+ if (shift_state & BIT(KG_SHIFT))
mod += 1;
- if (shift_state & (BIT(KG_ALT) | BIT(KG_ALTGR)))
+ if (shift_state & BIT(KG_ALT))
mod += 2;
- if (shift_state & (BIT(KG_CTRL) | BIT(KG_CTRLL) | BIT(KG_CTRLR)))
+ if (shift_state & BIT(KG_CTRL))
mod += 4;
return mod;
}
diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
index a2a1b21f2ef8..880097f1007d 100644
--- a/drivers/usb/cdns3/cdnsp-mem.c
+++ b/drivers/usb/cdns3/cdnsp-mem.c
@@ -631,6 +631,8 @@ cleanup_rings:
}
}
+ cdnsp_free_stream_ctx(pdev, pep);
+
cleanup_stream_rings:
kfree(pep->stream_info.stream_rings);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ddf0b5963859..3cb372721282 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1810,6 +1810,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */
.driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */
},
+ { USB_DEVICE(0x1965, 0x0017), /* Uniden BC125AT */
+ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+ },
{ USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index 9b69148128e5..7e43429e996e 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -281,28 +281,24 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
ulpi->dev.parent = dev; /* needed early for ops */
ulpi->dev.bus = &ulpi_bus;
ulpi->dev.type = &ulpi_dev_type;
+
+ device_initialize(&ulpi->dev);
+
dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
ret = ulpi_of_register(ulpi);
- if (ret) {
- kfree(ulpi);
+ if (ret)
return ret;
- }
ret = ulpi_read_id(ulpi);
- if (ret) {
- of_node_put(ulpi->dev.of_node);
- kfree(ulpi);
+ if (ret)
return ret;
- }
- ret = device_register(&ulpi->dev);
- if (ret) {
- put_device(&ulpi->dev);
+ ret = device_add(&ulpi->dev);
+ if (ret)
return ret;
- }
root = debugfs_create_dir(dev_name(&ulpi->dev), ulpi_root);
debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops);
@@ -334,9 +330,10 @@ struct ulpi *ulpi_register_interface(struct device *dev,
ulpi->ops = ops;
ret = ulpi_register(dev, ulpi);
- if (ret)
+ if (ret) {
+ put_device(&ulpi->dev);
return ERR_PTR(ret);
-
+ }
return ulpi;
}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 87810eff974e..87ee2d938bc0 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -296,6 +296,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* CarrolTouch 4500U */
{ USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Samsung T5 EVO Portable SSD */
+ { USB_DEVICE(0x04e8, 0x6200), .driver_info = USB_QUIRK_NO_LPM },
+
/* Samsung Android phone modem - ID conflict with SPH-I500 */
{ USB_DEVICE(0x04e8, 0x6601), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -576,6 +579,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* VLI disk */
{ USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM },
+ /* VIA Labs, Inc. USB2.0 Hub */
+ { USB_DEVICE(0x2109, 0x2817), .driver_info = USB_QUIRK_NO_LPM },
+
/* Raydium Touchscreen */
{ USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 65213896de99..6f3c00b08937 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -793,9 +793,9 @@ static void dwc3_ulpi_setup(struct dwc3 *dwc)
if (dwc->enable_usb2_transceiver_delay) {
for (index = 0; index < dwc->num_usb2_ports; index++) {
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
+ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
reg |= DWC3_GUSB2PHYCFG_XCVRDLY;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
+ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
}
}
}
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index 55e144ba8cfc..4d611c08e8a4 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -907,35 +907,39 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
ret = priv->drvdata->usb_init(priv);
if (ret)
- return ret;
+ goto err_rearm;
/* Init PHYs */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_init(priv->phys[i]);
if (ret)
- return ret;
+ goto err_rearm;
}
/* Set PHY Power */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_power_on(priv->phys[i]);
if (ret)
- return ret;
+ goto err_rearm;
}
if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
ret = regulator_enable(priv->vbus);
if (ret)
- return ret;
+ goto err_rearm;
}
if (priv->drvdata->usb_post_init) {
ret = priv->drvdata->usb_post_init(priv);
if (ret)
- return ret;
+ goto err_rearm;
}
return 0;
+
+err_rearm:
+ reset_control_rearm(priv->reset);
+ return ret;
}
static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3d4ca68e584c..1082e9c9afaa 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -3934,15 +3934,48 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
}
}
+static bool dwc3_prepare_disconnect_gadget(struct dwc3 *dwc,
+ struct usb_gadget_driver **driver,
+ struct usb_gadget **gadget)
+{
+ if (!dwc->async_callbacks || !dwc->gadget_driver ||
+ !dwc->gadget_driver->disconnect)
+ return false;
+
+ *driver = dwc->gadget_driver;
+ *gadget = dwc->gadget;
+
+ return true;
+}
+
static void dwc3_disconnect_gadget(struct dwc3 *dwc)
{
- if (dwc->async_callbacks && dwc->gadget_driver->disconnect) {
+ struct usb_gadget_driver *driver;
+ struct usb_gadget *gadget;
+
+ if (dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
spin_unlock(&dwc->lock);
- dwc->gadget_driver->disconnect(dwc->gadget);
+ driver->disconnect(gadget);
spin_lock(&dwc->lock);
}
}
+static void dwc3_disconnect_gadget_sleepable(struct dwc3 *dwc)
+{
+ struct usb_gadget_driver *driver;
+ struct usb_gadget *gadget;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ driver->disconnect(gadget);
+}
+
static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->suspend) {
@@ -4838,7 +4871,6 @@ EXPORT_SYMBOL_GPL(dwc3_gadget_exit);
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
- unsigned long flags;
int ret;
ret = dwc3_gadget_soft_disconnect(dwc);
@@ -4852,10 +4884,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
return -EAGAIN;
}
- spin_lock_irqsave(&dwc->lock, flags);
- if (dwc->gadget_driver)
- dwc3_disconnect_gadget(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_disconnect_gadget_sleepable(dwc);
return 0;
}
diff --git a/drivers/usb/fotg210/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c
index 1a48329a4e08..956be5b56510 100644
--- a/drivers/usb/fotg210/fotg210-hcd.c
+++ b/drivers/usb/fotg210/fotg210-hcd.c
@@ -4267,8 +4267,6 @@ static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
return 0;
fail:
- iso_sched_free(stream, sched);
- urb->hcpriv = NULL;
return status;
}
@@ -4562,6 +4560,10 @@ static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
else
usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&fotg210->lock, flags);
done:
return status;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index dc3664374596..df39e3487c1f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1863,9 +1863,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (cdev->config)
config = cdev->config;
else
- config = list_first_entry(
+ config = list_first_entry_or_null(
&cdev->configs,
- struct usb_configuration, list);
+ struct usb_configuration,
+ list);
if (!config)
goto done;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 75912ce6ab55..44218be1e676 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -288,6 +288,7 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
+static void ffs_reset_work(struct work_struct *work);
/* Misc helper functions ****************************************************/
@@ -1374,7 +1375,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
mutex_unlock(&epfile->dmabufs_mutex);
- __ffs_epfile_read_buffer_free(epfile);
ffs_data_closed(epfile->ffs);
return 0;
@@ -1704,6 +1704,7 @@ static int ffs_dmabuf_transfer(struct file *file,
resv_dir = epfile->in ? DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE;
dma_resv_add_fence(dmabuf->resv, &fence->base, resv_dir);
+ dma_fence_put(&fence->base);
dma_resv_unlock(dmabuf->resv);
/* Now that the dma_fence is in place, queue the transfer. */
@@ -2221,6 +2222,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
init_waitqueue_head(&ffs->ev.waitq);
init_waitqueue_head(&ffs->wait);
init_completion(&ffs->ep0req_completion);
+ INIT_WORK(&ffs->reset_work, ffs_reset_work);
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;
@@ -2364,6 +2366,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfile->name, "ep%u", i);
+ epfile->in = (ffs->eps_addrmap[i] & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
err = ffs_sb_create_file(ffs->sb, epfile->name,
epfile, &ffs_epfile_operations);
if (err) {
@@ -2389,6 +2392,7 @@ static void ffs_epfiles_destroy(struct super_block *sb,
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
+ __ffs_epfile_read_buffer_free(epfile);
simple_remove_by_name(root, epfile->name, clear_one);
}
@@ -2453,7 +2457,6 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ret = usb_ep_enable(ep->ep);
if (!ret) {
epfile->ep = ep;
- epfile->in = usb_endpoint_dir_in(ep->ep->desc);
epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
} else {
break;
@@ -3775,7 +3778,6 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
spin_unlock_irqrestore(&ffs->eps_lock, flags);
- INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
@@ -3806,7 +3808,6 @@ static void ffs_func_disable(struct usb_function *f)
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
spin_unlock_irqrestore(&ffs->eps_lock, flags);
- INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return;
}
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index e4f7828ae75d..837f753d0cae 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -363,12 +363,11 @@ printer_open(struct inode *inode, struct file *fd)
ret = 0;
/* Change the printer status to show that it's on-line. */
dev->printer_status |= PRINTER_SELECTED;
+ kref_get(&dev->kref);
}
spin_unlock_irqrestore(&dev->lock, flags);
- kref_get(&dev->kref);
-
return ret;
}
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 3da54a7d7aba..a2fd239b7ad3 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -591,6 +591,7 @@ static int rndis_init_response(struct rndis_params *params,
static int rndis_query_response(struct rndis_params *params,
rndis_query_msg_type *buf)
{
+ u32 BufLength, BufOffset;
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
@@ -598,6 +599,13 @@ static int rndis_query_response(struct rndis_params *params,
if (!params->dev)
return -ENOTSUPP;
+ BufLength = le32_to_cpu(buf->InformationBufferLength);
+ BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+ if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+ (BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
+ (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+ return -EINVAL;
+
/*
* we need more memory:
* gen_ndis_query_resp expects enough space for
@@ -614,10 +622,8 @@ static int rndis_query_response(struct rndis_params *params,
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
- le32_to_cpu(buf->InformationBufferOffset)
- + 8 + (u8 *)buf,
- le32_to_cpu(buf->InformationBufferLength),
- r)) {
+ BufOffset + 8 + (u8 *)buf,
+ BufLength, r)) {
/* OID not supported */
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = cpu_to_le32(sizeof *resp);
@@ -1074,6 +1080,12 @@ int rndis_rm_hdr(struct gether *port,
/* tmp points to a struct rndis_packet_msg_type */
__le32 *tmp = (void *)skb->data;
+ /* Need at least MessageType, MessageLength, DataOffset, DataLength */
+ if (skb->len < 16) {
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
/* MessageType, MessageLength */
if (cpu_to_le32(RNDIS_MSG_PACKET)
!= get_unaligned(tmp++)) {
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index e8861eaad907..068423fc581a 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -31,8 +31,9 @@ static const struct bus_type gadget_bus_type;
/**
* struct usb_udc - describes one usb device controller
* @driver: the gadget driver pointer. For use by the class code
- * @dev: the child device to the actual controller
* @gadget: the gadget. For use by the class code
+ * @gadget_release: the gadget's release routine
+ * @dev: the child device to the actual controller
* @list: for use by the udc class driver
* @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
@@ -53,6 +54,7 @@ static const struct bus_type gadget_bus_type;
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
+ void (*gadget_release)(struct device *dev);
struct device dev;
struct list_head list;
bool vbus;
@@ -1357,6 +1359,17 @@ static void usb_udc_nop_release(struct device *dev)
dev_vdbg(dev, "%s\n", __func__);
}
+static void usb_gadget_release(struct device *dev)
+{
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ /* Cache the gadget's release routine to prevent UAF */
+ void (*release)(struct device *dev) = udc->gadget_release;
+
+ put_device(&udc->dev);
+ release(dev);
+}
+
/**
* usb_initialize_gadget - initialize a gadget and its embedded struct device
* @parent: the parent device to this udc. Usually the controller driver's
@@ -1413,6 +1426,14 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_init(&udc->connect_lock);
udc->started = false;
+ /*
+ * Align decoupled lifecycles: take a UDC reference to ensure it
+ * remains allocated until the gadget is released, requiring an
+ * override of the gadget's release routine to drop it.
+ */
+ udc->gadget_release = gadget->dev.release;
+ gadget->dev.release = usb_gadget_release;
+ get_device(&udc->dev);
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
@@ -1457,6 +1478,12 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
+ /*
+ * Revert the override and drop the UDC reference to prevent
+ * leaking the UDC if the gadget was statically allocated.
+ */
+ gadget->dev.release = udc->gadget_release;
+ put_device(&udc->dev);
err_put_udc:
put_device(&udc->dev);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a241337c9af8..57d07d1c2dfa 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1623,6 +1623,7 @@ iso_stream_schedule(
status = 1; /* and give it back immediately */
iso_sched_free(stream, sched);
sched = NULL;
+ urb->hcpriv = NULL;
}
}
urb->error_count = skip / period;
@@ -1653,8 +1654,6 @@ iso_stream_schedule(
return status;
fail:
- iso_sched_free(stream, sched);
- urb->hcpriv = NULL;
return status;
}
@@ -1966,6 +1965,10 @@ static int itd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
@@ -2343,6 +2346,10 @@ static int sitd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4ae47edd4b8b..b044977f6f56 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1591,6 +1591,7 @@ sl811h_remove(struct platform_device *dev)
remove_debug_file(sl811);
usb_remove_hcd(hcd);
+ device_wakeup_disable(hcd->self.controller);
/* some platforms may use IORESOURCE_IO */
res = platform_get_resource(dev, IORESOURCE_MEM, 1);
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
index 23153e136d4b..a5deeee4d5dc 100644
--- a/drivers/usb/host/xhci-sideband.c
+++ b/drivers/usb/host/xhci-sideband.c
@@ -58,6 +58,8 @@ xhci_ring_to_sgtable(struct xhci_sideband *sb, struct xhci_ring *ring)
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL))
goto err;
+ kvfree(pages);
+
/*
* Save first segment dma address to sg dma_address field for the sideband
* client to have access to the IOVA of the ring.
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a54f5b57f205..15346fdd66bc 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3788,6 +3788,7 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_virt_device *vdev;
struct xhci_command *command;
struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_stream_info *stream_info[EP_CTX_PER_DEV];
unsigned int ep_index;
unsigned long flags;
u32 changed_ep_bitmask;
@@ -3848,10 +3849,15 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
if (ret < 0)
return ret;
+ /*
+ * dma_free_coherent() called by xhci_free_stream_info() may sleep,
+ * so save stream_info pointers and clear references under lock,
+ * then free the memory outside lock.
+ */
spin_lock_irqsave(&xhci->lock, flags);
for (i = 0; i < num_eps; i++) {
ep_index = xhci_get_endpoint_index(&eps[i]->desc);
- xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info);
+ stream_info[i] = vdev->eps[ep_index].stream_info;
vdev->eps[ep_index].stream_info = NULL;
/* FIXME Unset maxPstreams in endpoint context and
* update deq ptr to point to normal string ring.
@@ -3861,6 +3867,9 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
}
spin_unlock_irqrestore(&xhci->lock, flags);
+ for (i = 0; i < num_eps; i++)
+ xhci_free_stream_info(xhci, stream_info[i]);
+
return 0;
}
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index d8016540953f..9c06f7775301 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -320,7 +320,6 @@ bail:
mutex_unlock(&dev->lock);
destruction:
mutex_unlock(&chaoskey_list_lock);
- usb_dbg(interface, "release success");
return rv;
}
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 0f6b3464c2d6..3e37adf2bb57 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -63,6 +63,7 @@ MODULE_DEVICE_TABLE(usb, idmouse_table);
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
+ struct kref kref;
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
@@ -209,8 +210,10 @@ static int idmouse_resume(struct usb_interface *intf)
return 0;
}
-static inline void idmouse_delete(struct usb_idmouse *dev)
+static inline void idmouse_delete(struct kref *kref)
{
+ struct usb_idmouse *dev = container_of(kref, struct usb_idmouse, kref);
+
kfree(dev->bulk_in_buffer);
kfree(dev);
}
@@ -254,6 +257,8 @@ static int idmouse_open(struct inode *inode, struct file *file)
/* increment our usage count for the driver */
++dev->open;
+ kref_get(&dev->kref);
+
/* save our object in the file's private structure */
file->private_data = dev;
@@ -277,16 +282,11 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* lock our device */
mutex_lock(&dev->lock);
-
--dev->open;
+ mutex_unlock(&dev->lock);
+
+ kref_put(&dev->kref, idmouse_delete);
- if (!dev->present) {
- /* the device was unplugged before the file was released */
- mutex_unlock(&dev->lock);
- idmouse_delete(dev);
- } else {
- mutex_unlock(&dev->lock);
- }
return 0;
}
@@ -334,6 +334,7 @@ static int idmouse_probe(struct usb_interface *interface,
if (dev == NULL)
return -ENOMEM;
+ kref_init(&dev->kref);
mutex_init(&dev->lock);
dev->udev = udev;
dev->interface = interface;
@@ -342,8 +343,7 @@ static int idmouse_probe(struct usb_interface *interface,
result = usb_find_bulk_in_endpoint(iface_desc, &endpoint);
if (result) {
dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
- idmouse_delete(dev);
- return result;
+ goto err_put_kref;
}
dev->orig_bi_size = usb_endpoint_maxp(endpoint);
@@ -351,8 +351,8 @@ static int idmouse_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- idmouse_delete(dev);
- return -ENOMEM;
+ result = -ENOMEM;
+ goto err_put_kref;
}
/* allow device read, write and ioctl */
@@ -364,14 +364,18 @@ static int idmouse_probe(struct usb_interface *interface,
if (result) {
/* something prevented us from registering this device */
dev_err(&interface->dev, "Unable to allocate minor number.\n");
- idmouse_delete(dev);
- return result;
+ goto err_put_kref;
}
/* be noisy */
dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC);
return 0;
+
+err_put_kref:
+ kref_put(&dev->kref, idmouse_delete);
+
+ return result;
}
static void idmouse_disconnect(struct usb_interface *interface)
@@ -387,14 +391,9 @@ static void idmouse_disconnect(struct usb_interface *interface)
/* prevent device read, write and ioctl */
dev->present = 0;
- /* if the device is opened, idmouse_release will clean this up */
- if (!dev->open) {
- mutex_unlock(&dev->lock);
- idmouse_delete(dev);
- } else {
- /* unlock */
- mutex_unlock(&dev->lock);
- }
+ mutex_unlock(&dev->lock);
+
+ kref_put(&dev->kref, idmouse_delete);
dev_info(&interface->dev, "disconnected\n");
}
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 22504c0a2841..de2b236ef903 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -72,6 +72,7 @@ static struct usb_driver iowarrior_driver;
/* Structure to hold all of our device specific stuff */
struct iowarrior {
+ struct kref kref;
struct mutex mutex; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
@@ -240,8 +241,10 @@ static void iowarrior_write_callback(struct urb *urb)
/*
* iowarrior_delete
*/
-static inline void iowarrior_delete(struct iowarrior *dev)
+static inline void iowarrior_delete(struct kref *kref)
{
+ struct iowarrior *dev = container_of(kref, struct iowarrior, kref);
+
kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue);
@@ -637,6 +640,9 @@ static int iowarrior_open(struct inode *inode, struct file *file)
}
/* increment our usage count for the driver */
++dev->opened;
+
+ kref_get(&dev->kref);
+
/* save our object in the file's private structure */
file->private_data = dev;
retval = 0;
@@ -652,7 +658,6 @@ out:
static int iowarrior_release(struct inode *inode, struct file *file)
{
struct iowarrior *dev;
- int retval = 0;
dev = file->private_data;
if (!dev)
@@ -660,29 +665,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)
/* lock our device */
mutex_lock(&dev->mutex);
+ dev->opened = 0; /* we're closing now */
- if (dev->opened <= 0) {
- retval = -ENODEV; /* close called more than once */
- mutex_unlock(&dev->mutex);
- } else {
- dev->opened = 0; /* we're closing now */
- retval = 0;
- if (dev->present) {
- /*
- The device is still connected so we only shutdown
- pending read-/write-ops.
- */
- usb_kill_urb(dev->int_in_urb);
- wake_up_interruptible(&dev->read_wait);
- wake_up_interruptible(&dev->write_wait);
- mutex_unlock(&dev->mutex);
- } else {
- /* The device was unplugged, cleanup resources */
- mutex_unlock(&dev->mutex);
- iowarrior_delete(dev);
- }
+ if (dev->present) {
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
}
- return retval;
+ mutex_unlock(&dev->mutex);
+
+ kref_put(&dev->kref, iowarrior_delete);
+
+ return 0;
}
static __poll_t iowarrior_poll(struct file *file, poll_table * wait)
@@ -767,6 +761,7 @@ static int iowarrior_probe(struct usb_interface *interface,
if (!dev)
return retval;
+ kref_init(&dev->kref);
mutex_init(&dev->mutex);
atomic_set(&dev->intr_idx, 0);
@@ -885,7 +880,8 @@ static int iowarrior_probe(struct usb_interface *interface,
return retval;
error:
- iowarrior_delete(dev);
+ kref_put(&dev->kref, iowarrior_delete);
+
return retval;
}
@@ -905,21 +901,18 @@ static void iowarrior_disconnect(struct usb_interface *interface)
/* prevent device read, write and ioctl */
dev->present = 0;
+ /* write urbs are not stopped on close() so kill unconditionally */
+ usb_kill_anchored_urbs(&dev->submitted);
+
if (dev->opened) {
- /* There is a process that holds a filedescriptor to the device ,
- so we only shutdown read-/write-ops going on.
- Deleting the device is postponed until close() was called.
- */
usb_kill_urb(dev->int_in_urb);
- usb_kill_anchored_urbs(&dev->submitted);
wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait);
- mutex_unlock(&dev->mutex);
- } else {
- /* no process is using the device, cleanup now */
- mutex_unlock(&dev->mutex);
- iowarrior_delete(dev);
}
+
+ mutex_unlock(&dev->mutex);
+
+ kref_put(&dev->kref, iowarrior_delete);
}
/* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index c74f142f6637..71132a15e771 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -150,6 +150,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
/* Structure to hold all of our device specific stuff */
struct ld_usb {
+ struct kref kref;
struct mutex mutex; /* locks this structure */
struct usb_interface *intf; /* save off the usb interface pointer */
unsigned long disconnected:1;
@@ -201,8 +202,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
/*
* ld_usb_delete
*/
-static void ld_usb_delete(struct ld_usb *dev)
+static void ld_usb_delete(struct kref *kref)
{
+ struct ld_usb *dev = container_of(kref, struct ld_usb, kref);
+
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -355,6 +358,8 @@ static int ld_usb_open(struct inode *inode, struct file *file)
goto unlock_exit;
}
+ kref_get(&dev->kref);
+
/* save device in the file's private structure */
file->private_data = dev;
@@ -381,17 +386,8 @@ static int ld_usb_release(struct inode *inode, struct file *file)
mutex_lock(&dev->mutex);
- if (dev->open_count != 1) {
- retval = -ENODEV;
+ if (dev->disconnected)
goto unlock_exit;
- }
- if (dev->disconnected) {
- /* the device was unplugged before the file was released */
- mutex_unlock(&dev->mutex);
- /* unlock here as ld_usb_delete frees dev */
- ld_usb_delete(dev);
- goto exit;
- }
/* wait until write transfer is finished */
if (dev->interrupt_out_busy)
@@ -401,7 +397,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
unlock_exit:
mutex_unlock(&dev->mutex);
-
+ kref_put(&dev->kref, ld_usb_delete);
exit:
return retval;
}
@@ -659,6 +655,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev = kzalloc_obj(*dev);
if (!dev)
goto exit;
+
+ kref_init(&dev->kref);
mutex_init(&dev->mutex);
spin_lock_init(&dev->rbsl);
dev->intf = intf;
@@ -740,7 +738,7 @@ exit:
return retval;
error:
- ld_usb_delete(dev);
+ kref_put(&dev->kref, ld_usb_delete);
return retval;
}
@@ -768,18 +766,18 @@ static void ld_usb_disconnect(struct usb_interface *intf)
mutex_lock(&dev->mutex);
- /* if the device is not opened, then we clean up right now */
- if (!dev->open_count) {
- mutex_unlock(&dev->mutex);
- ld_usb_delete(dev);
- } else {
- dev->disconnected = 1;
+ dev->disconnected = 1;
+
+ if (dev->open_count) {
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
- mutex_unlock(&dev->mutex);
}
+ mutex_unlock(&dev->mutex);
+
+ kref_put(&dev->kref, ld_usb_delete);
+
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
(minor - USB_LD_MINOR_BASE));
}
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 052ffc2e71ee..18dd4115befb 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -185,6 +185,7 @@ MODULE_DEVICE_TABLE(usb, tower_table);
/* Structure to hold all of our device specific stuff */
struct lego_usb_tower {
+ struct kref kref;
struct mutex lock; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
unsigned char minor; /* the starting minor number for this device */
@@ -220,7 +221,6 @@ struct lego_usb_tower {
/* local function prototypes */
static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
-static inline void tower_delete(struct lego_usb_tower *dev);
static int tower_open(struct inode *inode, struct file *file);
static int tower_release(struct inode *inode, struct file *file);
static __poll_t tower_poll(struct file *file, poll_table *wait);
@@ -286,8 +286,10 @@ static inline void lego_usb_tower_debug_data(struct device *dev,
/*
* tower_delete
*/
-static inline void tower_delete(struct lego_usb_tower *dev)
+static inline void tower_delete(struct kref *kref)
{
+ struct lego_usb_tower *dev = container_of(kref, struct lego_usb_tower, kref);
+
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -381,6 +383,8 @@ static int tower_open(struct inode *inode, struct file *file)
dev->open_count = 1;
+ kref_get(&dev->kref);
+
unlock_exit:
mutex_unlock(&dev->lock);
@@ -404,14 +408,8 @@ static int tower_release(struct inode *inode, struct file *file)
mutex_lock(&dev->lock);
- if (dev->disconnected) {
- /* the device was unplugged before the file was released */
-
- /* unlock here as tower_delete frees dev */
- mutex_unlock(&dev->lock);
- tower_delete(dev);
- goto exit;
- }
+ if (dev->disconnected)
+ goto out_unlock;
/* wait until write transfer is finished */
if (dev->interrupt_out_busy) {
@@ -425,7 +423,9 @@ static int tower_release(struct inode *inode, struct file *file)
dev->open_count = 0;
+out_unlock:
mutex_unlock(&dev->lock);
+ kref_put(&dev->kref, tower_delete);
exit:
return retval;
}
@@ -752,6 +752,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_
if (!dev)
goto exit;
+ kref_init(&dev->kref);
mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
spin_lock_init(&dev->read_buffer_lock);
@@ -828,7 +829,7 @@ exit:
return retval;
error:
- tower_delete(dev);
+ kref_put(&dev->kref, tower_delete);
return retval;
}
@@ -856,18 +857,18 @@ static void tower_disconnect(struct usb_interface *interface)
mutex_lock(&dev->lock);
- /* if the device is not opened, then we clean up right now */
- if (!dev->open_count) {
- mutex_unlock(&dev->lock);
- tower_delete(dev);
- } else {
- dev->disconnected = 1;
+ dev->disconnected = 1;
+
+ if (dev->open_count) {
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
- mutex_unlock(&dev->lock);
}
+ mutex_unlock(&dev->lock);
+
+ kref_put(&dev->kref, tower_delete);
+
dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
(minor - LEGO_USB_TOWER_MINOR_BASE));
}
diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c
index 02d1e0760f0c..3c2474dca810 100644
--- a/drivers/usb/misc/usbio.c
+++ b/drivers/usb/misc/usbio.c
@@ -344,6 +344,10 @@ read:
if (ibuf_len < bpkt_len)
return -ENOSPC;
+ /* The device must not claim more payload than it actually sent. */
+ if (bpkt_len > act - sizeof(*bpkt))
+ return -EPROTO;
+
memcpy(ibuf, bpkt->data, bpkt_len);
return bpkt_len;
@@ -518,7 +522,7 @@ static int usbio_resume(struct usb_interface *intf)
static void usbio_disconnect(struct usb_interface *intf)
{
struct usbio_device *usbio = usb_get_intfdata(intf);
- struct usbio_client *client;
+ struct usbio_client *client, *next;
/* Wakeup any clients waiting for a reply */
usbio->rxdat_len = 0;
@@ -535,7 +539,7 @@ static void usbio_disconnect(struct usb_interface *intf)
usb_kill_urb(usbio->urb);
usb_free_urb(usbio->urb);
- list_for_each_entry_reverse(client, &usbio->cli_list, link) {
+ list_for_each_entry_safe_reverse(client, next, &usbio->cli_list, link) {
auxiliary_device_delete(&client->auxdev);
auxiliary_device_uninit(&client->auxdev);
}
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index b7d3c44b970e..1ce48f5832d7 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -732,8 +732,11 @@ static int uss720_probe(struct usb_interface *intf,
* here. */
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
- if (ret < 0)
+ if (ret < 0) {
+ priv->pp = NULL;
+ parport_del_port(pp);
goto probe_abort;
+ }
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index da29f467943f..f224f2ee379a 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -305,6 +305,7 @@ static int mtu3_gadget_queue(struct usb_ep *ep,
if (mtu3_prepare_transfer(mep)) {
ret = -EAGAIN;
+ usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
goto error;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index c481208255eb..c96e5b76f313 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -394,12 +394,14 @@ static int digi_write_oob_command(struct usb_serial_port *port,
len &= ~3;
memcpy(oob_port->write_urb->transfer_buffer, buf, len);
oob_port->write_urb->transfer_buffer_length = len;
+
ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
- if (ret == 0) {
- oob_priv->dp_write_urb_in_use = 1;
- count -= len;
- buf += len;
- }
+ if (ret)
+ break;
+
+ oob_priv->dp_write_urb_in_use = 1;
+ count -= len;
+ buf += len;
}
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
@@ -429,20 +431,22 @@ static int digi_write_inb_command(struct usb_serial_port *port,
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
+ unsigned long expire;
unsigned long flags;
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
if (timeout)
- timeout += jiffies;
- else
- timeout = ULONG_MAX;
+ expire = jiffies + timeout;
spin_lock_irqsave(&priv->dp_port_lock, flags);
while (count > 0 && ret == 0) {
- while (priv->dp_write_urb_in_use &&
- time_before(jiffies, timeout)) {
+ while (priv->dp_write_urb_in_use) {
+ if (timeout && time_after(jiffies, expire)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
cond_wait_interruptible_timeout_irqrestore(
&priv->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
@@ -451,6 +455,9 @@ static int digi_write_inb_command(struct usb_serial_port *port,
spin_lock_irqsave(&priv->dp_port_lock, flags);
}
+ if (ret)
+ break;
+
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
@@ -1071,6 +1078,7 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
+ int throttled;
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
@@ -1098,6 +1106,21 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
not_termios.c_iflag = ~tty->termios.c_iflag;
digi_set_termios(tty, port, &not_termios);
}
+
+ spin_lock_irq(&priv->dp_port_lock);
+ throttled = priv->dp_throttle_restart;
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
+ spin_unlock_irq(&priv->dp_port_lock);
+
+ if (throttled) {
+ ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (ret) {
+ dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
+ return ret;
+ }
+ }
+
return 0;
}
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 5036600dd334..377f5695cfc6 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -518,7 +518,7 @@ static int keyspan_pda_write_start(struct usb_serial_port *port)
if (count == room)
schedule_work(&priv->unthrottle_work);
- return count;
+ return 0;
}
static void keyspan_pda_write_bulk_callback(struct urb *urb)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a34e79cfd5b6..7a0f37feb9f2 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1326,6 +1326,22 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x30), /* Telit FE990D50 (RNDIS) */
+ .driver_info = NCTRL(6) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x40) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x60) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x30), /* Telit FE990D50 (rmnet) */
+ .driver_info = NCTRL(5) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x40) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x60) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x30), /* Telit FE990D50 (MBIM) */
+ .driver_info = NCTRL(6) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x40) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x60) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x30), /* Telit FE990D50 (ECM) */
+ .driver_info = NCTRL(6) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x40) },
+ { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x60) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1031, 0xff), /* Telit LE910C1-EUX */
.driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 8770de01a384..ed49a3bc859c 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -2305,7 +2305,8 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
/*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
- if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready)))
+ if (unlikely(!(info->SD_Status & SD_Ready) &&
+ !(info->MS_Status & MS_Ready)))
result = ene_init(us);
if (result == USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index fa83fe0defe2..064c7fc8e368 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -570,7 +570,7 @@ void usb_stor_adjust_quirks(struct usb_device *udev, u64 *fflags)
US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS |
- US_FL_ALWAYS_SYNC);
+ US_FL_ALWAYS_SYNC | US_FL_NO_SAME);
p = quirks;
while (*p) {
diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c
index 2e8ae1d2faf9..db917b05dcde 100644
--- a/drivers/usb/typec/anx7411.c
+++ b/drivers/usb/typec/anx7411.c
@@ -1537,7 +1537,9 @@ static int anx7411_i2c_probe(struct i2c_client *client)
if (anx7411_typec_check_connection(plat))
dev_err(dev, "check status\n");
- pm_runtime_enable(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ goto free_wq;
return 0;
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 0977581ad1b6..0595e8cb83aa 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1619,6 +1619,7 @@ static ssize_t select_usb_power_delivery_store(struct device *dev,
return -EINVAL;
ret = port->ops->pd_set(port, pd);
+ put_device(&pd->dev);
if (ret)
return ret;
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index db5e4a4c0a99..9b908c46bd7d 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -275,9 +275,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)
static void *typec_mux_match(const struct fwnode_handle *fwnode,
const char *id, void *data)
{
- struct typec_mux_dev **mux_devs = data;
struct device *dev;
- int i;
/*
* Device graph (OF graph) does not give any means to identify the
@@ -293,14 +291,6 @@ static void *typec_mux_match(const struct fwnode_handle *fwnode,
dev = class_find_device(&typec_mux_class, NULL, fwnode,
mux_fwnode_match);
- /* Skip duplicates */
- for (i = 0; i < TYPEC_MUX_MAX_DEVS; i++)
- if (to_typec_mux_dev(dev) == mux_devs[i]) {
- put_device(dev);
- return NULL;
- }
-
-
return dev ? to_typec_mux_dev(dev) : ERR_PTR(-EPROBE_DEFER);
}
@@ -326,8 +316,7 @@ struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode)
return ERR_PTR(-ENOMEM);
count = fwnode_connection_find_matches(fwnode, "mode-switch",
- (void **)mux_devs,
- typec_mux_match,
+ NULL, typec_mux_match,
(void **)mux_devs,
ARRAY_SIZE(mux_devs));
if (count <= 0) {
diff --git a/drivers/usb/typec/mux/ps883x.c b/drivers/usb/typec/mux/ps883x.c
index 1256252eceed..c9bf4b4c2ba1 100644
--- a/drivers/usb/typec/mux/ps883x.c
+++ b/drivers/usb/typec/mux/ps883x.c
@@ -118,12 +118,12 @@ static int ps883x_set(struct ps883x_retimer *retimer, struct typec_retimer_state
CONN_STATUS_1_DP_HPD_LEVEL;
switch (state->mode) {
+ case TYPEC_DP_STATE_D:
+ cfg0 |= CONN_STATUS_0_USB_3_1_CONNECTED;
+ fallthrough;
case TYPEC_DP_STATE_C:
cfg1 |= CONN_STATUS_1_DP_SINK_REQUESTED |
CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D;
- fallthrough;
- case TYPEC_DP_STATE_D:
- cfg1 |= CONN_STATUS_0_USB_3_1_CONNECTED;
break;
default: /* MODE_E */
break;
diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
index 4b3e4e22a82e..0af95c2d33fc 100644
--- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c
+++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
@@ -295,6 +295,8 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip)
return 0;
}
+static void rt1711h_unregister_tcpci_port(void *tcpci);
+
static int rt1711h_probe(struct i2c_client *client)
{
int ret;
@@ -340,6 +342,10 @@ static int rt1711h_probe(struct i2c_client *client)
if (IS_ERR_OR_NULL(chip->tcpci))
return PTR_ERR(chip->tcpci);
+ ret = devm_add_action_or_reset(chip->dev, rt1711h_unregister_tcpci_port, chip->tcpci);
+ if (ret)
+ return ret;
+
ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
rt1711h_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
@@ -357,11 +363,9 @@ static int rt1711h_probe(struct i2c_client *client)
return 0;
}
-static void rt1711h_remove(struct i2c_client *client)
+static void rt1711h_unregister_tcpci_port(void *tcpci)
{
- struct rt1711h_chip *chip = i2c_get_clientdata(client);
-
- tcpci_unregister_port(chip->tcpci);
+ tcpci_unregister_port(tcpci);
}
static const struct rt1711h_chip_info rt1711h = {
@@ -394,7 +398,6 @@ static struct i2c_driver rt1711h_i2c_driver = {
.of_match_table = rt1711h_of_match,
},
.probe = rt1711h_probe,
- .remove = rt1711h_remove,
.id_table = rt1711h_id,
};
module_i2c_driver(rt1711h_i2c_driver);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 7ef746a90a17..89eec20a2064 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2000,6 +2000,11 @@ static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt,
return;
}
+ if (pmdata->svid_index < 0 || pmdata->svid_index >= pmdata->nsvids) {
+ tcpm_log(port, "Invalid SVID index %d", pmdata->svid_index);
+ return;
+ }
+
for (i = 1; i < cnt; i++) {
if (pmdata->altmodes >= ALTMODE_DISCOVERY_MAX) {
/* Already logged in svdm_consume_svids() */
@@ -3088,7 +3093,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
if (svdm_version < 0)
return svdm_version;
- header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
+ header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
@@ -3136,7 +3141,7 @@ static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_pl
if (svdm_version < 0)
return svdm_version;
- header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
+ header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c
index 67a0991a7b76..7067f2561b84 100644
--- a/drivers/usb/typec/ucsi/displayport.c
+++ b/drivers/usb/typec/ucsi/displayport.c
@@ -166,12 +166,12 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp)
* that Multi-function is preferred.
*/
if (DP_CAP_CAPABILITY(cap) & DP_CAP_UFP_D) {
- dp->data.status |= DP_STATUS_CON_UFP_D;
+ dp->data.status |= DP_STATUS_CON_DFP_D;
if (DP_CAP_UFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D))
dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC;
} else {
- dp->data.status |= DP_STATUS_CON_DFP_D;
+ dp->data.status |= DP_STATUS_CON_UFP_D;
if (DP_CAP_DFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D))
dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC;
@@ -185,13 +185,12 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp)
static int ucsi_displayport_configure(struct ucsi_dp *dp)
{
- u32 pins = DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
u64 command;
if (!dp->override)
return 0;
- command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins);
+ command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, dp->data.conf);
return ucsi_send_command(dp->con->ucsi, command, NULL, 0);
}
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 61cb24ed820f..66b879957165 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1978,6 +1978,26 @@ static void ucsi_resume_work(struct work_struct *work)
}
}
+int ucsi_suspend(struct ucsi *ucsi)
+{
+ int i;
+
+ /*
+ * Cancel pending work so it cannot access the firmware after the ACPI
+ * EC is stopped for suspend; state is re-read on resume.
+ */
+ cancel_delayed_work_sync(&ucsi->work);
+
+ if (!ucsi->connector)
+ return 0;
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ cancel_work_sync(&ucsi->connector[i].work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ucsi_suspend);
+
int ucsi_resume(struct ucsi *ucsi)
{
if (ucsi->connector)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index cff9ddc2ae21..dd64ddc42118 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -566,6 +566,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command,
void *retval, size_t size);
void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_suspend(struct ucsi *ucsi);
int ucsi_resume(struct ucsi *ucsi);
void ucsi_notify_common(struct ucsi *ucsi, u32 cci);
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index 6b92f296e985..94b52ccf6f42 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -245,6 +245,13 @@ static void ucsi_acpi_remove(struct platform_device *pdev)
ucsi_acpi_notify);
}
+static int ucsi_acpi_suspend(struct device *dev)
+{
+ struct ucsi_acpi *ua = dev_get_drvdata(dev);
+
+ return ucsi_suspend(ua->ucsi);
+}
+
static int ucsi_acpi_resume(struct device *dev)
{
struct ucsi_acpi *ua = dev_get_drvdata(dev);
@@ -252,7 +259,8 @@ static int ucsi_acpi_resume(struct device *dev)
return ucsi_resume(ua->ucsi);
}
-static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, ucsi_acpi_suspend,
+ ucsi_acpi_resume);
static const struct acpi_device_id ucsi_acpi_match[] = {
{ "PNP0CA0", 0 },
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 4463c1ae96bd..51498329a4d5 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -1519,8 +1519,8 @@ static void ucsi_ccg_remove(struct i2c_client *client)
cancel_work_sync(&uc->work);
pm_runtime_disable(uc->dev);
ucsi_unregister(uc->ucsi);
- ucsi_destroy(uc->ucsi);
free_irq(uc->irq, uc);
+ ucsi_destroy(uc->ucsi);
}
static const struct of_device_id ucsi_ccg_of_match_table[] = {
diff --git a/drivers/usb/usbip/vudc.h b/drivers/usb/usbip/vudc.h
index faf61c9c6a98..5ef0e7d9b23a 100644
--- a/drivers/usb/usbip/vudc.h
+++ b/drivers/usb/usbip/vudc.h
@@ -38,7 +38,6 @@ struct vep {
struct vrequest {
struct usb_request req;
- struct vudc *udc;
struct list_head req_entry; /* Request queue */
};
diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c
index c5f079c5a1ea..5ef88117965d 100644
--- a/drivers/usb/usbip/vudc_dev.c
+++ b/drivers/usb/usbip/vudc_dev.c
@@ -333,7 +333,6 @@ static int vep_queue(struct usb_ep *_ep, struct usb_request *_req,
static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct vep *ep;
- struct vrequest *req;
struct vudc *udc;
struct vrequest *lst;
unsigned long flags;
@@ -343,8 +342,7 @@ static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return ret;
ep = to_vep(_ep);
- req = to_vrequest(_req);
- udc = req->udc;
+ udc = ep_to_vudc(ep);
if (!udc->driver)
return -ESHUTDOWN;
diff --git a/drivers/vfio/debugfs.c b/drivers/vfio/debugfs.c
index 8b0ca7a09064..8a2f1b0cce3f 100644
--- a/drivers/vfio/debugfs.c
+++ b/drivers/vfio/debugfs.c
@@ -97,6 +97,7 @@ void vfio_device_debugfs_init(struct vfio_device *vdev)
void vfio_device_debugfs_exit(struct vfio_device *vdev)
{
debugfs_remove_recursive(vdev->debug_root);
+ vdev->debug_root = NULL;
}
void vfio_debugfs_create_root(void)
diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h
index deed0f132f39..c86d8b243a52 100644
--- a/drivers/vfio/pci/mlx5/cmd.h
+++ b/drivers/vfio/pci/mlx5/cmd.h
@@ -158,26 +158,29 @@ struct mlx5_vhca_qp {
struct mlx5_vhca_page_tracker {
u32 id;
u32 pdn;
- u8 is_err:1;
- u8 object_changed:1;
+ /* Flags modified at runtime - dedicated storage unit */
+ u8 is_err;
+ u8 object_changed;
+ int status;
struct mlx5_uars_page *uar;
struct mlx5_vhca_cq cq;
struct mlx5_vhca_qp *host_qp;
struct mlx5_vhca_qp *fw_qp;
struct mlx5_nb nb;
- int status;
};
struct mlx5vf_pci_core_device {
struct vfio_pci_core_device core_device;
int vf_id;
u16 vhca_id;
+ /* Flags only modified on setup/release - bitfield ok */
u8 migrate_cap:1;
- u8 deferred_reset:1;
- u8 mdev_detach:1;
- u8 log_active:1;
u8 chunk_mode:1;
u8 mig_state_cap:1;
+ /* Flags modified at runtime - dedicated storage unit */
+ u8 mdev_detach;
+ u8 log_active;
+ u8 deferred_reset;
struct completion tracker_comp;
/* protect migration state */
struct mutex state_mutex;
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 050e7542952e..beb1674c6945 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -271,8 +271,11 @@ int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev, pci_power_t stat
int ret;
/* Prevent changing power state for PFs with VFs enabled */
- if (pci_num_vf(pdev) && state > PCI_D0)
- return -EBUSY;
+ if (state > PCI_D0) {
+ lockdep_assert_held_write(&vdev->memory_lock);
+ if (vdev->sriov_active)
+ return -EBUSY;
+ }
if (vdev->needs_pm_restore) {
if (pdev->current_state < PCI_D3hot && state >= PCI_D3hot) {
@@ -535,7 +538,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
u16 cmd;
u8 msix_pos;
- if (!disable_idle_d3) {
+ if (!vdev->disable_idle_d3) {
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;
@@ -614,7 +617,7 @@ out_free_state:
out_disable_device:
pci_disable_device(pdev);
out_power:
- if (!disable_idle_d3)
+ if (!vdev->disable_idle_d3)
pm_runtime_put(&pdev->dev);
return ret;
}
@@ -750,7 +753,7 @@ out:
vfio_pci_dev_set_try_reset(vdev->vdev.dev_set);
/* Put the pm-runtime usage counter acquired during enable */
- if (!disable_idle_d3)
+ if (!vdev->disable_idle_d3)
pm_runtime_put(&pdev->dev);
}
EXPORT_SYMBOL_GPL(vfio_pci_core_disable);
@@ -2142,6 +2145,8 @@ int vfio_pci_core_init_dev(struct vfio_device *core_vdev)
init_rwsem(&vdev->memory_lock);
xa_init(&vdev->ctx);
+ vdev->disable_idle_d3 = disable_idle_d3;
+
return 0;
}
EXPORT_SYMBOL_GPL(vfio_pci_core_init_dev);
@@ -2237,7 +2242,7 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
dev->driver->pm = &vfio_pci_core_pm_ops;
pm_runtime_allow(dev);
- if (!disable_idle_d3)
+ if (!vdev->disable_idle_d3)
pm_runtime_put(dev);
ret = vfio_register_group_dev(&vdev->vdev);
@@ -2246,10 +2251,11 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
return 0;
out_power:
- if (!disable_idle_d3)
+ if (!vdev->disable_idle_d3)
pm_runtime_get_noresume(dev);
pm_runtime_forbid(dev);
+ vfio_pci_vga_uninit(vdev);
out_vf:
vfio_pci_vf_uninit(vdev);
return ret;
@@ -2265,7 +2271,7 @@ void vfio_pci_core_unregister_device(struct vfio_pci_core_device *vdev)
vfio_pci_vf_uninit(vdev);
vfio_pci_vga_uninit(vdev);
- if (!disable_idle_d3)
+ if (!vdev->disable_idle_d3)
pm_runtime_get_noresume(&vdev->pdev->dev);
pm_runtime_forbid(&vdev->pdev->dev);
@@ -2327,8 +2333,9 @@ int vfio_pci_core_sriov_configure(struct vfio_pci_core_device *vdev,
down_write(&vdev->memory_lock);
vfio_pci_set_power_state(vdev, PCI_D0);
- ret = pci_enable_sriov(pdev, nr_virtfn);
+ vdev->sriov_active = true;
up_write(&vdev->memory_lock);
+ ret = pci_enable_sriov(pdev, nr_virtfn);
if (ret) {
pm_runtime_put(&pdev->dev);
goto out_del;
@@ -2342,6 +2349,13 @@ int vfio_pci_core_sriov_configure(struct vfio_pci_core_device *vdev,
}
out_del:
+ /*
+ * Avoid taking the memory_lock intentionally. A race with a power
+ * state transition would at most result in an -EBUSY, leaving the
+ * device in PCI_D0.
+ */
+ vdev->sriov_active = false;
+
mutex_lock(&vfio_pci_sriov_pfs_mutex);
list_del_init(&vdev->sriov_pfs_item);
out_unlock:
@@ -2589,7 +2603,7 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set)
* state. Increment the usage count for all the devices in the dev_set
* before reset and decrement the same after reset.
*/
- if (!disable_idle_d3 && vfio_pci_dev_set_pm_runtime_get(dev_set))
+ if (vfio_pci_dev_set_pm_runtime_get(dev_set))
return;
if (!pci_reset_bus(pdev))
@@ -2599,8 +2613,7 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set)
if (reset_done)
cur->needs_reset = false;
- if (!disable_idle_d3)
- pm_runtime_put(&cur->pdev->dev);
+ pm_runtime_put(&cur->pdev->dev);
}
}
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 6222376ab6ab..ed538aebb0b8 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -407,6 +407,13 @@ void vfio_unregister_group_dev(struct vfio_device *device)
vfio_device_group_unregister(device);
/*
+ * Remove debugfs before device_del(), which releases devres. Some
+ * debugfs entries are created with debugfs_create_devm_seqfile() and
+ * therefore rely on devres-managed inode private data.
+ */
+ vfio_device_debugfs_exit(device);
+
+ /*
* Balances vfio_device_add() in register path, also prevents
* new device opened by userspace in the cdev path.
*/
@@ -435,7 +442,6 @@ void vfio_unregister_group_dev(struct vfio_device *device)
}
}
- vfio_device_debugfs_exit(device);
/* Balances vfio_device_set_group in register path */
vfio_device_remove_group(device);
}
@@ -858,7 +864,8 @@ int vfio_mig_get_next_state(struct vfio_device *device,
* logical state, as per the above comment.
*/
*next_fsm = vfio_from_fsm_table[cur_fsm][new_fsm];
- while ((state_flags_table[*next_fsm] & device->migration_flags) !=
+ while (*next_fsm != VFIO_DEVICE_STATE_ERROR &&
+ (state_flags_table[*next_fsm] & device->migration_flags) !=
state_flags_table[*next_fsm])
*next_fsm = vfio_from_fsm_table[*next_fsm][new_fsm];
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 595c2274fbb5..510b7c4efdff 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -662,9 +662,7 @@ static void virtio_mmio_remove(struct platform_device *pdev)
#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES)
-static struct device vm_cmdline_parent = {
- .init_name = "virtio-mmio-cmdline",
-};
+static struct device *vm_cmdline_parent;
static int vm_cmdline_parent_registered;
static int vm_cmdline_id;
@@ -672,7 +670,6 @@ static int vm_cmdline_id;
static int vm_cmdline_set(const char *device,
const struct kernel_param *kp)
{
- int err;
struct resource resources[2] = {};
char *str;
long long base, size;
@@ -704,11 +701,10 @@ static int vm_cmdline_set(const char *device,
resources[1].start = resources[1].end = irq;
if (!vm_cmdline_parent_registered) {
- err = device_register(&vm_cmdline_parent);
- if (err) {
- put_device(&vm_cmdline_parent);
+ vm_cmdline_parent = __root_device_register("virtio-mmio-cmdline", NULL);
+ if (IS_ERR(vm_cmdline_parent)) {
pr_err("Failed to register parent device!\n");
- return err;
+ return PTR_ERR(vm_cmdline_parent);
}
vm_cmdline_parent_registered = 1;
}
@@ -719,7 +715,7 @@ static int vm_cmdline_set(const char *device,
(unsigned long long)resources[0].end,
(int)resources[1].start);
- pdev = platform_device_register_resndata(&vm_cmdline_parent,
+ pdev = platform_device_register_resndata(vm_cmdline_parent,
"virtio-mmio", vm_cmdline_id++,
resources, ARRAY_SIZE(resources), NULL, 0);
@@ -743,8 +739,12 @@ static int vm_cmdline_get_device(struct device *dev, void *data)
static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
{
buffer[0] = '\0';
- device_for_each_child(&vm_cmdline_parent, buffer,
- vm_cmdline_get_device);
+
+ if (vm_cmdline_parent_registered) {
+ device_for_each_child(vm_cmdline_parent, buffer,
+ vm_cmdline_get_device);
+ }
+
return strlen(buffer) + 1;
}
@@ -766,9 +766,9 @@ static int vm_unregister_cmdline_device(struct device *dev,
static void vm_unregister_cmdline_devices(void)
{
if (vm_cmdline_parent_registered) {
- device_for_each_child(&vm_cmdline_parent, NULL,
+ device_for_each_child(vm_cmdline_parent, NULL,
vm_unregister_cmdline_device);
- device_unregister(&vm_cmdline_parent);
+ root_device_unregister(vm_cmdline_parent);
vm_cmdline_parent_registered = 0;
}
}
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index da97b6a988de..164f480b18a6 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -423,10 +423,11 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
vqs[i] = NULL;
continue;
}
- vqs[i] = vp_find_one_vq_msix(vdev, queue_idx++, vqi->callback,
+ vqs[i] = vp_find_one_vq_msix(vdev, queue_idx, vqi->callback,
vqi->name, vqi->ctx, false,
&allocated_vectors, vector_policy,
- &vp_dev->vqs[i]);
+ &vp_dev->vqs[queue_idx]);
+ queue_idx++;
if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]);
goto error_find;
@@ -485,9 +486,10 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
vqs[i] = NULL;
continue;
}
- vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+ vqs[i] = vp_setup_vq(vdev, queue_idx, vqi->callback,
vqi->name, vqi->ctx,
- VIRTIO_MSI_NO_VECTOR, &vp_dev->vqs[i]);
+ VIRTIO_MSI_NO_VECTOR, &vp_dev->vqs[queue_idx]);
+ queue_idx++;
if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]);
goto out_del_vqs;
diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
index 66a158f67a71..6b9b0f9b05ce 100644
--- a/drivers/watchdog/apple_wdt.c
+++ b/drivers/watchdog/apple_wdt.c
@@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);
static const struct of_device_id apple_wdt_of_match[] = {
+ { .compatible = "apple,t8103-wdt" },
{ .compatible = "apple,wdt" },
{},
};