summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-11-16 10:11:56 -0800
committerLinux Build Service Account <lnxbuild@localhost>2019-11-16 10:11:56 -0800
commitfeb565e67fc2b2f2a95890577120141be5886594 (patch)
treeb9057c7253ca0180b12d885d5a5140d5f90eb927 /drivers
parent6ed4c5de4bb191a209c629463678e34f076fb417 (diff)
parent739a986440ba67d48277fd553a5fe32ab008666d (diff)
Merge 739a986440ba67d48277fd553a5fe32ab008666d on remote branch
Change-Id: Idd84f971e07f65aa635d7d499dde696b84b217b6
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/cppc_acpi.c6
-rw-r--r--drivers/acpi/custom_method.c5
-rw-r--r--drivers/android/binder.c42
-rw-r--r--drivers/base/core.c3
-rw-r--r--drivers/base/soc.c2
-rw-r--r--drivers/block/loop.c1
-rw-r--r--drivers/bluetooth/btusb.c3
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/diag/Kconfig2
-rw-r--r--drivers/char/diag/Makefile2
-rw-r--r--drivers/char/diag/diag_dci.c23
-rw-r--r--drivers/char/diag/diag_masks.c3
-rw-r--r--drivers/char/diag/diagfwd_bridge.c2
-rw-r--r--drivers/char/diag/diagfwd_sdio.h4
-rw-r--r--drivers/char/hw_random/core.c2
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c24
-rw-r--r--drivers/char/mem.c21
-rw-r--r--drivers/clk/clk-qoriq.c2
-rw-r--r--drivers/clk/sirf/clk-common.c12
-rw-r--r--drivers/cpufreq/cpufreq.c10
-rw-r--r--drivers/crypto/caam/caamalg.c11
-rw-r--r--drivers/crypto/qat/qat_common/adf_common_drv.h2
-rw-r--r--drivers/crypto/talitos.c1
-rw-r--r--drivers/devfreq/governor_msm_adreno_tz.c10
-rw-r--r--drivers/dma/bcm2835-dma.c4
-rw-r--r--drivers/dma/edma.c9
-rw-r--r--drivers/dma/iop-adma.c18
-rw-r--r--drivers/firmware/efi/cper.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c3
-rw-r--r--drivers/gpu/drm/drm_edid.c3
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c9
-rw-r--r--drivers/gpu/drm/msm/ekms/edrm_drv.c35
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c2
-rw-r--r--drivers/gpu/msm/adreno_dispatch.c18
-rw-r--r--drivers/hid/hid-apple.c49
-rw-r--r--drivers/hid/hid-core.c55
-rw-r--r--drivers/hid/hid-lg.c22
-rw-r--r--drivers/hid/hid-lg4ff.c1
-rw-r--r--drivers/hid/hid-prodikeys.c12
-rw-r--r--drivers/hid/hidraw.c2
-rw-r--r--drivers/hwmon/acpi_power_meter.c4
-rw-r--r--drivers/i2c/busses/i2c-riic.c1
-rw-r--r--drivers/iio/adc/ad799x.c4
-rw-r--r--drivers/iio/light/opt3001.c6
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c28
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c9
-rw-r--r--drivers/isdn/mISDN/socket.c2
-rw-r--r--drivers/leds/leds-lp5562.c6
-rw-r--r--drivers/md/md.c14
-rw-r--r--drivers/md/raid1.c13
-rw-r--r--drivers/md/raid5.c4
-rw-r--r--drivers/media/i2c/ov9650.c5
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c12
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c3
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c50
-rw-r--r--drivers/media/platform/omap3isp/isp.c8
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c1
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c1
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c1
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c1
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c1
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c5
-rw-r--r--drivers/media/rc/iguanair.c15
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c4
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c8
-rw-r--r--drivers/media/usb/gspca/konica.c5
-rw-r--r--drivers/media/usb/gspca/nw80x.c5
-rw-r--r--drivers/media/usb/gspca/ov519.c10
-rw-r--r--drivers/media/usb/gspca/ov534.c5
-rw-r--r--drivers/media/usb/gspca/ov534_9.c1
-rw-r--r--drivers/media/usb/gspca/se401.c5
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c12
-rw-r--r--drivers/media/usb/gspca/sonixb.c5
-rw-r--r--drivers/media/usb/gspca/sonixj.c5
-rw-r--r--drivers/media/usb/gspca/spca1528.c5
-rw-r--r--drivers/media/usb/gspca/sq930x.c5
-rw-r--r--drivers/media/usb/gspca/sunplus.c5
-rw-r--r--drivers/media/usb/gspca/vc032x.c5
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c5
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c13
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c3
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c2
-rw-r--r--drivers/memstick/host/jmb38x_ms.c2
-rw-r--r--drivers/mfd/intel-lpss-pci.c2
-rw-r--r--drivers/misc/qseecom.c1610
-rw-r--r--drivers/mmc/host/sdhci.c4
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c18
-rw-r--r--drivers/net/arcnet/arcnet.c31
-rw-r--r--drivers/net/can/spi/mcp251x.c19
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c11
-rw-r--r--drivers/net/ethernet/hisilicon/hns_mdio.c6
-rw-r--r--drivers/net/ethernet/marvell/skge.c2
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c13
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c1
-rw-r--r--drivers/net/ieee802154/atusb.c3
-rw-r--r--drivers/net/phy/national.c9
-rw-r--r--drivers/net/usb/cdc_ncm.c6
-rw-r--r--drivers/net/usb/hso.c12
-rw-r--r--drivers/net/usb/usbnet.c8
-rw-r--r--drivers/net/wireless/cnss2/Makefile1
-rw-r--r--drivers/net/wireless/cnss2/bus.c39
-rw-r--r--drivers/net/wireless/cnss2/bus.h3
-rw-r--r--drivers/net/wireless/cnss2/main.c38
-rw-r--r--drivers/net/wireless/cnss2/main.h1
-rw-r--r--drivers/net/wireless/cnss2/pci.c13
-rw-r--r--drivers/net/wireless/cnss2/qmi.c3
-rw-r--r--drivers/net/wireless/cnss2/sdio.c410
-rw-r--r--drivers/net/wireless/cnss2/sdio.h86
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/ps.c6
-rw-r--r--drivers/net/xen-netback/interface.c1
-rw-r--r--drivers/net/xen-netfront.c17
-rw-r--r--drivers/parisc/dino.c24
-rw-r--r--drivers/pci/host/pci-msm.c13
-rw-r--r--drivers/pci/pci.c24
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c4
-rw-r--r--drivers/power/supply/qcom/battery.c14
-rw-r--r--drivers/s390/cio/ccwgroup.c2
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c16
-rw-r--r--drivers/scsi/megaraid.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c4
-rw-r--r--drivers/scsi/scsi_logging.c48
-rw-r--r--drivers/scsi/scsi_sysfs.c11
-rw-r--r--drivers/scsi/ufs/ufshcd.c3
-rw-r--r--drivers/soc/qcom/Kconfig2
-rw-r--r--drivers/soc/qcom/peripheral-loader.c20
-rw-r--r--drivers/soc/qcom/peripheral-loader.h4
-rw-r--r--drivers/soc/qcom/pil-msa.c23
-rw-r--r--drivers/soc/qcom/scm.c70
-rw-r--r--drivers/soc/qcom/subsys-pil-tz.c5
-rw-r--r--drivers/spi/spi_qsd.c8
-rw-r--r--drivers/staging/android/lowmemorykiller.c16
-rw-r--r--drivers/staging/fbtft/fbtft-core.c7
-rw-r--r--drivers/staging/vt6655/device_main.c4
-rw-r--r--drivers/thermal/thermal_core.c2
-rw-r--r--drivers/tty/serial/uartlite.c3
-rw-r--r--drivers/usb/class/usblp.c12
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c3
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c6
-rw-r--r--drivers/usb/host/xhci.c32
-rw-r--r--drivers/usb/image/microtek.c4
-rw-r--r--drivers/usb/misc/Kconfig10
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/adutux.c26
-rw-r--r--drivers/usb/misc/chaoskey.c5
-rw-r--r--drivers/usb/misc/iowarrior.c16
-rw-r--r--drivers/usb/misc/ldusb.c44
-rw-r--r--drivers/usb/misc/legousbtower.c63
-rw-r--r--drivers/usb/misc/rio500.c578
-rw-r--r--drivers/usb/misc/rio500_usb.h37
-rw-r--r--drivers/usb/misc/usblcd.c33
-rw-r--r--drivers/usb/misc/yurex.c18
-rw-r--r--drivers/usb/renesas_usbhs/common.h1
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c2
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h1
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c18
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c15
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h1
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h9
-rw-r--r--drivers/usb/serial/keyspan.c4
-rw-r--r--drivers/usb/serial/option.c11
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c10
-rw-r--r--drivers/usb/serial/usb-serial.c5
-rw-r--r--drivers/usb/usb-skeleton.c15
-rw-r--r--drivers/vfio/pci/vfio_pci.c17
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c9
-rw-r--r--drivers/video/fbdev/ssd1307fb.c2
-rw-r--r--drivers/xen/pci.c21
175 files changed, 2691 insertions, 1821 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 0afd1981e350..43c27c04c40a 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -137,8 +137,10 @@ static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle)
union acpi_object *psd = NULL;
struct acpi_psd_package *pdomain;
- status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer,
- ACPI_TYPE_PACKAGE);
+ status = acpi_evaluate_object_typed(handle, "_PSD", NULL,
+ &buffer, ACPI_TYPE_PACKAGE);
+ if (status == AE_NOT_FOUND) /* _PSD is optional */
+ return 0;
if (ACPI_FAILURE(status))
return -ENODEV;
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index c68e72414a67..435bd0ffc8c0 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -48,8 +48,10 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
if ((*ppos > max_size) ||
(*ppos + count > max_size) ||
(*ppos + count < count) ||
- (count > uncopied_bytes))
+ (count > uncopied_bytes)) {
+ kfree(buf);
return -EINVAL;
+ }
if (copy_from_user(buf + (*ppos), user_buf, count)) {
kfree(buf);
@@ -69,6 +71,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
+ kfree(buf);
return count;
}
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d726b03f19bc..9fa18e8f25ac 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -528,7 +528,8 @@ struct binder_priority {
* @requested_threads_started: number binder threads started
* (protected by @inner_lock)
* @tmp_ref: temporary reference to indicate proc is in use
- * (protected by @inner_lock)
+ * (atomic since @proc->inner_lock cannot
+ * always be acquired)
* @default_priority: default scheduler priority
* (invariant after initialized)
* @debugfs_entry: debugfs node
@@ -562,7 +563,7 @@ struct binder_proc {
int max_threads;
int requested_threads;
int requested_threads_started;
- int tmp_ref;
+ atomic_t tmp_ref;
struct binder_priority default_priority;
struct dentry *debugfs_entry;
struct binder_alloc alloc;
@@ -2053,9 +2054,9 @@ static void binder_thread_dec_tmpref(struct binder_thread *thread)
static void binder_proc_dec_tmpref(struct binder_proc *proc)
{
binder_inner_proc_lock(proc);
- proc->tmp_ref--;
+ atomic_dec(&proc->tmp_ref);
if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) &&
- !proc->tmp_ref) {
+ !atomic_read(&proc->tmp_ref)) {
binder_inner_proc_unlock(proc);
binder_free_proc(proc);
return;
@@ -2117,8 +2118,26 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner(
static void binder_free_transaction(struct binder_transaction *t)
{
- if (t->buffer)
- t->buffer->transaction = NULL;
+ struct binder_proc *target_proc;
+
+ spin_lock(&t->lock);
+ target_proc = t->to_proc;
+ if (target_proc) {
+ atomic_inc(&target_proc->tmp_ref);
+ spin_unlock(&t->lock);
+
+ binder_inner_proc_lock(target_proc);
+ if (t->buffer)
+ t->buffer->transaction = NULL;
+ binder_inner_proc_unlock(target_proc);
+ binder_proc_dec_tmpref(target_proc);
+ } else {
+ /*
+ * If the transaction has no target_proc, then
+ * t->buffer->transaction * has already been cleared.
+ */
+ spin_unlock(&t->lock);
+ }
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
@@ -2871,7 +2890,7 @@ static struct binder_node *binder_get_node_refs_for_txn(
target_node = node;
binder_inc_node_nilocked(node, 1, 0, NULL);
binder_inc_node_tmpref_ilocked(node);
- node->proc->tmp_ref++;
+ atomic_inc(&node->proc->tmp_ref);
*procp = node->proc;
} else
*error = BR_DEAD_REPLY;
@@ -2967,7 +2986,7 @@ static void binder_transaction(struct binder_proc *proc,
goto err_dead_binder;
}
target_proc = target_thread->proc;
- target_proc->tmp_ref++;
+ atomic_inc(&target_proc->tmp_ref);
binder_inner_proc_unlock(target_thread->proc);
} else {
if (tr->target.handle) {
@@ -3700,10 +3719,12 @@ static int binder_thread_write(struct binder_proc *proc,
buffer->debug_id,
buffer->transaction ? "active" : "finished");
+ binder_inner_proc_lock(proc);
if (buffer->transaction) {
buffer->transaction->buffer = NULL;
buffer->transaction = NULL;
}
+ binder_inner_proc_unlock(proc);
if (buffer->async_transaction && buffer->target_node) {
struct binder_node *buf_node;
struct binder_work *w;
@@ -4565,7 +4586,7 @@ static int binder_thread_release(struct binder_proc *proc,
* The corresponding dec is when we actually
* free the thread in binder_free_thread()
*/
- proc->tmp_ref++;
+ atomic_inc(&proc->tmp_ref);
/*
* take a ref on this thread to ensure it
* survives while we are releasing it
@@ -5060,6 +5081,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
return -ENOMEM;
spin_lock_init(&proc->inner_lock);
spin_lock_init(&proc->outer_lock);
+ atomic_set(&proc->tmp_ref, 0);
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
mutex_init(&proc->files_lock);
@@ -5239,7 +5261,7 @@ static void binder_deferred_release(struct binder_proc *proc)
* Make sure proc stays alive after we
* remove all the threads
*/
- proc->tmp_ref++;
+ atomic_inc(&proc->tmp_ref);
proc->is_dead = true;
threads = 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 4e27b3abf5a5..146d8c081695 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -10,6 +10,7 @@
*
*/
+#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fwnode.h>
@@ -2129,6 +2130,8 @@ void device_shutdown(void)
{
struct device *dev, *parent;
+ cpufreq_suspend();
+
spin_lock(&devices_kset->list_lock);
/*
* Walk the devices list backward, shutting down each in turn.
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 75b98aad6faf..84242e6b2897 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -146,6 +146,7 @@ out2:
out1:
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(soc_device_register);
/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
void soc_device_unregister(struct soc_device *soc_dev)
@@ -154,6 +155,7 @@ void soc_device_unregister(struct soc_device *soc_dev)
device_unregister(&soc_dev->dev);
}
+EXPORT_SYMBOL_GPL(soc_device_unregister);
static int __init soc_bus_register(void)
{
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1a1b094da6cb..aa7895f2cf95 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1614,6 +1614,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
case LOOP_SET_FD:
case LOOP_CHANGE_FD:
case LOOP_SET_BLOCK_SIZE:
+ case LOOP_SET_DIRECT_IO:
err = lo_ioctl(bdev, mode, cmd, arg);
break;
default:
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index b0a12e6dae43..fcc12c879659 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -353,6 +353,9 @@ static const struct usb_device_id blacklist_table[] = {
/* Additional Realtek 8822BE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
+ /* Additional Realtek 8822CE Bluetooth devices */
+ { USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK },
+
/* Silicon Wave based devices */
{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index efdff5d16c5d..c603312bae17 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -633,8 +633,8 @@ config MSM_RDBG
for a debugger running on a host PC to communicate with a remote
stub running on peripheral subsystems such as the ADSP, MODEM etc.
-config QCOM_SDIO_CLIENT
- bool "QCOM_SDIO_CLIENT support"
+config QTI_SDIO_CLIENT
+ bool "QTI_SDIO_CLIENT support"
depends on SDIO_QCN
default y
help
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index dc00ba448d20..731f8fdd2ec6 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -67,4 +67,4 @@ ifdef CONFIG_COMPAT
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o
endif
obj-$(CONFIG_MSM_RDBG) += rdbg.o
-obj-$(CONFIG_QCOM_SDIO_CLIENT) += qti_sdio_client.o
+obj-$(CONFIG_QTI_SDIO_CLIENT) += qti_sdio_client.o
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 1bcacb8d83dd..f8a072025e9e 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -25,7 +25,7 @@ endmenu
menu "HSIC/SMUX support for DIAG"
config DIAGFWD_BRIDGE_CODE
- depends on USB_QCOM_DIAG_BRIDGE || MSM_MHI || QCOM_SDIO_CLIENT
+ depends on USB_QCOM_DIAG_BRIDGE || MSM_MHI || QTI_SDIO_CLIENT
default y
bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
help
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 40c5387998b3..b090f228535c 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -3,6 +3,6 @@ obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_bridge.o
obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o
obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.o
-obj-$(CONFIG_QCOM_SDIO_CLIENT) += diagfwd_sdio.o
+obj-$(CONFIG_QTI_SDIO_CLIENT) += diagfwd_sdio.o
diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_smd.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 2301e1e566e0..e9a6711c9990 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -998,6 +998,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
unsigned char *temp = buf;
int save_req_uid = 0;
struct diag_dci_pkt_rsp_header_t pkt_rsp_header;
+ int header_len = sizeof(struct diag_dci_pkt_rsp_header_t);
if (!buf || len <= 0) {
pr_err("diag: Invalid pointer in %s\n", __func__);
@@ -1066,23 +1067,24 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
mutex_lock(&rsp_buf->data_mutex);
/*
* Check if we can fit the data in the rsp buffer. The total length of
- * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int)
- * + field for length (int) + delete_flag (uint8_t)
+ * the rsp is the rsp length (write_len) + dci response packet header
+ * length (sizeof(struct diag_dci_pkt_rsp_header_t))
*/
- if ((rsp_buf->data_len + 9 + rsp_len) > rsp_buf->capacity) {
+ if ((rsp_buf->data_len + header_len + rsp_len) > rsp_buf->capacity) {
pr_alert("diag: create capacity for pkt rsp\n");
- rsp_buf->capacity += 9 + rsp_len;
- temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity,
- GFP_KERNEL);
+ temp_buf = vzalloc(rsp_buf->capacity + header_len + rsp_len);
if (!temp_buf) {
pr_err("diag: DCI realloc failed\n");
mutex_unlock(&rsp_buf->data_mutex);
mutex_unlock(&entry->buffers[data_source].buf_mutex);
mutex_unlock(&driver->dci_mutex);
return;
- } else {
- rsp_buf->data = temp_buf;
}
+ rsp_buf->capacity += header_len + rsp_len;
+ if (rsp_buf->capacity > rsp_buf->data_len)
+ memcpy(temp_buf, rsp_buf->data, rsp_buf->data_len);
+ vfree(rsp_buf->data);
+ rsp_buf->data = temp_buf;
}
/* Fill in packet response header information */
@@ -1091,9 +1093,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
pkt_rsp_header.length = rsp_len + sizeof(int);
pkt_rsp_header.delete_flag = delete_flag;
pkt_rsp_header.uid = save_req_uid;
- memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header,
- sizeof(struct diag_dci_pkt_rsp_header_t));
- rsp_buf->data_len += sizeof(struct diag_dci_pkt_rsp_header_t);
+ memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header, header_len);
+ rsp_buf->data_len += header_len;
memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len);
rsp_buf->data_len += rsp_len;
rsp_buf->data_source = data_source;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index ec3013c5fd85..775a66db30f7 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -901,7 +901,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
goto end;
if (mask_size + write_len > dest_len)
mask_size = dest_len - write_len;
- memcpy(dest_buf + write_len, src_buf + header_len, mask_size);
+ if (mask_size && src_len >= header_len + mask_size)
+ memcpy(dest_buf + write_len, src_buf + header_len, mask_size);
write_len += mask_size;
for (i = 0; i < NUM_PERIPHERALS; i++) {
if (!diag_check_update(i, pid))
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index bfe85d9fd19d..298813917dec 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -43,7 +43,7 @@ static int diag_mhi_init(void)
}
#endif
-#ifndef CONFIG_QCOM_SDIO_CLIENT
+#ifndef CONFIG_QTI_SDIO_CLIENT
static int diag_sdio_init(void)
{
return -EINVAL;
diff --git a/drivers/char/diag/diagfwd_sdio.h b/drivers/char/diag/diagfwd_sdio.h
index 1fa258e901c0..42c300d47c68 100644
--- a/drivers/char/diag/diagfwd_sdio.h
+++ b/drivers/char/diag/diagfwd_sdio.h
@@ -13,7 +13,7 @@
#ifndef DIAGFWD_SDIO_H
#define DIAGFWD_SDIO_H
-#ifdef CONFIG_QCOM_SDIO_CLIENT
+#ifdef CONFIG_QTI_SDIO_CLIENT
#ifdef CONFIG_DIAG_OVER_USB
#include <linux/usb/usbdiag.h>
@@ -52,4 +52,4 @@ int diag_sdio_init(void);
void diag_sdio_exit(void);
#endif
-#endif /*CONFIG_QCOM_SDIO_CLIENT*/
+#endif /*CONFIG_QTI_SDIO_CLIENT*/
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 340f96e44642..bba54422d2ca 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -88,7 +88,7 @@ static void add_early_randomness(struct hwrng *rng)
size_t size = min_t(size_t, 16, rng_buffer_size());
mutex_lock(&reading_mutex);
- bytes_read = rng_get_data(rng, rng_buffer, size, 1);
+ bytes_read = rng_get_data(rng, rng_buffer, size, 0);
mutex_unlock(&reading_mutex);
if (bytes_read > 0)
add_device_randomness(rng_buffer, bytes_read);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 2f9abe0d04dc..2f8ff63bbbe4 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -281,6 +281,9 @@ struct smi_info {
*/
bool irq_enable_broken;
+ /* Is the driver in maintenance mode? */
+ bool in_maintenance_mode;
+
/*
* Did we get an attention that we did not handle?
*/
@@ -1091,11 +1094,20 @@ static int ipmi_thread(void *data)
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
&busy_until);
- if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+ if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
; /* do nothing */
- else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
- schedule();
- else if (smi_result == SI_SM_IDLE) {
+ } else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) {
+ /*
+ * In maintenance mode we run as fast as
+ * possible to allow firmware updates to
+ * complete as fast as possible, but normally
+ * don't bang on the scheduler.
+ */
+ if (smi_info->in_maintenance_mode)
+ schedule();
+ else
+ usleep_range(100, 200);
+ } else if (smi_result == SI_SM_IDLE) {
if (atomic_read(&smi_info->need_watch)) {
schedule_timeout_interruptible(100);
} else {
@@ -1103,8 +1115,9 @@ static int ipmi_thread(void *data)
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
- } else
+ } else {
schedule_timeout_interruptible(1);
+ }
}
return 0;
}
@@ -1283,6 +1296,7 @@ static void set_maintenance_mode(void *send_info, bool enable)
if (!enable)
atomic_set(&smi_info->req_events, 0);
+ smi_info->in_maintenance_mode = enable;
}
static const struct ipmi_smi_handlers handlers = {
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 23f52a897283..6ebe2b86d8eb 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -95,6 +95,13 @@ void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
}
#endif
+static inline bool should_stop_iteration(void)
+{
+ if (need_resched())
+ cond_resched();
+ return fatal_signal_pending(current);
+}
+
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -161,6 +168,8 @@ static ssize_t read_mem(struct file *file, char __user *buf,
p += sz;
count -= sz;
read += sz;
+ if (should_stop_iteration())
+ break;
}
*ppos += read;
@@ -232,6 +241,8 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
p += sz;
count -= sz;
written += sz;
+ if (should_stop_iteration())
+ break;
}
*ppos += written;
@@ -443,6 +454,10 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
read += sz;
low_count -= sz;
count -= sz;
+ if (should_stop_iteration()) {
+ count = 0;
+ break;
+ }
}
}
@@ -467,6 +482,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
buf += sz;
read += sz;
p += sz;
+ if (should_stop_iteration())
+ break;
}
free_page((unsigned long)kbuf);
}
@@ -517,6 +534,8 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
p += sz;
count -= sz;
written += sz;
+ if (should_stop_iteration())
+ break;
}
*ppos += written;
@@ -568,6 +587,8 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
buf += sz;
virtr += sz;
p += sz;
+ if (should_stop_iteration())
+ break;
}
free_page((unsigned long)kbuf);
}
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index a5070f9cb0d4..7244a621c61b 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -540,7 +540,7 @@ static const struct clockgen_chipinfo chipinfo[] = {
.guts_compat = "fsl,qoriq-device-config-1.0",
.init_periph = p5020_init_periph,
.cmux_groups = {
- &p2041_cmux_grp1, &p2041_cmux_grp2
+ &p5020_cmux_grp1, &p5020_cmux_grp2
},
.cmux_to_group = {
0, 1, -1
diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c
index 77e1e2491689..edb7197cc4b4 100644
--- a/drivers/clk/sirf/clk-common.c
+++ b/drivers/clk/sirf/clk-common.c
@@ -298,9 +298,10 @@ static u8 dmn_clk_get_parent(struct clk_hw *hw)
{
struct clk_dmn *clk = to_dmnclk(hw);
u32 cfg = clkc_readl(clk->regofs);
+ const char *name = clk_hw_get_name(hw);
/* parent of io domain can only be pll3 */
- if (strcmp(hw->init->name, "io") == 0)
+ if (strcmp(name, "io") == 0)
return 4;
WARN_ON((cfg & (BIT(3) - 1)) > 4);
@@ -312,9 +313,10 @@ static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent)
{
struct clk_dmn *clk = to_dmnclk(hw);
u32 cfg = clkc_readl(clk->regofs);
+ const char *name = clk_hw_get_name(hw);
/* parent of io domain can only be pll3 */
- if (strcmp(hw->init->name, "io") == 0)
+ if (strcmp(name, "io") == 0)
return -EINVAL;
cfg &= ~(BIT(3) - 1);
@@ -354,7 +356,8 @@ static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate,
{
unsigned long fin;
unsigned ratio, wait, hold;
- unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+ const char *name = clk_hw_get_name(hw);
+ unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4;
fin = *parent_rate;
ratio = fin / rate;
@@ -376,7 +379,8 @@ static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_dmn *clk = to_dmnclk(hw);
unsigned long fin;
unsigned ratio, wait, hold, reg;
- unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+ const char *name = clk_hw_get_name(hw);
+ unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4;
fin = parent_rate;
ratio = fin / rate;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 12c5210eabbc..e8fca2cf056b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2631,14 +2631,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
-/*
- * Stop cpufreq at shutdown to make sure it isn't holding any locks
- * or mutexes when secondary CPUs are halted.
- */
-static struct syscore_ops cpufreq_syscore_ops = {
- .shutdown = cpufreq_suspend,
-};
-
struct kobject *cpufreq_global_kobject;
EXPORT_SYMBOL(cpufreq_global_kobject);
@@ -2650,8 +2642,6 @@ static int __init cpufreq_core_init(void)
cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
BUG_ON(!cpufreq_global_kobject);
- register_syscore_ops(&cpufreq_syscore_ops);
-
return 0;
}
core_initcall(cpufreq_core_init);
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index f2d1fea23fbf..492432dd5cd6 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -75,7 +75,7 @@
#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ)
#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ)
#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ)
-#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ)
+#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 10 * CAAM_CMD_SZ)
/* Note: Nonce is counted in enckeylen */
#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ)
@@ -437,6 +437,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
u32 geniv, moveiv;
u32 ctx1_iv_off = 0;
u32 *desc;
+ u32 *wait_cmd;
const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) ==
OP_ALG_AAI_CTR_MOD128);
const bool is_rfc3686 = alg->caam.rfc3686;
@@ -702,6 +703,14 @@ copy_iv:
/* Will read cryptlen */
append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+
+ /*
+ * Wait for IV transfer (ofifo -> class2) to finish before starting
+ * ciphertext transfer (ofifo -> external memory).
+ */
+ wait_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NIFP);
+ set_jump_tgt_here(desc, wait_cmd);
+
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF |
FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH);
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF);
diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h
index aa1dbeaa9b49..5358162018dd 100644
--- a/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -95,7 +95,7 @@ struct service_hndl {
static inline int get_current_node(void)
{
- return topology_physical_package_id(smp_processor_id());
+ return topology_physical_package_id(raw_smp_processor_id());
}
int adf_service_register(struct service_hndl *service);
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 014745271bb4..1c8857e7db89 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -2730,6 +2730,7 @@ static int talitos_remove(struct platform_device *ofdev)
break;
case CRYPTO_ALG_TYPE_AEAD:
crypto_unregister_aead(&t_alg->algt.alg.aead);
+ break;
case CRYPTO_ALG_TYPE_AHASH:
crypto_unregister_ahash(&t_alg->algt.alg.hash);
break;
diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c
index f31089d63e0c..4c010654204c 100644
--- a/drivers/devfreq/governor_msm_adreno_tz.c
+++ b/drivers/devfreq/governor_msm_adreno_tz.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, 2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -150,6 +150,8 @@ void compute_work_load(struct devfreq_dev_status *stats,
struct devfreq_msm_adreno_tz_data *priv,
struct devfreq *devfreq)
{
+ u64 busy;
+
spin_lock(&sample_lock);
/*
* Keep collecting the stats till the client
@@ -157,8 +159,10 @@ void compute_work_load(struct devfreq_dev_status *stats,
* is done when the entry is read
*/
acc_total += stats->total_time;
- acc_relative_busy += (stats->busy_time * stats->current_frequency) /
- devfreq->profile->freq_table[0];
+ busy = (u64)stats->busy_time * stats->current_frequency;
+ do_div(busy, devfreq->profile->freq_table[0]);
+ acc_relative_busy += busy;
+
spin_unlock(&sample_lock);
}
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 996c4b00d323..d6cdc3be03fc 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -595,8 +595,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- if (rc)
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set DMA mask\n");
return rc;
+ }
od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
if (!od)
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 85674a8d0436..e508c8c5f3fd 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -2218,9 +2218,6 @@ static int edma_probe(struct platform_device *pdev)
ecc->default_queue = info->default_queue;
- for (i = 0; i < ecc->num_slots; i++)
- edma_write_slot(ecc, i, &dummy_paramset);
-
if (info->rsv) {
/* Set the reserved slots in inuse list */
rsv_slots = info->rsv->rsv_slots;
@@ -2233,6 +2230,12 @@ static int edma_probe(struct platform_device *pdev)
}
}
+ for (i = 0; i < ecc->num_slots; i++) {
+ /* Reset only unused - not reserved - paRAM slots */
+ if (!test_bit(i, ecc->slot_inuse))
+ edma_write_slot(ecc, i, &dummy_paramset);
+ }
+
/* Clear the xbar mapped channels in unused list */
xbar_chans = info->xbar_chans;
if (xbar_chans) {
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index e4f43125e0fb..a390415c97a8 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -126,9 +126,9 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
list_for_each_entry_safe(iter, _iter, &iop_chan->chain,
chain_node) {
pr_debug("\tcookie: %d slot: %d busy: %d "
- "this_desc: %#x next_desc: %#x ack: %d\n",
+ "this_desc: %#x next_desc: %#llx ack: %d\n",
iter->async_tx.cookie, iter->idx, busy,
- iter->async_tx.phys, iop_desc_get_next_desc(iter),
+ iter->async_tx.phys, (u64)iop_desc_get_next_desc(iter),
async_tx_test_ack(&iter->async_tx));
prefetch(_iter);
prefetch(&_iter->async_tx);
@@ -316,9 +316,9 @@ retry:
int i;
dev_dbg(iop_chan->device->common.dev,
"allocated slot: %d "
- "(desc %p phys: %#x) slots_per_op %d\n",
+ "(desc %p phys: %#llx) slots_per_op %d\n",
iter->idx, iter->hw_desc,
- iter->async_tx.phys, slots_per_op);
+ (u64)iter->async_tx.phys, slots_per_op);
/* pre-ack all but the last descriptor */
if (num_slots != slots_per_op)
@@ -526,7 +526,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
return NULL;
BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
- dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
+ dev_dbg(iop_chan->device->common.dev, "%s len: %zu\n",
__func__, len);
spin_lock_bh(&iop_chan->lock);
@@ -559,7 +559,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
dev_dbg(iop_chan->device->common.dev,
- "%s src_cnt: %d len: %u flags: %lx\n",
+ "%s src_cnt: %d len: %zu flags: %lx\n",
__func__, src_cnt, len, flags);
spin_lock_bh(&iop_chan->lock);
@@ -592,7 +592,7 @@ iop_adma_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *dma_src,
if (unlikely(!len))
return NULL;
- dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n",
+ dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n",
__func__, src_cnt, len);
spin_lock_bh(&iop_chan->lock);
@@ -630,7 +630,7 @@ iop_adma_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
dev_dbg(iop_chan->device->common.dev,
- "%s src_cnt: %d len: %u flags: %lx\n",
+ "%s src_cnt: %d len: %zu flags: %lx\n",
__func__, src_cnt, len, flags);
if (dmaf_p_disabled_continue(flags))
@@ -693,7 +693,7 @@ iop_adma_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
return NULL;
BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
- dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n",
+ dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n",
__func__, src_cnt, len);
spin_lock_bh(&iop_chan->lock);
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index d42537425438..f40f7df4b734 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -384,6 +384,21 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
printk(
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
+
+ /* Fatal errors call __ghes_panic() before AER handler prints this */
+ if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
+ (gdata->error_severity & CPER_SEV_FATAL)) {
+ struct aer_capability_regs *aer;
+
+ aer = (struct aer_capability_regs *)pcie->aer_info;
+ printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
+ pfx, aer->uncor_status, aer->uncor_mask);
+ printk("%saer_uncor_severity: 0x%08x\n",
+ pfx, aer->uncor_severity);
+ printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
+ aer->header_log.dw0, aer->header_log.dw1,
+ aer->header_log.dw2, aer->header_log.dw3);
+ }
}
static void cper_estatus_print_section(
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index a5c824078472..e35e603710b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -406,6 +406,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
sh_num = 0xffffffff;
+ if (info->read_mmr_reg.count > 128)
+ return -EINVAL;
+
regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
if (!regs)
return -ENOMEM;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d3f3e33230f2..edef90810c84 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -158,6 +158,9 @@ static struct edid_quirk {
/* Medion MD 30217 PG */
{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 },
+ /* Lenovo G50 */
+ { "SDC", 18514, EDID_QUIRK_FORCE_6BPC },
+
/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
{ "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC },
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 81dfc23e1c6a..e83ba7c61d90 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -326,6 +326,9 @@ static void output_poll_execute(struct work_struct *work)
enum drm_connector_status old_status;
bool repoll = false, changed;
+ if (!dev->mode_config.poll_enabled)
+ return;
+
/* Pick up any changes detected by the probe functions. */
changed = dev->mode_config.delayed_event;
dev->mode_config.delayed_event = false;
@@ -489,7 +492,11 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init);
*/
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
- drm_kms_helper_poll_disable(dev);
+ if (!dev->mode_config.poll_enabled)
+ return;
+
+ dev->mode_config.poll_enabled = false;
+ cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
diff --git a/drivers/gpu/drm/msm/ekms/edrm_drv.c b/drivers/gpu/drm/msm/ekms/edrm_drv.c
index 144dd231e428..69b8c01e59d4 100644
--- a/drivers/gpu/drm/msm/ekms/edrm_drv.c
+++ b/drivers/gpu/drm/msm/ekms/edrm_drv.c
@@ -23,9 +23,6 @@
#include "msm_mmu.h"
#include "edrm_kms.h"
-static struct completion wait_display_completion;
-static bool msm_edrm_probed;
-
static int msm_edrm_unload(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
@@ -331,8 +328,6 @@ static int msm_pdev_edrm_probe(struct platform_device *pdev)
struct msm_drm_private *master_priv;
struct msm_kms *master_kms;
- msm_edrm_probed = true;
-
/* main DRM's minor ID is zero */
minor = drm_minor_acquire(0);
if (IS_ERR(minor)) {
@@ -372,7 +367,6 @@ static int msm_pdev_edrm_probe(struct platform_device *pdev)
if (ret)
DRM_ERROR("drm_platform_init failed: %d\n", ret);
- complete(&wait_display_completion);
return ret;
}
@@ -414,20 +408,6 @@ static const struct of_device_id dt_match[] = {
};
MODULE_DEVICE_TABLE(of, dt_match);
-static int find_match(struct device *dev, void *data)
-{
- struct device_driver *drv = data;
-
- return drv->bus->match(dev, drv);
-}
-
-static bool find_device(struct platform_driver *pdrv)
-{
- struct device_driver *drv = &pdrv->driver;
-
- return bus_for_each_dev(drv->bus, NULL, drv, find_match);
-}
-
static struct platform_driver msm_platform_driver = {
.probe = msm_pdev_edrm_probe,
.remove = msm_pdev_edrm_remove,
@@ -443,7 +423,6 @@ static struct platform_driver msm_platform_driver = {
static int __init msm_edrm_register(void)
{
DBG("init");
- init_completion(&wait_display_completion);
return platform_driver_register(&msm_platform_driver);
}
@@ -453,22 +432,8 @@ static void __exit msm_edrm_unregister(void)
platform_driver_unregister(&msm_platform_driver);
}
-static int __init msm_edrm_late_register(void)
-{
- struct platform_driver *pdrv;
-
- pdrv = &msm_platform_driver;
- if (msm_edrm_probed || find_device(pdrv)) {
- pr_debug("wait for eDRM display probe completion\n");
- wait_for_completion(&wait_display_completion);
- }
- return 0;
-}
-
module_init(msm_edrm_register);
module_exit(msm_edrm_unregister);
-/* init level 7 */
-late_initcall(msm_edrm_late_register);
MODULE_DESCRIPTION("MSM EARLY DRM Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 5a9e56b58158..d755ba959c20 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -78,7 +78,12 @@ static ssize_t _sde_hdmi_debugfs_dump_info_read(struct file *file,
if (!buf)
return -ENOMEM;
- len += snprintf(buf, SZ_4K, "name = %s\n", display->name);
+ len += snprintf(buf, SZ_1K, "name = %s\n", display->name);
+
+ if (len > count) {
+ kfree(buf);
+ return -ENOMEM;
+ }
if (copy_to_user(buff, buf, len)) {
kfree(buf);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index c6bf378534f8..bebcef2ce6b8 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -758,7 +758,7 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
radeon_encoder->output_csc = val;
- if (connector->encoder->crtc) {
+ if (connector->encoder && connector->encoder->crtc) {
struct drm_crtc *crtc = connector->encoder->crtc;
const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 002722f75c6c..49b14fbf439c 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1405,6 +1405,22 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
user_ts = *timestamp;
+ /*
+ * If there is only one drawobj in the array and it is of
+ * type SYNCOBJ_TYPE, skip comparing user_ts as it can be 0
+ */
+ if (!(count == 1 && drawobj[0]->type == SYNCOBJ_TYPE) &&
+ (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS)) {
+ /*
+ * User specified timestamps need to be greater than the last
+ * issued timestamp in the context
+ */
+ if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) {
+ spin_unlock(&drawctxt->lock);
+ return -ERANGE;
+ }
+ }
+
for (i = 0; i < count; i++) {
switch (drawobj[i]->type) {
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 37e8b61b5c98..ec4250061922 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -55,7 +55,6 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
struct apple_sc {
unsigned long quirks;
unsigned int fn_on;
- DECLARE_BITMAP(pressed_fn, KEY_CNT);
DECLARE_BITMAP(pressed_numlock, KEY_CNT);
};
@@ -182,6 +181,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
{
struct apple_sc *asc = hid_get_drvdata(hid);
const struct apple_key_translation *trans, *table;
+ bool do_translate;
+ u16 code = 0;
if (usage->code == KEY_FN) {
asc->fn_on = !!value;
@@ -190,8 +191,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
if (fnmode) {
- int do_translate;
-
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys;
@@ -203,25 +202,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
trans = apple_find_translation (table, usage->code);
if (trans) {
- if (test_bit(usage->code, asc->pressed_fn))
- do_translate = 1;
- else if (trans->flags & APPLE_FLAG_FKEY)
- do_translate = (fnmode == 2 && asc->fn_on) ||
- (fnmode == 1 && !asc->fn_on);
- else
- do_translate = asc->fn_on;
-
- if (do_translate) {
- if (value)
- set_bit(usage->code, asc->pressed_fn);
- else
- clear_bit(usage->code, asc->pressed_fn);
-
- input_event(input, usage->type, trans->to,
- value);
-
- return 1;
+ if (test_bit(trans->from, input->key))
+ code = trans->from;
+ else if (test_bit(trans->to, input->key))
+ code = trans->to;
+
+ if (!code) {
+ if (trans->flags & APPLE_FLAG_FKEY) {
+ switch (fnmode) {
+ case 1:
+ do_translate = !asc->fn_on;
+ break;
+ case 2:
+ do_translate = asc->fn_on;
+ break;
+ default:
+ /* should never happen */
+ do_translate = false;
+ }
+ } else {
+ do_translate = asc->fn_on;
+ }
+
+ code = do_translate ? trans->to : trans->from;
}
+
+ input_event(input, usage->type, code, value);
+ return 1;
}
if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7f6c13740f4f..a22881befa27 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -200,13 +200,22 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
* Add a usage to the temporary parser table.
*/
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
{
if (parser->local.usage_index >= HID_MAX_USAGES) {
hid_err(parser->device, "usage index exceeded\n");
return -1;
}
- parser->local.usage[parser->local.usage_index] = usage;
+ if (!parser->local.usage_index && parser->global.usage_page)
+ parser->local.usage_page_preceding = 1;
+ if (parser->local.usage_page_preceding == 2)
+ parser->local.usage_page_preceding = 3;
+ if (size <= 2 && parser->global.usage_page)
+ parser->local.usage[parser->local.usage_index] =
+ (usage & 0xffff) + (parser->global.usage_page << 16);
+ else
+ parser->local.usage[parser->local.usage_index] = usage;
+ parser->local.usage_size[parser->local.usage_index] = size;
parser->local.collection_index[parser->local.usage_index] =
parser->collection_stack_ptr ?
parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
@@ -345,6 +354,8 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
parser->global.usage_page = item_udata(item);
+ if (parser->local.usage_page_preceding == 1)
+ parser->local.usage_page_preceding = 2;
return 0;
case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
@@ -463,10 +474,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- return hid_add_usage(parser, data);
+ return hid_add_usage(parser, data, item->size);
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
@@ -475,9 +483,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
parser->local.usage_minimum = data;
return 0;
@@ -488,9 +493,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
count = data - parser->local.usage_minimum;
if (count + parser->local.usage_index >= HID_MAX_USAGES) {
/*
@@ -510,7 +512,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
}
for (n = parser->local.usage_minimum; n <= data; n++)
- if (hid_add_usage(parser, n)) {
+ if (hid_add_usage(parser, n, item->size)) {
dbg_hid("hid_add_usage failed\n");
return -1;
}
@@ -525,6 +527,29 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
}
/*
+ * Concatenate Usage Pages into Usages where relevant:
+ * As per specification, 6.2.2.8: "When the parser encounters a main item it
+ * concatenates the last declared Usage Page with a Usage to form a complete
+ * usage value."
+ */
+
+static void hid_concatenate_usage_page(struct hid_parser *parser)
+{
+ int i;
+
+ if (parser->local.usage_page_preceding == 3) {
+ dbg_hid("Using preceding usage page for final usage\n");
+ return;
+ }
+
+ for (i = 0; i < parser->local.usage_index; i++)
+ if (parser->local.usage_size[i] <= 2)
+ parser->local.usage[i] =
+ (parser->global.usage_page << 16)
+ + (parser->local.usage[i] & 0xffff);
+}
+
+/*
* Process a main item.
*/
@@ -533,6 +558,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
__u32 data;
int ret;
+ hid_concatenate_usage_page(parser);
+
data = item_udata(item);
switch (item->tag) {
@@ -746,6 +773,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
__u32 data;
int i;
+ hid_concatenate_usage_page(parser);
+
data = item_udata(item);
switch (item->tag) {
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c690fae02cf8..0fd9fc135f3d 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -701,11 +701,16 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
/* Setup wireless link with Logitech Wii wheel */
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
- unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ const unsigned char cbuf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
- ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
- HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_stop;
+ }
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0) {
/* insert a little delay of 10 jiffies ~ 40ms */
wait_queue_head_t wait;
@@ -717,9 +722,10 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
buf[1] = 0xB2;
get_random_bytes(&buf[2], 2);
- ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
+ kfree(buf);
}
if (drv_data->quirks & LG_FF)
@@ -732,9 +738,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = lg4ff_init(hdev);
if (ret)
- goto err_free;
+ goto err_stop;
return 0;
+
+err_stop:
+ hid_hw_stop(hdev);
err_free:
kfree(drv_data);
return ret;
@@ -745,8 +754,7 @@ static void lg_remove(struct hid_device *hdev)
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev);
- else
- hid_hw_stop(hdev);
+ hid_hw_stop(hdev);
kfree(drv_data);
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fbddcb37ae98..dae1b9cdd2e5 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1378,7 +1378,6 @@ int lg4ff_deinit(struct hid_device *hid)
}
}
#endif
- hid_hw_stop(hid);
drv_data->device_props = NULL;
kfree(entry);
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 3a207c0ac0e3..cba15edd47c2 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -556,10 +556,14 @@ static void pcmidi_setup_extra_keys(
static int pcmidi_set_operational(struct pcmidi_snd *pm)
{
+ int rc;
+
if (pm->ifnum != 1)
return 0; /* only set up ONCE for interace 1 */
- pcmidi_get_output_report(pm);
+ rc = pcmidi_get_output_report(pm);
+ if (rc < 0)
+ return rc;
pcmidi_submit_output_report(pm, 0xc1);
return 0;
}
@@ -688,7 +692,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
spin_lock_init(&pm->rawmidi_in_lock);
init_sustain_timers(pm);
- pcmidi_set_operational(pm);
+ err = pcmidi_set_operational(pm);
+ if (err < 0) {
+ pk_error("failed to find output report\n");
+ goto fail_register;
+ }
/* register it */
err = snd_card_register(card);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c0c4df198725..627a24d3ea7c 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -383,7 +383,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&minors_lock);
dev = hidraw_table[minor];
- if (!dev) {
+ if (!dev || !dev->exist) {
ret = -ENODEV;
goto out;
}
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 579bdf93be43..e27f7e12c05b 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -693,8 +693,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
if (resource->caps.flags & POWER_METER_CAN_CAP) {
if (!can_cap_in_hardware()) {
- dev_err(&resource->acpi_dev->dev,
- "Ignoring unsafe software power cap!\n");
+ dev_warn(&resource->acpi_dev->dev,
+ "Ignoring unsafe software power cap!\n");
goto skip_unsafe_cap;
}
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index 16833365475f..a4eceb994f7e 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -212,6 +212,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
/* We got a NACKIE */
readb(riic->base + RIIC_ICDRR); /* dummy read */
+ riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
riic->err = -ENXIO;
} else if (riic->bytes_left) {
return IRQ_NONE;
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index ba82de25a797..46681e399e22 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -822,10 +822,10 @@ static int ad799x_probe(struct i2c_client *client,
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
- goto error_disable_reg;
+ goto error_disable_vref;
ret = ad799x_read_config(st);
if (ret < 0)
- goto error_disable_reg;
+ goto error_disable_vref;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index 01e111e72d4b..eecdc50ed282 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -646,6 +646,7 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
struct iio_dev *iio = _iio;
struct opt3001 *opt = iio_priv(iio);
int ret;
+ bool wake_result_ready_queue = false;
if (!opt->ok_to_ignore_lock)
mutex_lock(&opt->lock);
@@ -680,13 +681,16 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
}
opt->result = ret;
opt->result_ready = true;
- wake_up(&opt->result_ready_queue);
+ wake_result_ready_queue = true;
}
out:
if (!opt->ok_to_ignore_lock)
mutex_unlock(&opt->lock);
+ if (wake_result_ready_queue)
+ wake_up(&opt->result_ready_queue);
+
return IRQ_HANDLED;
}
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 8218d714fa01..4b682375f465 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -254,13 +254,17 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr)
{
int err;
- struct fw_ri_tpte tpt;
+ struct fw_ri_tpte *tpt;
u32 stag_idx;
static atomic_t key;
if (c4iw_fatal_error(rdev))
return -EIO;
+ tpt = kmalloc(sizeof(*tpt), GFP_KERNEL);
+ if (!tpt)
+ return -ENOMEM;
+
stag_state = stag_state > 0;
stag_idx = (*stag) >> 8;
@@ -270,6 +274,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.fail++;
mutex_unlock(&rdev->stats.lock);
+ kfree(tpt);
return -ENOMEM;
}
mutex_lock(&rdev->stats.lock);
@@ -284,28 +289,28 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
/* write TPT entry */
if (reset_tpt_entry)
- memset(&tpt, 0, sizeof(tpt));
+ memset(tpt, 0, sizeof(*tpt));
else {
- tpt.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
+ tpt->valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) |
FW_RI_TPTE_STAGSTATE_V(stag_state) |
FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid));
- tpt.locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
+ tpt->locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
(bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) |
FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO :
FW_RI_VA_BASED_TO))|
FW_RI_TPTE_PS_V(page_size));
- tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
+ tpt->nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3));
- tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
- tpt.va_hi = cpu_to_be32((u32)(to >> 32));
- tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
- tpt.dca_mwbcnt_pstag = cpu_to_be32(0);
- tpt.len_hi = cpu_to_be32((u32)(len >> 32));
+ tpt->len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
+ tpt->va_hi = cpu_to_be32((u32)(to >> 32));
+ tpt->va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
+ tpt->dca_mwbcnt_pstag = cpu_to_be32(0);
+ tpt->len_hi = cpu_to_be32((u32)(len >> 32));
}
err = write_adapter_mem(rdev, stag_idx +
(rdev->lldi.vr->stag.start >> 5),
- sizeof(tpt), &tpt);
+ sizeof(*tpt), tpt);
if (reset_tpt_entry) {
c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
@@ -313,6 +318,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
rdev->stats.stag.cur -= 32;
mutex_unlock(&rdev->stats.lock);
}
+ kfree(tpt);
return err;
}
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 114d5883d497..cf11d43ce241 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1372,14 +1372,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
int i;
+ bitmap_release_region(its_dev->event_map.lpi_map,
+ its_get_event_id(irq_domain_get_irq_data(domain, virq)),
+ get_count_order(nr_irqs));
+
for (i = 0; i < nr_irqs; i++) {
struct irq_data *data = irq_domain_get_irq_data(domain,
virq + i);
- u32 event = its_get_event_id(data);
-
- /* Mark interrupt index as unused */
- clear_bit(event, its_dev->event_map.lpi_map);
-
/* Nuke the entry in the domain */
irq_domain_reset_irq_data(data);
}
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 8cbb75d09a1d..75962c62304d 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -763,6 +763,8 @@ base_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
+ if (!capable(CAP_NET_RAW))
+ return -EPERM;
sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
if (!sk)
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 0360c59dbdc9..fc8b2e7bcfef 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -263,7 +263,11 @@ static void lp5562_firmware_loaded(struct lp55xx_chip *chip)
{
const struct firmware *fw = chip->fw;
- if (fw->size > LP5562_PROGRAM_LENGTH) {
+ /*
+ * the firmware is encoded in ascii hex character, with 2 chars
+ * per byte
+ */
+ if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) {
dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
fw->size);
return;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index dd41ee2ee19d..c7a006e102de 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1667,8 +1667,15 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
if (!(le32_to_cpu(sb->feature_map) &
MD_FEATURE_RECOVERY_BITMAP))
rdev->saved_raid_disk = -1;
- } else
- set_bit(In_sync, &rdev->flags);
+ } else {
+ /*
+ * If the array is FROZEN, then the device can't
+ * be in_sync with rest of array.
+ */
+ if (!test_bit(MD_RECOVERY_FROZEN,
+ &mddev->recovery))
+ set_bit(In_sync, &rdev->flags);
+ }
rdev->raid_disk = role;
break;
}
@@ -8445,7 +8452,8 @@ void md_reap_sync_thread(struct mddev *mddev)
/* resync has finished, collect result */
md_unregister_thread(&mddev->sync_thread);
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+ mddev->degraded != mddev->raid_disks) {
/* success...*/
/* activate any spares */
if (mddev->pers->spare_active(mddev)) {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index b64915a54a02..c2a5378c5e08 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2958,6 +2958,13 @@ static int run(struct mddev *mddev)
!test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
test_bit(Faulty, &conf->mirrors[i].rdev->flags))
mddev->degraded++;
+ /*
+ * RAID1 needs at least one disk in active
+ */
+ if (conf->raid_disks - mddev->degraded < 1) {
+ ret = -EINVAL;
+ goto abort;
+ }
if (conf->raid_disks - mddev->degraded == 1)
mddev->recovery_cp = MaxSector;
@@ -2992,8 +2999,12 @@ static int run(struct mddev *mddev)
ret = md_integrity_register(mddev);
if (ret) {
md_unregister_thread(&mddev->thread);
- raid1_free(mddev, conf);
+ goto abort;
}
+ return 0;
+
+abort:
+ raid1_free(mddev, conf);
return ret;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 38e62418c6ff..8d712a939a7b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2394,7 +2394,9 @@ static void raid5_end_read_request(struct bio * bi)
&& !test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
retry = 1;
if (retry)
- if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) {
+ if (sh->qd_idx >= 0 && sh->pd_idx == i)
+ set_bit(R5_ReadError, &sh->dev[i].flags);
+ else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) {
set_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReadNoMerge, &sh->dev[i].flags);
} else
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 1ee6a5527c38..d11de02ecb63 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -707,6 +707,11 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain)
for (m = 6; m >= 0; m--)
if (gain >= (1 << m) * 16)
break;
+
+ /* Sanity check: don't adjust the gain with a negative value */
+ if (m < 0)
+ return -EINVAL;
+
rgain = (gain - ((1 << m) * 16)) / (1 << m);
rgain |= (((1 << m) - 1) << 4);
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index bc957528f69f..e636fca36e3d 100644
--- a/drivers/media/pci/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -355,7 +355,11 @@ static struct i2c_client saa7134_client_template = {
/* ----------------------------------------------------------- */
-/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */
+/*
+ * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T
+ * demod i2c gate closed due to an address clash between this EEPROM
+ * and the demod one.
+ */
static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev)
{
u8 subaddr = 0x7, dmdregval;
@@ -372,14 +376,14 @@ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev)
ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2);
if ((ret == 2) && (dmdregval & 0x2)) {
- pr_debug("%s: DVB-T demod i2c gate was left closed\n",
+ pr_debug("%s: DVB-T demod i2c gate was left open\n",
dev->name);
data[0] = subaddr;
data[1] = (dmdregval & ~0x2);
if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1)
- pr_err("%s: EEPROM i2c gate open failure\n",
- dev->name);
+ pr_err("%s: EEPROM i2c gate close failure\n",
+ dev->name);
}
}
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index d4b3ce828285..343cd75fcd8d 100644
--- a/drivers/media/pci/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -304,6 +304,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
if (ret < 0) {
pr_err("cannot register capture v4l2 device. skipping.\n");
+ saa7146_vv_release(dev);
+ i2c_del_adapter(&hexium->i2c_adapter);
+ kfree(hexium);
return ret;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 83abaea1fa44..d75af08846cd 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1498,8 +1498,6 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
uint32_t i;
int rc = -1;
- int counter = 0;
- u32 result = 0;
struct cpp_device *cpp_dev = NULL;
struct msm_device_queue *processing_q = NULL;
struct msm_device_queue *eventData_q = NULL;
@@ -1581,54 +1579,6 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
pr_debug("DEBUG_R1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
- /* mask IRQ status */
- msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC);
-
- /* clear IRQ status */
- msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14);
-
- /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
- msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C);
-
- while (counter < MSM_CPP_POLL_RETRIES) {
- result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
- if (result & 0x2)
- break;
- /*
- * Below usleep values are chosen based on experiments
- * and this was the smallest number which works. This
- * sleep is needed to leave enough time for hardware
- * to update status register.
- */
- usleep_range(200, 250);
- counter++;
- }
-
- pr_debug("CPP AXI done counter %d result 0x%x\n",
- counter, result);
-
- /* clear IRQ status */
- msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14);
- counter = 0;
- /* MMSS_A_CPP_RST_CMD_0 = 0x8, firmware reset = 0x3DF77 */
- msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8);
-
- while (counter < MSM_CPP_POLL_RETRIES) {
- result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
- if (result & 0x1)
- break;
- /*
- * Below usleep values are chosen based on experiments
- * and this was the smallest number which works. This
- * sleep is needed to leave enough time for hardware
- * to update status register.
- */
- usleep_range(200, 250);
- counter++;
- }
- pr_debug("CPP reset done counter %d result 0x%x\n",
- counter, result);
-
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
msm_cpp_clear_timer(cpp_dev);
cpp_release_hardware(cpp_dev);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 136ea1848701..f41e0d08de93 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -917,6 +917,10 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
s_stream, mode);
pipe->do_propagation = true;
}
+
+ /* Stop at the first external sub-device. */
+ if (subdev->dev != isp->dev)
+ break;
}
return 0;
@@ -1031,6 +1035,10 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
isp->crashed |= 1U << subdev->entity.id;
failure = -ETIMEDOUT;
}
+
+ /* Stop at the first external sub-device. */
+ if (subdev->dev != isp->dev)
+ break;
}
return failure;
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index a6a61cce43dd..e349f5d990b7 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -2603,6 +2603,7 @@ int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
int ret;
/* Register the subdev and video node. */
+ ccdc->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 38e6a974c5b1..e6b19b785c2f 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -1025,6 +1025,7 @@ int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
int ret;
/* Register the subdev and video nodes. */
+ ccp2->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index a78338d012b4..029b434b7609 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1201,6 +1201,7 @@ int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
int ret;
/* Register the subdev and video nodes. */
+ csi2->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 13803270d104..c9e8845de1b1 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -2223,6 +2223,7 @@ int omap3isp_preview_register_entities(struct isp_prev_device *prev,
int ret;
/* Register the subdev and video nodes. */
+ prev->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &prev->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 7cfb43dc0ffd..d4e53cbe9193 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -1679,6 +1679,7 @@ int omap3isp_resizer_register_entities(struct isp_res_device *res,
int ret;
/* Register the subdev and video nodes. */
+ res->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &res->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index 94d4c295d3d0..c54c5c494b75 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1010,6 +1010,8 @@ void omap3isp_stat_unregister_entities(struct ispstat *stat)
int omap3isp_stat_register_entities(struct ispstat *stat,
struct v4l2_device *vdev)
{
+ stat->subdev.dev = vdev->mdev->dev;
+
return v4l2_device_register_subdev(vdev, &stat->subdev);
}
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 091d793f6583..c9347d5aac04 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -743,7 +743,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* start radio */
retval = si470x_start_usb(radio);
if (retval < 0)
- goto err_all;
+ goto err_buf;
/* set initial frequency */
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
@@ -758,6 +758,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
return 0;
err_all:
+ usb_kill_urb(radio->int_in_urb);
+err_buf:
kfree(radio->buffer);
err_ctrl:
v4l2_ctrl_handler_free(&radio->hdl);
@@ -831,6 +833,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
mutex_lock(&radio->lock);
v4l2_device_disconnect(&radio->v4l2_dev);
video_unregister_device(&radio->videodev);
+ usb_kill_urb(radio->int_in_urb);
usb_set_intfdata(intf, NULL);
mutex_unlock(&radio->lock);
v4l2_device_put(&radio->v4l2_dev);
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index ee60e17fba05..cda4ce612dcf 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -430,6 +430,10 @@ static int iguanair_probe(struct usb_interface *intf,
int ret, pipein, pipeout;
struct usb_host_interface *idesc;
+ idesc = intf->altsetting;
+ if (idesc->desc.bNumEndpoints < 2)
+ return -ENODEV;
+
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
rc = rc_allocate_device();
if (!ir || !rc) {
@@ -444,18 +448,13 @@ static int iguanair_probe(struct usb_interface *intf,
ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
ir->urb_out = usb_alloc_urb(0, GFP_KERNEL);
- if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) {
+ if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out ||
+ !usb_endpoint_is_int_in(&idesc->endpoint[0].desc) ||
+ !usb_endpoint_is_int_out(&idesc->endpoint[1].desc)) {
ret = -ENOMEM;
goto out;
}
- idesc = intf->altsetting;
-
- if (idesc->desc.bNumEndpoints < 2) {
- ret = -ENODEV;
- goto out;
- }
-
ir->rc = rc;
ir->dev = &intf->dev;
ir->udev = udev;
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index 41ea00ac3a87..76b9cb940b87 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -665,6 +665,10 @@ static int submit_urbs(struct camera_data *cam)
ERR("%s: usb_alloc_urb error!\n", __func__);
for (j = 0; j < i; j++)
usb_free_urb(cam->sbuf[j].urb);
+ for (j = 0; j < NUM_SBUF; j++) {
+ kfree(cam->sbuf[j].data);
+ cam->sbuf[j].data = NULL;
+ }
return -ENOMEM;
}
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 38c03283a441..e1316c7b7c2e 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -2418,9 +2418,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
8, 0x0486,
};
+ if (!IS_ENABLED(CONFIG_DVB_DIB9000))
+ return -ENODEV;
if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL)
return -ENODEV;
i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+ if (!i2c)
+ return -ENODEV;
if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
return -ENODEV;
dib0700_set_i2c_speed(adap->dev, 1500);
@@ -2496,10 +2500,14 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
0, 0x00ef,
8, 0x0406,
};
+ if (!IS_ENABLED(CONFIG_DVB_DIB9000))
+ return -ENODEV;
i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
return -ENODEV;
i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+ if (!i2c)
+ return -ENODEV;
if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
return -ENODEV;
diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c
index 0f6d57fbf91b..624b4d24716d 100644
--- a/drivers/media/usb/gspca/konica.c
+++ b/drivers/media/usb/gspca/konica.c
@@ -127,6 +127,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index)
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, 2);
}
}
diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c
index 599f755e75b8..7ebeee98dc1b 100644
--- a/drivers/media/usb/gspca/nw80x.c
+++ b/drivers/media/usb/gspca/nw80x.c
@@ -1584,6 +1584,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
return;
}
if (len == 1)
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index c95f32a0c02b..c7aafdbb5738 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -2116,6 +2116,11 @@ static int reg_r(struct sd *sd, u16 index)
} else {
PERR("reg_r %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
+ /*
+ * Make sure the result is zeroed to avoid uninitialized
+ * values.
+ */
+ gspca_dev->usb_buf[0] = 0;
}
return ret;
@@ -2142,6 +2147,11 @@ static int reg_r8(struct sd *sd,
} else {
PERR("reg_r8 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, 8);
}
return ret;
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index bfff1d1c70ab..466f984312dd 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -644,6 +644,11 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
if (ret < 0) {
pr_err("read failed %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the result is zeroed to avoid uninitialized
+ * values.
+ */
+ gspca_dev->usb_buf[0] = 0;
}
return gspca_dev->usb_buf[0];
}
diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c
index 47085cf2d723..f2dca0606935 100644
--- a/drivers/media/usb/gspca/ov534_9.c
+++ b/drivers/media/usb/gspca/ov534_9.c
@@ -1157,6 +1157,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ return 0;
}
return gspca_dev->usb_buf[0];
}
diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c
index 5102cea50471..6adbb0eca71f 100644
--- a/drivers/media/usb/gspca/se401.c
+++ b/drivers/media/usb/gspca/se401.c
@@ -115,6 +115,11 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent)
pr_err("read req failed req %#04x error %d\n",
req, err);
gspca_dev->usb_err = err;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, READ_REQ_SIZE);
}
}
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index d0ee899584a9..6136eb683306 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -139,6 +139,13 @@ static const struct dmi_system_id flip_dmi_table[] = {
}
},
{
+ .ident = "MSI MS-1039",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1039"),
+ }
+ },
+ {
.ident = "MSI MS-1632",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
@@ -924,6 +931,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
if (unlikely(result < 0 || result != length)) {
pr_err("Read register %02x failed %d\n", reg, result);
gspca_dev->usb_err = result;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index 6696b2ec34e9..83e98b85ab6a 100644
--- a/drivers/media/usb/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
@@ -466,6 +466,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
dev_err(gspca_dev->v4l2_dev.dev,
"Error reading register %02x: %d\n", value, res);
gspca_dev->usb_err = res;
+ /*
+ * Make sure the result is zeroed to avoid uninitialized
+ * values.
+ */
+ gspca_dev->usb_buf[0] = 0;
}
}
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index fd1c8706d86a..67e23557a1a9 100644
--- a/drivers/media/usb/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
@@ -1175,6 +1175,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c
index f38fd8949609..ee93bd443df5 100644
--- a/drivers/media/usb/gspca/spca1528.c
+++ b/drivers/media/usb/gspca/spca1528.c
@@ -84,6 +84,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c
index e274cf19a3ea..b236e9dcd468 100644
--- a/drivers/media/usb/gspca/sq930x.c
+++ b/drivers/media/usb/gspca/sq930x.c
@@ -438,6 +438,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r %04x failed %d\n", value, ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index 46c9f2229a18..cc3e1478c5a0 100644
--- a/drivers/media/usb/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
@@ -268,6 +268,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c
index b4efb2fb36fa..5032b9d7d9bb 100644
--- a/drivers/media/usb/gspca/vc032x.c
+++ b/drivers/media/usb/gspca/vc032x.c
@@ -2919,6 +2919,11 @@ static void reg_r_i(struct gspca_dev *gspca_dev,
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
}
}
static void reg_r(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c
index fb9fe2ef3a6f..a74ac595656f 100644
--- a/drivers/media/usb/gspca/w996Xcf.c
+++ b/drivers/media/usb/gspca/w996Xcf.c
@@ -139,6 +139,11 @@ static int w9968cf_read_sb(struct sd *sd)
} else {
pr_err("Read SB reg [01] failed\n");
sd->gspca_dev.usb_err = ret;
+ /*
+ * Make sure the buffer is zeroed to avoid uninitialized
+ * values.
+ */
+ memset(sd->gspca_dev.usb_buf, 0, 2);
}
udelay(W9968CF_I2C_BUS_DELAY);
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 08f0ca7aa012..7b5c493f02b0 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -143,6 +143,7 @@ static int device_authorization(struct hdpvr_device *dev)
dev->fw_ver = dev->usbc_buf[1];
+ dev->usbc_buf[46] = '\0';
v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
dev->fw_ver, &dev->usbc_buf[2]);
@@ -278,6 +279,7 @@ static int hdpvr_probe(struct usb_interface *interface,
#endif
size_t buffer_size;
int i;
+ int dev_num;
int retval = -ENOMEM;
/* allocate memory for our device state and initialize it */
@@ -386,8 +388,17 @@ static int hdpvr_probe(struct usb_interface *interface,
}
#endif
+ dev_num = atomic_inc_return(&dev_nr);
+ if (dev_num >= HDPVR_MAX) {
+ v4l2_err(&dev->v4l2_dev,
+ "max device number reached, device register failed\n");
+ atomic_dec(&dev_nr);
+ retval = -ENODEV;
+ goto reg_fail;
+ }
+
retval = hdpvr_register_videodev(dev, &interface->dev,
- video_nr[atomic_inc_return(&dev_nr)]);
+ video_nr[dev_num]);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
goto reg_fail;
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index c21c4c004f97..17ee9cde4156 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -642,8 +642,7 @@ static int v4l_stk_release(struct file *fp)
dev->owner = NULL;
}
- if (is_present(dev))
- usb_autopm_put_interface(dev->interface);
+ usb_autopm_put_interface(dev->interface);
mutex_unlock(&dev->lock);
return v4l2_fh_release(fp);
}
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index a5de46f04247..f9b5de7ace01 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -272,7 +272,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
dprintk("%s\n", __func__);
- b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
+ b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
if (!b)
return -ENOMEM;
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 48db922075e2..08fa6400d255 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -947,7 +947,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev,
if (!cnt) {
rc = -ENODEV;
pci_dev_busy = 1;
- goto err_out;
+ goto err_out_int;
}
jm = kzalloc(sizeof(struct jmb38x_ms)
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 5bfdfccbb9a1..032c95157497 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -38,6 +38,8 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
info->mem = &pdev->resource[0];
info->irq = pdev->irq;
+ pdev->d3cold_delay = 0;
+
/* Probably it is enough to set this for iDMA capable devices only */
pci_set_master(pdev);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index dfa3bb6b186f..21ad3dc3abaa 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,4 +1,5 @@
-/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+/*
+ * QTI Secure Execution Environment Communicator (QSEECOM) driver
*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
@@ -43,13 +44,13 @@
#include <linux/msm-bus-board.h>
#include <soc/qcom/qseecomi.h>
#include <asm/cacheflush.h>
-#include "qseecom_legacy.h"
#include "qseecom_kernel.h"
#include <crypto/ice.h>
#include <linux/delay.h>
#include <linux/compat.h>
#include "compat_qseecom.h"
+#include <linux/kthread.h>
#define QSEECOM_DEV "qseecom"
#define QSEOS_VERSION_14 0x14
@@ -65,7 +66,7 @@
#define QSEE_CE_CLK_100MHZ 100000000
#define CE_CLK_DIV 1000000
-#define QSEECOM_MAX_SG_ENTRY 512
+#define QSEECOM_MAX_SG_ENTRY 4096
#define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \
(QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT)
@@ -100,6 +101,10 @@
#define QSEECOM_STATE_READY 2
#define QSEECOM_ICE_FDE_KEY_SIZE_MASK 2
+#define QSEECOM_SCM_EBUSY_WAIT_MS 30
+#define QSEECOM_SCM_EBUSY_MAX_RETRY 67
+#define QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT 33
+
/*
* default ce info unit to 0 for
* services which
@@ -109,6 +114,9 @@
#define DEFAULT_CE_INFO_UNIT 0
#define DEFAULT_NUM_CE_INFO_UNIT 1
+#define FDE_FLAG_POS 4
+#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS)
+
enum qseecom_clk_definitions {
CLK_DFAB = 0,
CLK_SFPB,
@@ -137,12 +145,25 @@ enum qseecom_ce_hw_instance {
CLK_INVALID,
};
+enum qseecom_listener_unregister_kthread_state {
+ LSNR_UNREG_KT_SLEEP = 0,
+ LSNR_UNREG_KT_WAKEUP,
+};
+
+enum qseecom_unload_app_kthread_state {
+ UNLOAD_APP_KT_SLEEP = 0,
+ UNLOAD_APP_KT_WAKEUP,
+};
+
static struct class *driver_class;
static dev_t qseecom_device_no;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+static DEFINE_MUTEX(listener_access_lock);
+static DEFINE_MUTEX(unload_app_pending_list_lock);
+
struct sglist_info {
uint32_t indexAndFlags;
@@ -182,13 +203,21 @@ struct qseecom_registered_listener_list {
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
wait_queue_head_t rcv_req_wq;
+ /* rcv_req_flag: 0: ready and empty; 1: received req */
int rcv_req_flag;
int send_resp_flag;
bool listener_in_use;
/* wq for thread blocked on this listener*/
wait_queue_head_t listener_block_app_wq;
- struct sglist_info sglistinfo_ptr[MAX_ION_FD];
- uint32_t sglist_cnt;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ int abort;
+ bool unregister_pending;
+};
+
+struct qseecom_unregister_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_registered_app_list {
@@ -198,6 +227,7 @@ struct qseecom_registered_app_list {
char app_name[MAX_APP_NAME_SIZE];
u32 app_arch;
bool app_blocked;
+ u32 check_block;
u32 blocked_on_listener_id;
};
@@ -235,7 +265,6 @@ struct qseecom_clk {
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
- spinlock_t registered_listener_list_lock;
struct list_head registered_app_list_head;
spinlock_t registered_app_list_lock;
@@ -275,12 +304,29 @@ struct qseecom_control {
unsigned int ce_opp_freq_hz;
bool appsbl_qseecom_support;
uint32_t qsee_reentrancy_support;
+ bool enable_key_wrap_in_ks;
uint32_t app_block_ref_cnt;
wait_queue_head_t app_block_wq;
atomic_t qseecom_state;
int is_apps_region_protected;
bool smcinvoke_support;
+
+ struct list_head unregister_lsnr_pending_list_head;
+ wait_queue_head_t register_lsnr_pending_wq;
+ struct task_struct *unregister_lsnr_kthread_task;
+ wait_queue_head_t unregister_lsnr_kthread_wq;
+ atomic_t unregister_lsnr_kthread_state;
+
+ struct list_head unload_app_pending_list_head;
+ struct task_struct *unload_app_kthread_task;
+ wait_queue_head_t unload_app_kthread_wq;
+ atomic_t unload_app_kthread_state;
+};
+
+struct qseecom_unload_app_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_sec_buf_fd_info {
@@ -305,10 +351,14 @@ struct qseecom_client_handle {
char app_name[MAX_APP_NAME_SIZE];
u32 app_arch;
struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD];
+ bool from_smcinvoke;
+ bool unload_pending;
};
struct qseecom_listener_handle {
u32 id;
+ bool unregister_pending;
+ bool release_called;
};
static struct qseecom_control qseecom;
@@ -380,6 +430,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data,
void __user *argp);
static int qseecom_query_ce_info(struct qseecom_dev_handle *data,
void __user *argp);
+static int __qseecom_unload_app(struct qseecom_dev_handle *data,
+ uint32_t app_id);
static int get_qseecom_keymaster_status(char *str)
{
@@ -388,6 +440,25 @@ static int get_qseecom_keymaster_status(char *str)
}
__setup("androidboot.keymaster=", get_qseecom_keymaster_status);
+static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc)
+{
+ int ret = 0;
+ int retry_count = 0;
+
+ do {
+ ret = scm_call2_noretry(smc_id, desc);
+ if (ret == -EBUSY) {
+ mutex_unlock(&app_access_lock);
+ msleep(QSEECOM_SCM_EBUSY_WAIT_MS);
+ mutex_lock(&app_access_lock);
+ }
+ if (retry_count == QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT)
+ pr_warn("secure world has been busy for 1 second!\n");
+ } while (ret == -EBUSY &&
+ (retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY));
+ return ret;
+}
+
static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
const void *req_buf, void *resp_buf)
{
@@ -415,7 +486,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
svc_id, tz_cmd_id);
return -EINVAL;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case SCM_SVC_ES: {
@@ -426,10 +497,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_save_partition_hash_req *)
req_buf;
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("error allocating data\n");
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, p_hash_req->digest,
SHA256_DIGEST_LENGTH);
@@ -439,7 +509,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = p_hash_req->partition_id;
desc.args[1] = virt_to_phys(tzbuf);
desc.args[2] = SHA256_DIGEST_LENGTH;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -457,6 +527,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
case QSEOS_APP_START_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_APP_START_ID;
desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -473,11 +544,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_APP_SHUTDOWN_COMMAND: {
struct qseecom_unload_app_ireq *req;
+
req = (struct qseecom_unload_app_ireq *)req_buf;
smc_id = TZ_OS_APP_SHUTDOWN_ID;
desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
@@ -489,11 +561,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
struct qseecom_check_app_ireq *req;
u32 tzbuflen = PAGE_ALIGN(sizeof(req->app_name));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
req = (struct qseecom_check_app_ireq *)req_buf;
pr_debug("Lookup app_name = %s\n", req->app_name);
strlcpy(tzbuf, req->app_name, sizeof(req->app_name));
@@ -503,13 +573,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = strlen(req->app_name);
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
case QSEOS_APP_REGION_NOTIFICATION: {
struct qsee_apps_region_info_ireq *req;
struct qsee_apps_region_info_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID;
desc.arginfo =
TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID;
@@ -526,12 +597,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[1] = req_64bit->size;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LOAD_SERV_IMAGE_COMMAND: {
struct qseecom_load_lib_image_ireq *req;
struct qseecom_load_lib_image_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID;
desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -549,19 +621,20 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: {
smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_REGISTER_LISTENER: {
struct qseecom_register_listener_ireq *req;
struct qseecom_register_listener_64bit_ireq *req_64bit;
+
desc.arginfo =
TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -580,30 +653,29 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
}
qseecom.smcinvoke_support = true;
smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
- if (ret) {
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
+ if (ret == -EIO) {
+ /* smcinvoke is not supported */
qseecom.smcinvoke_support = false;
smc_id = TZ_OS_REGISTER_LISTENER_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(
- smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
}
break;
}
case QSEOS_DEREGISTER_LISTENER: {
struct qseecom_unregister_listener_ireq *req;
+
req = (struct qseecom_unregister_listener_ireq *)
req_buf;
smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LISTENER_DATA_RSP_COMMAND: {
struct qseecom_client_listener_data_irsp *req;
+
req = (struct qseecom_client_listener_data_irsp *)
req_buf;
smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID;
@@ -611,7 +683,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
desc.args[1] = req->status;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
@@ -639,12 +711,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64->sglistinfo_ptr;
desc.args[3] = req_64->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_LOAD_EXTERNAL_IMAGE_ID;
desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -660,20 +733,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: {
smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID;
desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CLIENT_SEND_DATA_COMMAND: {
struct qseecom_client_send_data_ireq *req;
struct qseecom_client_send_data_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_QSAPP_SEND_DATA_ID;
desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -694,7 +768,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->rsp_ptr;
desc.args[4] = req_64bit->rsp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
@@ -726,32 +800,33 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
struct qseecom_client_send_service_ireq *req;
+
req = (struct qseecom_client_send_service_ireq *)
req_buf;
smc_id = TZ_OS_RPMB_PROVISION_KEY_ID;
desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
desc.args[0] = req->key_type;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_ERASE_COMMAND: {
smc_id = TZ_OS_RPMB_ERASE_ID;
desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: {
smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID;
desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_GENERATE_KEY: {
@@ -759,6 +834,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_generate_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
+
if (!tzbuf)
return -ENOMEM;
memset(tzbuf, 0, tzbuflen);
@@ -771,7 +847,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -780,11 +856,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_delete_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t),
(sizeof(struct qseecom_key_delete_ireq) -
@@ -795,7 +869,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -804,11 +878,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_select_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t),
(sizeof(struct qseecom_key_select_ireq) -
@@ -819,7 +891,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -828,11 +900,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_userinfo_update_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof
(struct qseecom_key_userinfo_update_ireq) -
@@ -843,13 +913,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
case QSEOS_TEE_OPEN_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_OPEN_SESSION_ID;
desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -868,7 +939,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
@@ -898,12 +969,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_INVOKE_COMMAND: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_ID;
desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -922,7 +994,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
@@ -952,12 +1024,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_CLOSE_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_CLOSE_SESSION_ID;
desc.arginfo = TZ_APP_GPAPP_CLOSE_SESSION_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -976,12 +1049,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_REQUEST_CANCELLATION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID;
desc.arginfo =
TZ_APP_GPAPP_REQUEST_CANCELLATION_ID_PARAM_ID;
@@ -1001,7 +1075,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: {
@@ -1016,11 +1090,11 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.arginfo =
TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID;
desc.args[0] = req->app_or_session_id;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
default: {
- pr_err("qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n",
+ pr_err("qseos_cmd_id %d is not supported by armv8 scm_call2.\n",
qseos_cmd_id);
ret = -EINVAL;
break;
@@ -1056,42 +1130,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf,
return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf);
}
-static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
- struct qseecom_register_listener_req *svc)
-{
- struct qseecom_registered_listener_list *ptr;
- int unique = 1;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
- if (ptr->svc.listener_id == svc->listener_id) {
- pr_err("Service id: %u is already registered\n",
- ptr->svc.listener_id);
- unique = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
- return unique;
-}
-
static struct qseecom_registered_listener_list *__qseecom_find_svc(
int32_t listener_id)
{
struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
- {
+ list_for_each_entry(entry,
+ &qseecom.registered_listener_list_head, list) {
if (entry->svc.listener_id == listener_id)
break;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
- pr_err("Service id: %u is not found\n", listener_id);
+ pr_debug("Service id: %u is not found\n", listener_id);
return NULL;
}
@@ -1151,8 +1201,14 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
resp.result = QSEOS_RESULT_INCOMPLETE;
+ mutex_unlock(&listener_access_lock);
+ mutex_lock(&app_access_lock);
+ __qseecom_reentrancy_check_if_no_app_blocked(
+ TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("qseecom_scm_call failed with err: %d\n", ret);
return -EINVAL;
@@ -1170,9 +1226,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
void __user *argp)
{
int ret = 0;
- unsigned long flags;
struct qseecom_register_listener_req rcvd_lstnr;
struct qseecom_registered_listener_list *new_entry;
+ struct qseecom_registered_listener_list *ptr_svc;
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
if (ret) {
@@ -1183,18 +1239,33 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
rcvd_lstnr.sb_size))
return -EFAULT;
- data->listener.id = 0;
- if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
- pr_err("Service is not unique and is already registered\n");
- data->released = true;
- return -EBUSY;
+ ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
+ if (ptr_svc) {
+ if (ptr_svc->unregister_pending == false) {
+ pr_err("Service %d is not unique\n",
+ rcvd_lstnr.listener_id);
+ data->released = true;
+ return -EBUSY;
+ }
+ /*wait until listener is unregistered*/
+ pr_debug("register %d has to wait\n",
+ rcvd_lstnr.listener_id);
+ mutex_unlock(&listener_access_lock);
+ ret = wait_event_interruptible(
+ qseecom.register_lsnr_pending_wq,
+ list_empty(
+ &qseecom.unregister_lsnr_pending_list_head));
+ if (ret) {
+ pr_err("interrupted register_pending_wq %d\n",
+ rcvd_lstnr.listener_id);
+ mutex_lock(&listener_access_lock);
+ return -ERESTARTSYS;
+ }
+ mutex_lock(&listener_access_lock);
}
-
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
- if (!new_entry) {
- pr_err("kmalloc failed\n");
+ if (!new_entry)
return -ENOMEM;
- }
memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
new_entry->rcv_req_flag = 0;
@@ -1202,30 +1273,28 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
new_entry->sb_length = rcvd_lstnr.sb_size;
new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
- pr_err("qseecom_set_sb_memoryfailed\n");
+ pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n",
+ rcvd_lstnr.listener_id, rcvd_lstnr.sb_size);
kzfree(new_entry);
return -ENOMEM;
}
- data->listener.id = rcvd_lstnr.listener_id;
init_waitqueue_head(&new_entry->rcv_req_wq);
init_waitqueue_head(&new_entry->listener_block_app_wq);
new_entry->send_resp_flag = 0;
new_entry->listener_in_use = false;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+ data->listener.id = rcvd_lstnr.listener_id;
+ pr_debug("Service %d is registered\n", rcvd_lstnr.listener_id);
return ret;
}
-static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret = 0;
- unsigned long flags;
- uint32_t unmap_mem = 0;
struct qseecom_register_listener_ireq req;
- struct qseecom_registered_listener_list *ptr_svc = NULL;
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
@@ -1233,68 +1302,157 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
req.listener_id = data->listener.id;
resp.result = QSEOS_RESULT_INCOMPLETE;
+ mutex_unlock(&listener_access_lock);
+ mutex_lock(&app_access_lock);
+ __qseecom_reentrancy_check_if_no_app_blocked(
+ TZ_OS_DEREGISTER_LISTENER_ID);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
ret, data->listener.id);
- return ret;
+ if (ret == -EBUSY)
+ return ret;
+ goto exit;
}
if (resp.result != QSEOS_RESULT_SUCCESS) {
pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
resp.result, data->listener.id);
- return -EPERM;
- }
-
- data->abort = 1;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
- list) {
- if (ptr_svc->svc.listener_id == data->listener.id) {
- wake_up_all(&ptr_svc->rcv_req_wq);
- break;
- }
+ ret = -EPERM;
+ goto exit;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
while (atomic_read(&data->ioctl_count) > 1) {
- if (wait_event_freezable(data->abort_wq,
+ if (wait_event_interruptible(data->abort_wq,
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
- return ret;
}
}
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr_svc,
- &qseecom.registered_listener_list_head,
- list)
- {
- if (ptr_svc->svc.listener_id == data->listener.id) {
- if (ptr_svc->sb_virt) {
- unmap_mem = 1;
- ihandle = ptr_svc->ihandle;
- }
- list_del(&ptr_svc->list);
- kzfree(ptr_svc);
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
- /* Unmap the memory */
- if (unmap_mem) {
+exit:
+ if (ptr_svc->sb_virt) {
+ ihandle = ptr_svc->ihandle;
if (!IS_ERR_OR_NULL(ihandle)) {
ion_unmap_kernel(qseecom.ion_clnt, ihandle);
ion_free(qseecom.ion_clnt, ihandle);
- }
+ }
}
+ list_del(&ptr_svc->list);
+ kzfree(ptr_svc);
+
data->released = true;
+ pr_debug("Service %d is unregistered\n", data->listener.id);
return ret;
}
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct qseecom_unregister_pending_list *entry = NULL;
+
+ if (data->released) {
+ pr_err("Don't unregister lsnr %d\n", data->listener.id);
+ return -EINVAL;
+ }
+
+ ptr_svc = __qseecom_find_svc(data->listener.id);
+ if (!ptr_svc) {
+ pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
+ return -ENODATA;
+ }
+ /* stop CA thread waiting for listener response */
+ ptr_svc->abort = 1;
+ wake_up_interruptible_all(&qseecom.send_resp_wq);
+
+ /* stop listener thread waiting for listener request */
+ data->abort = 1;
+ wake_up_all(&ptr_svc->rcv_req_wq);
+
+ /* return directly if pending*/
+ if (ptr_svc->unregister_pending)
+ return 0;
+
+ /*add unregistration into pending list*/
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unregister_lsnr_pending_list_head);
+ ptr_svc->unregister_pending = true;
+ pr_debug("unregister %d pending\n", data->listener.id);
+ return 0;
+}
+
+static void __qseecom_processing_pending_lsnr_unregister(void)
+{
+ struct qseecom_unregister_pending_list *entry = NULL;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&listener_access_lock);
+ while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) {
+ pos = qseecom.unregister_lsnr_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unregister_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unregister %d\n",
+ entry->data->listener.id);
+ /* don't process if qseecom_release is not called*/
+ if (!entry->data->listener.release_called)
+ break;
+ ptr_svc = __qseecom_find_svc(
+ entry->data->listener.id);
+ if (ptr_svc) {
+ ret = __qseecom_unregister_listener(
+ entry->data, ptr_svc);
+ if (ret == -EBUSY) {
+ pr_debug("unregister %d pending again\n",
+ entry->data->listener.id);
+ mutex_unlock(&listener_access_lock);
+ return;
+ }
+ } else
+ pr_err("invalid listener %d\n",
+ entry->data->listener.id);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&listener_access_lock);
+ wake_up_interruptible(&qseecom.register_lsnr_pending_wq);
+}
+
+static void __wakeup_unregister_listener_kthread(void)
+{
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_WAKEUP);
+ wake_up_interruptible(&qseecom.unregister_lsnr_kthread_wq);
+}
+
+static int __qseecom_unregister_listener_kthread_func(void *data)
+{
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ qseecom.unregister_lsnr_kthread_wq,
+ atomic_read(&qseecom.unregister_lsnr_kthread_state)
+ == LSNR_UNREG_KT_WAKEUP);
+ pr_debug("kthread to unregister listener is called %d\n",
+ atomic_read(&qseecom.unregister_lsnr_kthread_state));
+ __qseecom_processing_pending_lsnr_unregister();
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_SLEEP);
+ }
+ pr_warn("kthread to unregister listener stopped\n");
+ return 0;
+}
+
static int __qseecom_set_msm_bus_request(uint32_t mode)
{
int ret = 0;
@@ -1343,39 +1501,35 @@ static void qseecom_bw_inactive_req_work(struct work_struct *work)
qseecom.timer_running = false;
mutex_unlock(&qsee_bw_mutex);
mutex_unlock(&app_access_lock);
- return;
}
static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
{
schedule_work(&qseecom.bw_inactive_req_ws);
- return;
}
static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
{
struct qseecom_clk *qclk;
int ret = 0;
+
mutex_lock(&clk_access_lock);
if (ce == CLK_QSEE)
qclk = &qseecom.qsee;
else
qclk = &qseecom.ce_drv;
- if (qclk->clk_access_cnt > 2) {
+ if (qclk->clk_access_cnt > 0) {
+ qclk->clk_access_cnt--;
+ } else {
pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
ret = -EINVAL;
- goto err_dec_ref_cnt;
}
- if (qclk->clk_access_cnt == 2)
- qclk->clk_access_cnt--;
-err_dec_ref_cnt:
mutex_unlock(&clk_access_lock);
return ret;
}
-
static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
{
int32_t ret = 0;
@@ -1445,6 +1599,7 @@ static int __qseecom_register_bus_bandwidth_needs(
static int qseecom_perf_enable(struct qseecom_dev_handle *data)
{
int ret = 0;
+
ret = qsee_vote_for_clock(data, CLK_DFAB);
if (ret) {
pr_err("Failed to vote for DFAB clock with err %d\n", ret);
@@ -1481,9 +1636,9 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
}
/*
- * Register bus bandwidth needs if bus scaling feature is enabled;
- * otherwise, qseecom enable/disable clocks for the client directly.
- */
+ * Register bus bandwidth needs if bus scaling feature is enabled;
+ * otherwise, qseecom enable/disable clocks for the client directly.
+ */
if (qseecom.support_bus_scaling) {
mutex_lock(&qsee_bw_mutex);
ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
@@ -1526,12 +1681,12 @@ static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
else
__qseecom_add_bw_scale_down_timer(
QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
- return;
}
static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
{
int ret = 0;
+
if (qseecom.support_bus_scaling) {
ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
if (ret)
@@ -1583,7 +1738,7 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
}
if (len < req.sb_len) {
- pr_err("Requested length (0x%x) is > allocated (0x%zu)\n",
+ pr_err("Requested length (0x%x) is > allocated (%zu)\n",
req.sb_len, len);
return -EINVAL;
}
@@ -1600,11 +1755,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
return 0;
}
-static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
+static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret;
+
ret = (qseecom.send_resp_flag != 0);
- return ret || data->abort;
+ return ret || data->abort || ptr_svc->abort;
}
static int __qseecom_reentrancy_listener_has_sent_rsp(
@@ -1614,56 +1771,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp(
int ret;
ret = (ptr_svc->send_resp_flag != 0);
- return ret || data->abort;
-}
-
-static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
- struct qseecom_command_scm_resp *resp,
- struct qseecom_client_listener_data_irsp *send_data_rsp,
- struct qseecom_registered_listener_list *ptr_svc,
- uint32_t lstnr) {
- int ret = 0;
-
- send_data_rsp->status = QSEOS_RESULT_FAILURE;
- qseecom.send_resp_flag = 0;
- send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp->listener_id = lstnr;
- if (ptr_svc)
- pr_warn("listener_id:%x, lstnr: %x\n",
- ptr_svc->svc.listener_id, lstnr);
- if (ptr_svc && ptr_svc->ihandle) {
- ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
- ptr_svc->sb_virt, ptr_svc->sb_length,
- ION_IOC_CLEAN_INV_CACHES);
- if (ret) {
- pr_err("cache operation failed %d\n", ret);
- return ret;
- }
- }
-
- if (lstnr == RPMB_SERVICE) {
- ret = __qseecom_enable_clk(CLK_QSEE);
- if (ret)
- return ret;
- }
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp,
- sizeof(send_data_rsp), resp, sizeof(*resp));
- if (ret) {
- pr_err("scm_call() failed with err: %d (app_id = %d)\n",
- ret, data->client.app_id);
- if (lstnr == RPMB_SERVICE)
- __qseecom_disable_clk(CLK_QSEE);
- return ret;
- }
- if ((resp->result != QSEOS_RESULT_SUCCESS) &&
- (resp->result != QSEOS_RESULT_INCOMPLETE)) {
- pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
- resp->result, data->client.app_id, lstnr);
- ret = -EINVAL;
- }
- if (lstnr == RPMB_SERVICE)
- __qseecom_disable_clk(CLK_QSEE);
- return ret;
+ return ret || data->abort || ptr_svc->abort;
}
static void __qseecom_clean_listener_sglistinfo(
@@ -1682,9 +1790,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
- struct qseecom_client_listener_data_irsp send_data_rsp;
- struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
+ struct qseecom_client_listener_data_irsp send_data_rsp = {0};
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
+ = {0};
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
@@ -1693,13 +1801,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
size_t cmd_len;
struct sglist_info *table = NULL;
+ qseecom.app_block_ref_cnt++;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
@@ -1709,29 +1817,38 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, ptr_svc, lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (!ptr_svc->ihandle) {
pr_err("Client handle is not initialized\n");
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, ptr_svc, lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (ptr_svc->svc.listener_id != lstnr) {
- pr_warn("Service requested does not exist\n");
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, NULL, lstnr);
- return -ERESTARTSYS;
+ pr_err("Service %d does not exist\n",
+ lstnr);
+ rc = -ERESTARTSYS;
+ ptr_svc = NULL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
+ }
+
+ if (ptr_svc->abort == 1) {
+ pr_debug("Service %d abort %d\n",
+ lstnr, ptr_svc->abort);
+ rc = -ENODEV;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
+
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -1739,6 +1856,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
/* block all signals */
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+ mutex_unlock(&listener_access_lock);
do {
/*
* When reentrancy is not supported, check global
@@ -1746,22 +1864,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
* send_resp_flag.
*/
if (!qseecom.qsee_reentrancy_support &&
- !wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- break;
+ !wait_event_interruptible(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(
+ data, ptr_svc))) {
+ break;
}
if (qseecom.qsee_reentrancy_support &&
- !wait_event_freezable(qseecom.send_resp_wq,
+ !wait_event_interruptible(qseecom.send_resp_wq,
__qseecom_reentrancy_listener_has_sent_rsp(
data, ptr_svc))) {
- break;
+ break;
}
} while (1);
-
+ mutex_lock(&listener_access_lock);
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
- if (data->abort) {
+ if (data->abort || ptr_svc->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
@@ -1769,76 +1888,91 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
} else {
status = QSEOS_RESULT_SUCCESS;
}
-
+err_resp:
qseecom.send_resp_flag = 0;
- ptr_svc->send_resp_flag = 0;
- table = ptr_svc->sglistinfo_ptr;
+ if (ptr_svc) {
+ ptr_svc->send_resp_flag = 0;
+ table = ptr_svc->sglistinfo_ptr;
+ }
if (qseecom.qsee_version < QSEE_VERSION_40) {
send_data_rsp.listener_id = lstnr;
send_data_rsp.status = status;
- send_data_rsp.sglistinfo_ptr =
- (uint32_t)virt_to_phys(table);
- send_data_rsp.sglistinfo_len =
- SGLISTINFO_TABLE_SIZE;
- dmac_flush_range((void *)table,
- (void *)table + SGLISTINFO_TABLE_SIZE);
+ if (table) {
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ }
cmd_buf = (void *)&send_data_rsp;
cmd_len = sizeof(send_data_rsp);
} else {
send_data_rsp_64bit.listener_id = lstnr;
send_data_rsp_64bit.status = status;
- send_data_rsp_64bit.sglistinfo_ptr =
- virt_to_phys(table);
- send_data_rsp_64bit.sglistinfo_len =
- SGLISTINFO_TABLE_SIZE;
- dmac_flush_range((void *)table,
- (void *)table + SGLISTINFO_TABLE_SIZE);
+ if (table) {
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ }
cmd_buf = (void *)&send_data_rsp_64bit;
cmd_len = sizeof(send_data_rsp_64bit);
}
- if (qseecom.whitelist_support == false)
+ if (qseecom.whitelist_support == false || table == NULL)
*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc) {
+ if (ptr_svc && ptr_svc->ihandle) {
ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len, resp, sizeof(*resp));
- ptr_svc->listener_in_use = false;
- __qseecom_clean_listener_sglistinfo(ptr_svc);
+ if (ptr_svc) {
+ ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
+ }
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
- return ret;
+ goto exit;
}
+ pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
+ status, resp->result, data->client.app_id, lstnr);
if ((resp->result != QSEOS_RESULT_SUCCESS) &&
(resp->result != QSEOS_RESULT_INCOMPLETE)) {
pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
resp->result, data->client.app_id, lstnr);
ret = -EINVAL;
+ goto exit;
}
+exit:
+ mutex_unlock(&listener_access_lock);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
}
+ qseecom.app_block_ref_cnt--;
+ wake_up_interruptible_all(&qseecom.app_block_wq);
if (rc)
return rc;
@@ -1859,6 +1993,7 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
sigset_t old_sigset;
unsigned long flags;
bool found_app = false;
+ struct qseecom_registered_app_list dummy_app_entry = { {NULL} };
if (!resp || !data) {
pr_err("invalid resp or data pointer\n");
@@ -1868,33 +2003,42 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
/* find app_id & img_name from list */
if (!ptr_app) {
- spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
- list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
- list) {
- if ((ptr_app->app_id == data->client.app_id) &&
- (!strcmp(ptr_app->app_name,
+ if (data->client.from_smcinvoke) {
+ pr_debug("This request is from smcinvoke\n");
+ ptr_app = &dummy_app_entry;
+ ptr_app->app_id = data->client.app_id;
+ } else {
+ spin_lock_irqsave(&qseecom.registered_app_list_lock,
+ flags);
+ list_for_each_entry(ptr_app,
+ &qseecom.registered_app_list_head, list) {
+ if ((ptr_app->app_id == data->client.app_id) &&
+ (!strcmp(ptr_app->app_name,
data->client.app_name))) {
- found_app = true;
- break;
+ found_app = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ if (!found_app) {
+ pr_err("app_id %d (%s) is not found\n",
+ data->client.app_id,
+ (char *)data->client.app_name);
+ ret = -ENOENT;
+ goto exit;
}
- }
- spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
- flags);
- if (!found_app) {
- pr_err("app_id %d (%s) is not found\n",
- data->client.app_id,
- (char *)data->client.app_name);
- ret = -ENOENT;
- goto exit;
}
}
do {
session_id = resp->resp_type;
+ mutex_lock(&listener_access_lock);
list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) {
pr_err("Invalid listener ID %d\n", resp->data);
ret = -ENODATA;
+ mutex_unlock(&listener_access_lock);
goto exit;
}
ptr_app->blocked_on_listener_id = resp->data;
@@ -1910,11 +2054,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
qseecom.app_block_ref_cnt++;
ptr_app->app_blocked = true;
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
- wait_event_freezable(
+ wait_event_interruptible(
list_ptr->listener_block_app_wq,
!list_ptr->listener_in_use);
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
} while (list_ptr->listener_in_use);
@@ -1947,9 +2093,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
if (ret) {
pr_err("unblock app %d or session %d fail\n",
data->client.app_id, session_id);
+ mutex_unlock(&listener_access_lock);
goto exit;
}
}
+ mutex_unlock(&listener_access_lock);
resp->result = continue_resp.result;
resp->resp_type = continue_resp.resp_type;
resp->data = continue_resp.data;
@@ -1971,9 +2119,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
- struct qseecom_client_listener_data_irsp send_data_rsp;
- struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
+ struct qseecom_client_listener_data_irsp send_data_rsp = {0};
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
+ = {0};
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
@@ -1982,13 +2130,12 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
size_t cmd_len;
struct sglist_info *table = NULL;
- while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
+ while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
@@ -1998,23 +2145,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (!ptr_svc->ihandle) {
pr_err("Client handle is not initialized\n");
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (ptr_svc->svc.listener_id != lstnr) {
- pr_warn("Service requested does not exist\n");
- return -ERESTARTSYS;
+ pr_err("Service %d does not exist\n",
+ lstnr);
+ rc = -ERESTARTSYS;
+ ptr_svc = NULL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
+ }
+
+ if (ptr_svc->abort == 1) {
+ pr_debug("Service %d abort %d\n",
+ lstnr, ptr_svc->abort);
+ rc = -ENODEV;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
+
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -2024,22 +2186,24 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
/* unlock mutex btw waking listener and sleep-wait */
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
do {
- if (!wait_event_freezable(qseecom.send_resp_wq,
+ if (!wait_event_interruptible(qseecom.send_resp_wq,
__qseecom_reentrancy_listener_has_sent_rsp(
data, ptr_svc))) {
- break;
+ break;
}
} while (1);
/* lock mutex again after resp sent */
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_svc->send_resp_flag = 0;
qseecom.send_resp_flag = 0;
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
- if (data->abort) {
+ if (data->abort || ptr_svc->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
@@ -2047,55 +2211,64 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
} else {
status = QSEOS_RESULT_SUCCESS;
}
- table = ptr_svc->sglistinfo_ptr;
+err_resp:
+ if (ptr_svc)
+ table = ptr_svc->sglistinfo_ptr;
if (qseecom.qsee_version < QSEE_VERSION_40) {
send_data_rsp.listener_id = lstnr;
send_data_rsp.status = status;
- send_data_rsp.sglistinfo_ptr =
- (uint32_t)virt_to_phys(table);
- send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
- dmac_flush_range((void *)table,
- (void *)table + SGLISTINFO_TABLE_SIZE);
+ if (table) {
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ }
cmd_buf = (void *)&send_data_rsp;
cmd_len = sizeof(send_data_rsp);
} else {
send_data_rsp_64bit.listener_id = lstnr;
send_data_rsp_64bit.status = status;
- send_data_rsp_64bit.sglistinfo_ptr =
- virt_to_phys(table);
- send_data_rsp_64bit.sglistinfo_len =
- SGLISTINFO_TABLE_SIZE;
- dmac_flush_range((void *)table,
- (void *)table + SGLISTINFO_TABLE_SIZE);
+ if (table) {
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ }
cmd_buf = (void *)&send_data_rsp_64bit;
cmd_len = sizeof(send_data_rsp_64bit);
}
- if (qseecom.whitelist_support == false)
+ if (qseecom.whitelist_support == false || table == NULL)
*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc) {
+ if (ptr_svc && ptr_svc->ihandle) {
ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if (lstnr == RPMB_SERVICE) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len, resp, sizeof(*resp));
- ptr_svc->listener_in_use = false;
- __qseecom_clean_listener_sglistinfo(ptr_svc);
- wake_up_interruptible(&ptr_svc->listener_block_app_wq);
+ if (ptr_svc) {
+ ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
+ wake_up_interruptible(&ptr_svc->listener_block_app_wq);
+ }
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
@@ -2113,8 +2286,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
ret = -EINVAL;
goto exit;
}
+ mutex_unlock(&listener_access_lock);
ret = __qseecom_process_reentrancy_blocked_on_listener(
resp, NULL, data);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("failed to process App(%d) %s blocked on listener %d\n",
data->client.app_id,
@@ -2131,6 +2306,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
goto exit;
}
exit:
+ mutex_unlock(&listener_access_lock);
if (lstnr == RPMB_SERVICE)
__qseecom_disable_clk(CLK_QSEE);
@@ -2149,23 +2325,15 @@ exit:
*/
static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
{
- sigset_t new_sigset, old_sigset;
-
if (qseecom.qsee_reentrancy_support > QSEE_REENTRANCY_PHASE_0 &&
qseecom.qsee_reentrancy_support < QSEE_REENTRANCY_PHASE_3 &&
IS_OWNER_TRUSTED_OS(TZ_SYSCALL_OWNER_ID(smc_id))) {
/* thread sleep until this app unblocked */
while (qseecom.app_block_ref_cnt > 0) {
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
mutex_unlock(&app_access_lock);
- do {
- if (!wait_event_freezable(qseecom.app_block_wq,
- (qseecom.app_block_ref_cnt == 0)))
- break;
- } while (1);
+ wait_event_interruptible(qseecom.app_block_wq,
+ (!qseecom.app_block_ref_cnt));
mutex_lock(&app_access_lock);
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
}
}
}
@@ -2178,22 +2346,17 @@ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
static void __qseecom_reentrancy_check_if_this_app_blocked(
struct qseecom_registered_app_list *ptr_app)
{
- sigset_t new_sigset, old_sigset;
if (qseecom.qsee_reentrancy_support) {
+ ptr_app->check_block++;
while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) {
/* thread sleep until this app unblocked */
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
mutex_unlock(&app_access_lock);
- do {
- if (!wait_event_freezable(qseecom.app_block_wq,
- (!ptr_app->app_blocked &&
- qseecom.app_block_ref_cnt <= 1)))
- break;
- } while (1);
+ wait_event_interruptible(qseecom.app_block_wq,
+ (!ptr_app->app_blocked &&
+ qseecom.app_block_ref_cnt <= 1));
mutex_lock(&app_access_lock);
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
}
+ ptr_app->check_block--;
}
}
@@ -2420,8 +2583,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
- pr_err("process_incomplete_cmd failed err: %d\n",
- ret);
+ /* TZ has created app_id, need to unload it */
+ pr_err("incomp_cmd err %d, %d, unload %d %s\n",
+ ret, resp.result, resp.data,
+ load_img_req.img_name);
+ __qseecom_unload_app(data, resp.data);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
ret = -EFAULT;
@@ -2442,7 +2608,6 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
- pr_err("kmalloc failed\n");
ret = -ENOMEM;
goto loadapp_err;
}
@@ -2450,11 +2615,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
entry->ref_cnt = 1;
entry->app_arch = load_img_req.app_arch;
/*
- * keymaster app may be first loaded as "keymaste" by qseecomd,
- * and then used as "keymaster" on some targets. To avoid app
- * name checking error, register "keymaster" into app_list and
- * thread private data.
- */
+ * keymaster app may be first loaded as "keymaste" by qseecomd,
+ * and then used as "keymaster" on some targets. To avoid app
+ * name checking error, register "keymaster" into app_list and
+ * thread private data.
+ */
if (!strcmp(load_img_req.img_name, "keymaste"))
strlcpy(entry->app_name, "keymaster",
MAX_APP_NAME_SIZE);
@@ -2463,6 +2628,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
MAX_APP_NAME_SIZE);
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
@@ -2473,7 +2639,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
- pr_warn("App with id %d (%s) now loaded\n", app_id,
+ pr_warn("App with id %u (%s) now loaded\n", app_id,
(char *)(load_img_req.img_name));
}
data->client.app_id = app_id;
@@ -2511,11 +2677,12 @@ enable_clk_err:
static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
{
int ret = 1; /* Set unload app */
+
wake_up_all(&qseecom.send_resp_wq);
if (qseecom.qsee_reentrancy_support)
mutex_unlock(&app_access_lock);
while (atomic_read(&data->ioctl_count) > 1) {
- if (wait_event_freezable(data->abort_wq,
+ if (wait_event_interruptible(data->abort_wq,
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
@@ -2530,10 +2697,56 @@ static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
{
int ret = 0;
+
if (!IS_ERR_OR_NULL(data->client.ihandle)) {
ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
ion_free(qseecom.ion_clnt, data->client.ihandle);
- data->client.ihandle = NULL;
+ memset((void *)&data->client,
+ 0, sizeof(struct qseecom_client_handle));
+ }
+ return ret;
+}
+
+static int __qseecom_unload_app(struct qseecom_dev_handle *data,
+ uint32_t app_id)
+{
+ struct qseecom_unload_app_ireq req;
+ struct qseecom_command_scm_resp resp;
+ int ret = 0;
+
+ /* Populate the structure for sending scm call to load image */
+ req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
+ req.app_id = app_id;
+
+ /* SCM_CALL to unload the app */
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(struct qseecom_unload_app_ireq),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("scm_call to unload app (id = %d) failed\n", app_id);
+ return -EFAULT;
+ }
+ switch (resp.result) {
+ case QSEOS_RESULT_SUCCESS:
+ pr_warn("App (%d) is unloaded\n", app_id);
+ break;
+ case QSEOS_RESULT_INCOMPLETE:
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret)
+ pr_err("unload app %d fail proc incom cmd: %d,%d,%d\n",
+ app_id, ret, resp.result, resp.data);
+ else
+ pr_warn("App (%d) is unloaded\n", app_id);
+ break;
+ case QSEOS_RESULT_FAILURE:
+ pr_err("app (%d) unload_failed!!\n", app_id);
+ ret = -EFAULT;
+ break;
+ default:
+ pr_err("unload app %d get unknown resp.result %d\n",
+ app_id, resp.result);
+ ret = -EFAULT;
+ break;
}
return ret;
}
@@ -2544,11 +2757,11 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
unsigned long flags;
unsigned long flags1;
int ret = 0;
- struct qseecom_command_scm_resp resp;
struct qseecom_registered_app_list *ptr_app = NULL;
bool unload = false;
bool found_app = false;
bool found_dead_app = false;
+ bool doublecheck = false;
if (!data) {
pr_err("Invalid/uninitialized device handle\n");
@@ -2571,15 +2784,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
if (!strcmp((void *)ptr_app->app_name,
(void *)data->client.app_name)) {
found_app = true;
- if (ptr_app->app_blocked)
+ if (ptr_app->app_blocked ||
+ ptr_app->check_block)
app_crash = false;
if (app_crash || ptr_app->ref_cnt == 1)
unload = true;
break;
- } else {
- found_dead_app = true;
- break;
}
+ found_dead_app = true;
+ break;
}
}
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
@@ -2598,42 +2811,30 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
if (unload) {
- struct qseecom_unload_app_ireq req;
- /* Populate the structure for sending scm call to load image */
- req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
- req.app_id = data->client.app_id;
+ ret = __qseecom_unload_app(data, data->client.app_id);
- /* SCM_CALL to unload the app */
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
- sizeof(struct qseecom_unload_app_ireq),
- &resp, sizeof(resp));
- if (ret) {
- pr_err("scm_call to unload app (id = %d) failed\n",
- req.app_id);
- ret = -EFAULT;
- goto unload_exit;
- } else {
- pr_warn("App id %d now unloaded\n", req.app_id);
- }
- if (resp.result == QSEOS_RESULT_FAILURE) {
- pr_err("app (%d) unload_failed!!\n",
- data->client.app_id);
- ret = -EFAULT;
- goto unload_exit;
- }
- if (resp.result == QSEOS_RESULT_SUCCESS)
- pr_debug("App (%d) is unloaded!!\n",
- data->client.app_id);
- if (resp.result == QSEOS_RESULT_INCOMPLETE) {
- ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret) {
- pr_err("process_incomplete_cmd fail err: %d\n",
- ret);
- goto unload_exit;
+ /* double check if this app_entry still exists */
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
+ list_for_each_entry(ptr_app,
+ &qseecom.registered_app_list_head, list) {
+ if ((ptr_app->app_id == data->client.app_id) &&
+ (!strcmp((void *)ptr_app->app_name,
+ (void *)data->client.app_name))) {
+ doublecheck = true;
+ break;
}
}
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags1);
+ if (!doublecheck) {
+ pr_warn("app %d(%s) entry is already removed\n",
+ data->client.app_id,
+ (char *)data->client.app_name);
+ found_app = false;
+ }
}
+unload_exit:
if (found_app) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
if (app_crash) {
@@ -2656,12 +2857,105 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags1);
}
-unload_exit:
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
}
+
+static int qseecom_prepare_unload_app(struct qseecom_dev_handle *data)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+
+ pr_debug("prepare to unload app(%d)(%s), pending %d\n",
+ data->client.app_id, data->client.app_name,
+ data->client.unload_pending);
+ if (data->client.unload_pending)
+ return 0;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unload_app_pending_list_head);
+ data->client.unload_pending = true;
+ pr_debug("unload ta %d pending\n", data->client.app_id);
+ return 0;
+}
+
+static void __wakeup_unload_app_kthread(void)
+{
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_WAKEUP);
+ wake_up_interruptible(&qseecom.unload_app_kthread_wq);
+}
+
+static bool __qseecom_find_pending_unload_app(uint32_t app_id, char *app_name)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+ bool found = false;
+
+ mutex_lock(&unload_app_pending_list_lock);
+ list_for_each_entry(entry, &qseecom.unload_app_pending_list_head,
+ list) {
+ if ((entry->data->client.app_id == app_id) &&
+ (!strcmp(entry->data->client.app_name, app_name))) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&unload_app_pending_list_lock);
+ return found;
+}
+
+static void __qseecom_processing_pending_unload_app(void)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&unload_app_pending_list_lock);
+ while (!list_empty(&qseecom.unload_app_pending_list_head)) {
+ pos = qseecom.unload_app_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unload_app_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unload app %d (%s)\n",
+ entry->data->client.app_id,
+ entry->data->client.app_name);
+ mutex_unlock(&unload_app_pending_list_lock);
+ mutex_lock(&app_access_lock);
+ ret = qseecom_unload_app(entry->data, true);
+ if (ret)
+ pr_err("unload app %d pending failed %d\n",
+ entry->data->client.app_id, ret);
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&unload_app_pending_list_lock);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&unload_app_pending_list_lock);
+}
+
+static int __qseecom_unload_app_kthread_func(void *data)
+{
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ qseecom.unload_app_kthread_wq,
+ atomic_read(&qseecom.unload_app_kthread_state)
+ == UNLOAD_APP_KT_WAKEUP);
+ pr_debug("kthread to unload app is called, state %d\n",
+ atomic_read(&qseecom.unload_app_kthread_state));
+ __qseecom_processing_pending_unload_app();
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_SLEEP);
+ }
+ pr_warn("kthread to unload app stopped\n");
+ return 0;
+}
+
static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
unsigned long virt)
{
@@ -3065,7 +3359,7 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp,
ret = __qseecom_reentrancy_process_incomplete_cmd(data, resp);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
- wake_up_interruptible(&qseecom.app_block_wq);
+ wake_up_interruptible_all(&qseecom.app_block_wq);
if (ret)
pr_err("process_incomplete_cmd failed err: %d\n",
ret);
@@ -3114,6 +3408,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
send_data_req.app_id = data->client.app_id;
send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
@@ -3245,23 +3546,23 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
- if ((req->cmd_req_len < sizeof(uint32_t)) ||
- (req->ifd_data[i].cmd_buf_offset >
- req->cmd_req_len - sizeof(uint32_t))) {
- pr_err("Invalid offset (req len) 0x%x\n",
- req->ifd_data[i].cmd_buf_offset);
- return -EINVAL;
- }
+ if ((req->cmd_req_len < sizeof(uint32_t)) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ req->cmd_req_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (req len) 0x%x\n",
+ req->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
} else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
(lstnr_resp->ifd_data[i].fd > 0)) {
- if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
- (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len - sizeof(uint32_t))) {
- pr_err("Invalid offset (lstnr resp len) 0x%x\n",
- lstnr_resp->ifd_data[i].cmd_buf_offset);
- return -EINVAL;
- }
+ if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (lstnr resp len) 0x%x\n",
+ lstnr_resp->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
}
+ }
return 0;
}
@@ -3369,6 +3670,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
sg = sg_ptr->sgl;
if (sg_ptr->nents == 1) {
uint32_t *update;
+
if (__boundary_checks_offset(req, lstnr_resp, data, i))
goto err;
if ((data->type == QSEECOM_CLIENT_APP &&
@@ -3432,8 +3734,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
update = (struct qseecom_sg_entry *)field;
for (j = 0; j < sg_ptr->nents; j++) {
/*
- * Check if sg list PA is under 4GB
- */
+ * Check if sg list PA is under 4GB
+ */
if ((qseecom.qsee_version >=
QSEE_VERSION_40) &&
(!cleanup) &&
@@ -3649,8 +3951,9 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
sg = sg_ptr->sgl;
if (sg_ptr->nents == 1) {
uint64_t *update_64bit;
+
if (__boundary_checks_offset_64(req, lstnr_resp,
- data, i))
+ data, i))
goto err;
/* 64bit app uses 64bit address */
update_64bit = (uint64_t *) field;
@@ -3833,7 +4136,8 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
struct qseecom_registered_listener_list *svc)
{
int ret;
- ret = (svc->rcv_req_flag != 0);
+
+ ret = (svc->rcv_req_flag == 1);
return ret || data->abort;
}
@@ -3842,14 +4146,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
int ret = 0;
struct qseecom_registered_listener_list *this_lstnr;
+ mutex_lock(&listener_access_lock);
this_lstnr = __qseecom_find_svc(data->listener.id);
if (!this_lstnr) {
pr_err("Invalid listener ID\n");
+ mutex_unlock(&listener_access_lock);
return -ENODATA;
}
+ mutex_unlock(&listener_access_lock);
while (1) {
- if (wait_event_freezable(this_lstnr->rcv_req_wq,
+ if (wait_event_interruptible(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
this_lstnr))) {
pr_debug("Interrupted: exiting Listener Service = %d\n",
@@ -3860,10 +4167,12 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
if (data->abort) {
pr_err("Aborting Listener Service = %d\n",
- (uint32_t)data->listener.id);
+ (uint32_t)data->listener.id);
return -ENODEV;
}
+ mutex_lock(&listener_access_lock);
this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
break;
}
return ret;
@@ -4079,9 +4388,19 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle,
ion_phys_addr_t pa;
struct ion_handle *ihandle = NULL;
u8 *img_data = NULL;
+ int retry = 0;
+ int ion_flag = ION_FLAG_CACHED;
- ihandle = ion_alloc(qseecom.ion_clnt, fw_size,
- SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ do {
+ if (retry++) {
+ mutex_unlock(&app_access_lock);
+ msleep(QSEECOM_TA_ION_ALLOCATE_DELAY);
+ mutex_lock(&app_access_lock);
+ }
+ ihandle = ion_alloc(qseecom.ion_clnt, fw_size,
+ SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), ion_flag);
+ } while (IS_ERR_OR_NULL(ihandle) &&
+ (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP));
if (IS_ERR_OR_NULL(ihandle)) {
pr_err("ION alloc failed\n");
@@ -4227,8 +4546,12 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname,
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
&resp, sizeof(resp));
if (ret) {
- pr_err("scm_call to load failed : ret %d\n", ret);
- ret = -EIO;
+ pr_err("scm_call to load failed : ret %d, result %x\n",
+ ret, resp.result);
+ if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED)
+ ret = -EEXIST;
+ else
+ ret = -EIO;
goto exit_disable_clk_vote;
}
@@ -4238,10 +4561,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname,
break;
case QSEOS_RESULT_INCOMPLETE:
ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret)
- pr_err("process_incomplete_cmd FAILED\n");
- else
+ if (ret) {
+ pr_err("incomp_cmd err %d, %d, unload %d %s\n",
+ ret, resp.result, resp.data, appname);
+ __qseecom_unload_app(data, resp.data);
+ ret = -EFAULT;
+ } else {
*app_id = resp.data;
+ }
break;
case QSEOS_RESULT_FAILURE:
pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
@@ -4437,6 +4764,9 @@ int qseecom_start_app(struct qseecom_handle **handle,
uint32_t fw_size, app_arch;
uint32_t app_id = 0;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4454,19 +4784,13 @@ int qseecom_start_app(struct qseecom_handle **handle,
}
*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
- if (!(*handle)) {
- pr_err("failed to allocate memory for kernel client handle\n");
+ if (!(*handle))
return -ENOMEM;
- }
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
- pr_err("kmalloc failed\n");
- if (ret == 0) {
- kfree(*handle);
- *handle = NULL;
- }
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit_handle_free;
}
data->abort = 0;
data->type = QSEECOM_CLIENT_APP;
@@ -4481,18 +4805,17 @@ int qseecom_start_app(struct qseecom_handle **handle,
ION_HEAP(ION_QSECOM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(data->client.ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
- kfree(data);
- kfree(*handle);
- *handle = NULL;
- return -EINVAL;
+ ret = -ENOMEM;
+ goto exit_data_free;
}
mutex_lock(&app_access_lock);
+recheck:
app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(app_ireq, &app_id);
if (ret)
- goto err;
+ goto exit_ion_free;
strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
if (app_id) {
@@ -4517,28 +4840,31 @@ int qseecom_start_app(struct qseecom_handle **handle,
pr_debug("%s: Loading app for the first time'\n",
qseecom.pdev->init_name);
ret = __qseecom_load_fw(data, app_name, &app_id);
- if (ret < 0)
- goto err;
+ if (ret == -EEXIST) {
+ pr_err("recheck if TA %s is loaded\n", app_name);
+ goto recheck;
+ } else if (ret < 0)
+ goto exit_ion_free;
}
data->client.app_id = app_id;
if (!found_app) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
pr_err("kmalloc for app entry failed\n");
- ret = -ENOMEM;
- goto err;
+ ret = -ENOMEM;
+ goto exit_ion_free;
}
entry->app_id = app_id;
entry->ref_cnt = 1;
strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) {
ret = -EIO;
- kfree(entry);
- goto err;
+ goto exit_entry_free;
}
entry->app_arch = app_arch;
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_add_tail(&entry->list, &qseecom.registered_app_list_head);
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
@@ -4550,7 +4876,7 @@ int qseecom_start_app(struct qseecom_handle **handle,
if (ret) {
pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
ret);
- goto err;
+ goto exit_entry_free;
}
/* Populate the structure for sending scm call to load image */
@@ -4559,7 +4885,7 @@ int qseecom_start_app(struct qseecom_handle **handle,
if (IS_ERR_OR_NULL(data->client.sb_virt)) {
pr_err("ION memory mapping for client shared buf failed\n");
ret = -ENOMEM;
- goto err;
+ goto exit_entry_free;
}
data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt;
data->client.sb_phys = (phys_addr_t)pa;
@@ -4569,9 +4895,8 @@ int qseecom_start_app(struct qseecom_handle **handle,
kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
if (!kclient_entry) {
- pr_err("kmalloc failed\n");
ret = -ENOMEM;
- goto err;
+ goto exit_ion_unmap_kernel;
}
kclient_entry->handle = *handle;
@@ -4581,13 +4906,28 @@ int qseecom_start_app(struct qseecom_handle **handle,
spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
mutex_unlock(&app_access_lock);
+ __wakeup_unload_app_kthread();
return 0;
-err:
- kfree(data);
- kfree(*handle);
- *handle = NULL;
+exit_ion_unmap_kernel:
+ if (!IS_ERR_OR_NULL(data->client.ihandle))
+ ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+exit_entry_free:
+ kfree(entry);
+exit_ion_free:
mutex_unlock(&app_access_lock);
+ if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+ ion_free(qseecom.ion_clnt, data->client.ihandle);
+ data->client.ihandle = NULL;
+ }
+exit_data_free:
+ kfree(data);
+exit_handle_free:
+ if (*handle) {
+ kfree(*handle);
+ *handle = NULL;
+ }
+ __wakeup_unload_app_kthread();
return ret;
}
EXPORT_SYMBOL(qseecom_start_app);
@@ -4601,6 +4941,9 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
unsigned long flags = 0;
bool found_handle = false;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4636,7 +4979,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
kzfree(kclient);
*handle = NULL;
}
-
+ __wakeup_unload_app_kthread();
return ret;
}
EXPORT_SYMBOL(qseecom_shutdown_app);
@@ -4649,6 +4992,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
struct qseecom_dev_handle *data;
bool perf_enabled = false;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4679,11 +5025,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
}
}
/*
- * On targets where crypto clock is handled by HLOS,
- * if clk_access_cnt is zero and perf_enabled is false,
- * then the crypto clock was not enabled before sending cmd
- * to tz, qseecom will enable the clock to avoid service failure.
- */
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
if (!qseecom.no_clock_support &&
!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
pr_debug("ce clock is not enabled!\n");
@@ -4724,6 +5070,7 @@ EXPORT_SYMBOL(qseecom_send_command);
int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
{
int ret = 0;
+
if ((handle == NULL) || (handle->dev == NULL)) {
pr_err("No valid kernel client\n");
return -EINVAL;
@@ -4771,6 +5118,7 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc)
resp.data = desc->ret[2]; /*listener_id*/
dummy_private_data.client.app_id = desc->ret[1];
+ dummy_private_data.client.from_smcinvoke = true;
dummy_app_entry.app_id = desc->ret[1];
mutex_lock(&app_access_lock);
@@ -5440,6 +5788,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
MAX_APP_NAME_SIZE);
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
spin_lock_irqsave(&qseecom.registered_app_list_lock,
flags);
list_add_tail(&entry->list,
@@ -5721,9 +6070,9 @@ static int __qseecom_update_current_key_user_info(
int ret;
if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
- usage >= QSEOS_KM_USAGE_MAX) {
- pr_err("Error:: unsupported usage %d\n", usage);
- return -EFAULT;
+ usage >= QSEOS_KM_USAGE_MAX) {
+ pr_err("Error:: unsupported usage %d\n", usage);
+ return -EFAULT;
}
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
@@ -5889,6 +6238,9 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
else
flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE;
+ if (qseecom.enable_key_wrap_in_ks == true)
+ flags |= ENABLE_KEY_WRAP_IN_KS;
+
generate_key_ireq.flags = flags;
generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
memset((void *)generate_key_ireq.key_id,
@@ -5937,10 +6289,12 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
memcpy((void *)set_key_ireq.hash32,
(void *)create_key_req.hash32,
QSEECOM_HASH_SIZE);
-
- /* It will return false if it is GPCE based crypto instance or
- ICE is setup properly */
- if (qseecom_enable_ice_setup(create_key_req.usage))
+ /*
+ * It will return false if it is GPCE based crypto instance or
+ * ICE is setup properly
+ */
+ ret = qseecom_enable_ice_setup(create_key_req.usage);
+ if (ret)
goto free_buf;
do {
@@ -6065,9 +6419,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
- /* It will return false if it is GPCE based crypto instance or
- ICE is setup properly */
- if (qseecom_enable_ice_setup(wipe_key_req.usage))
+ /*
+ * It will return false if it is GPCE based crypto instance or
+ * ICE is setup properly
+ */
+ ret = qseecom_enable_ice_setup(wipe_key_req.usage);
+ if (ret)
goto free_buf;
ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
@@ -6148,7 +6505,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
}
static int qseecom_is_es_activated(void __user *argp)
{
- struct qseecom_is_es_activated_req req;
+ struct qseecom_is_es_activated_req req = {0};
struct qseecom_command_scm_resp resp;
int ret;
@@ -6239,9 +6596,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
req.in_buf_size == 0 || req.in_buf_size > MAX_DIP ||
req.out_buf_size == 0 || req.out_buf_size > MAX_DIP ||
req.direction > 1) {
- pr_err("invalid parameters\n");
- ret = -EINVAL;
- break;
+ pr_err("invalid parameters\n");
+ ret = -EINVAL;
+ break;
}
/* Copy the input buffer from userspace to kernel space */
@@ -6284,7 +6641,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
if (ret)
break;
- ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc);
+ ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc);
__qseecom_disable_clk(CLK_QSEE);
@@ -6399,10 +6756,10 @@ static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data,
return -ENOMEM;
}
/*
- * Allocate a buffer, populate it with number of entry plus
- * each sg entry's phy addr and lenth; then return the
- * phy_addr of the buffer.
- */
+ * Allocate a buffer, populate it with number of entry plus
+ * each sg entry's phy addr and length; then return the
+ * phy_addr of the buffer.
+ */
size = sizeof(uint32_t) +
sizeof(struct qseecom_sg_entry) * sg_ptr->nents;
size = (size + PAGE_SIZE) & PAGE_MASK;
@@ -6603,6 +6960,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
(uintptr_t)req->req_ptr);
@@ -6806,6 +7169,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
@@ -6936,61 +7305,8 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
}
}
-
-static int __qseecom_bus_scaling_enable(struct qseecom_dev_handle *data,
- bool *perf_enabled)
-{
- int ret = 0;
-
- if (qseecom.support_bus_scaling) {
- if (!data->mode) {
- mutex_lock(&qsee_bw_mutex);
- __qseecom_register_bus_bandwidth_needs(
- data, HIGH);
- mutex_unlock(&qsee_bw_mutex);
- }
- ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
- if (ret) {
- pr_err("Failed to set bw\n");
- ret = -EINVAL;
- goto exit;
- }
- }
- /*
- * On targets where crypto clock is handled by HLOS,
- * if clk_access_cnt is zero and perf_enabled is false,
- * then the crypto clock was not enabled before sending cmd
- * to tz, qseecom will enable the clock to avoid service failure.
- */
- if (!qseecom.no_clock_support &&
- !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
- pr_debug("ce clock is not enabled\n");
- ret = qseecom_perf_enable(data);
- if (ret) {
- pr_err("Failed to vote for clock with err %d\n",
- ret);
- ret = -EINVAL;
- goto exit;
- }
- *perf_enabled = true;
- }
-exit:
- return ret;
-}
-
-static void __qseecom_bus_scaling_disable(struct qseecom_dev_handle *data,
- bool perf_enabled)
-{
- if (qseecom.support_bus_scaling)
- __qseecom_add_bw_scale_down_timer(
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- if (perf_enabled) {
- qsee_disable_clock_vote(data, CLK_DFAB);
- qsee_disable_clock_vote(data, CLK_SFPB);
- }
-}
-
-long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+long qseecom_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct qseecom_dev_handle *data = file->private_data;
@@ -7006,6 +7322,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("Aborting qseecom driver\n");
return -ENODEV;
}
+ if (cmd != QSEECOM_IOCTL_RECEIVE_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_RESP_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64)
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
switch (cmd) {
case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
@@ -7016,17 +7338,18 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
pr_debug("ioctl register_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
data->type = QSEECOM_LISTENER_SERVICE;
ret = qseecom_register_listener(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_register_listener: %d\n", ret);
break;
}
+
case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
if ((data->listener.id == 0) ||
(data->type != QSEECOM_LISTENER_SERVICE)) {
@@ -7036,12 +7359,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
pr_debug("ioctl unregister_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unregister_listener(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_unregister_listener: %d\n", ret);
break;
@@ -7056,14 +7379,50 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
+ if (qseecom.support_bus_scaling) {
+ /* register bus bw in case the client doesn't do it */
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ ret = -EINVAL;
+ mutex_unlock(&app_access_lock);
+ break;
+ }
+ }
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd to
+ * tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.no_clock_support &&
+ !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
}
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7082,17 +7441,52 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
+ if (qseecom.support_bus_scaling) {
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd to
+ * tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.no_clock_support &&
+ !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
}
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ)
ret = qseecom_send_modfd_cmd(data, argp);
else
ret = qseecom_send_modfd_cmd_64(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7125,6 +7519,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (!qseecom.qsee_reentrancy_support)
ret = qseecom_send_resp();
@@ -7132,6 +7527,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = qseecom_reentrancy_send_resp(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_resp: %d\n", ret);
break;
@@ -7173,6 +7569,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed load_app request: %d\n", ret);
+ __wakeup_unload_app_kthread();
break;
}
case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
@@ -7191,6 +7588,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed unload_app request: %d\n", ret);
+ __wakeup_unload_app_kthread();
break;
}
case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
@@ -7474,6 +7872,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
ret = qseecom_send_modfd_resp(data, argp);
@@ -7481,6 +7880,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = qseecom_send_modfd_resp_64(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
__qseecom_clean_data_sglistinfo(data);
@@ -7501,14 +7901,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
- }
atomic_inc(&data->ioctl_count);
ret = qseecom_qteec_open_session(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7556,14 +7950,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
- }
atomic_inc(&data->ioctl_count);
ret = qseecom_qteec_invoke_modfd_cmd(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7633,10 +8021,8 @@ static int qseecom_open(struct inode *inode, struct file *file)
struct qseecom_dev_handle *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- pr_err("kmalloc failed\n");
+ if (!data)
return -ENOMEM;
- }
file->private_data = data;
data->abort = 0;
data->type = QSEECOM_GENERIC;
@@ -7648,24 +8034,57 @@ static int qseecom_open(struct inode *inode, struct file *file)
return ret;
}
+static void __qseecom_release_disable_clk(struct qseecom_dev_handle *data)
+{
+ if (qseecom.no_clock_support)
+ return;
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ if (data->mode != INACTIVE) {
+ qseecom_unregister_bus_bandwidth_needs(data);
+ if (qseecom.cumulative_mode == INACTIVE)
+ __qseecom_set_msm_bus_request(INACTIVE);
+ }
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ if (data->fast_load_enabled)
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ if (data->perf_enabled)
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ }
+}
+
static int qseecom_release(struct inode *inode, struct file *file)
{
struct qseecom_dev_handle *data = file->private_data;
int ret = 0;
+ bool free_private_data = true;
- if (data->released == false) {
+ __qseecom_release_disable_clk(data);
+ if (!data->released) {
pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
data->type, data->mode, data);
switch (data->type) {
case QSEECOM_LISTENER_SERVICE:
- mutex_lock(&app_access_lock);
+ pr_debug("release lsnr svc %d\n", data->listener.id);
+ mutex_lock(&listener_access_lock);
ret = qseecom_unregister_listener(data);
- mutex_unlock(&app_access_lock);
+ if (!ret)
+ free_private_data = false;
+ data->listener.release_called = true;
+ mutex_unlock(&listener_access_lock);
+ __wakeup_unregister_listener_kthread();
break;
case QSEECOM_CLIENT_APP:
- mutex_lock(&app_access_lock);
- ret = qseecom_unload_app(data, true);
- mutex_unlock(&app_access_lock);
+ pr_debug("release app %d (%s)\n",
+ data->client.app_id, data->client.app_name);
+ if (data->client.app_id) {
+ free_private_data = false;
+ mutex_lock(&unload_app_pending_list_lock);
+ ret = qseecom_prepare_unload_app(data);
+ mutex_unlock(&unload_app_pending_list_lock);
+ __wakeup_unload_app_kthread();
+ }
break;
case QSEECOM_SECURE_SERVICE:
case QSEECOM_GENERIC:
@@ -7682,34 +8101,19 @@ static int qseecom_release(struct inode *inode, struct file *file)
}
}
- if (qseecom.support_bus_scaling) {
- mutex_lock(&qsee_bw_mutex);
- if (data->mode != INACTIVE) {
- qseecom_unregister_bus_bandwidth_needs(data);
- if (qseecom.cumulative_mode == INACTIVE) {
- ret = __qseecom_set_msm_bus_request(INACTIVE);
- if (ret)
- pr_err("Fail to scale down bus\n");
- }
- }
- mutex_unlock(&qsee_bw_mutex);
- } else {
- if (data->fast_load_enabled == true)
- qsee_disable_clock_vote(data, CLK_SFPB);
- if (data->perf_enabled == true)
- qsee_disable_clock_vote(data, CLK_DFAB);
- }
- kfree(data);
-
+ if (free_private_data)
+ kfree(data);
return ret;
}
+#ifndef CONFIG_COMPAT
+#define compat_qseecom_ioctl NULL
+#endif
+
static const struct file_operations qseecom_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = qseecom_ioctl,
-#ifdef CONFIG_COMPAT
.compat_ioctl = compat_qseecom_ioctl,
-#endif
.open = qseecom_open,
.release = qseecom_release
};
@@ -7761,14 +8165,14 @@ static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
/* Get CE3 src core clk. */
qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
if (!IS_ERR(qclk->ce_core_src_clk)) {
- rc = clk_set_rate(qclk->ce_core_src_clk,
- qseecom.ce_opp_freq_hz);
- if (rc) {
- clk_put(qclk->ce_core_src_clk);
- qclk->ce_core_src_clk = NULL;
- pr_err("Unable to set the core src clk @%uMhz.\n",
- qseecom.ce_opp_freq_hz/CE_CLK_DIV);
- return -EIO;
+ rc = clk_set_rate(qclk->ce_core_src_clk,
+ qseecom.ce_opp_freq_hz);
+ if (rc) {
+ clk_put(qclk->ce_core_src_clk);
+ qclk->ce_core_src_clk = NULL;
+ pr_err("Unable to set the core src clk @%uMhz.\n",
+ qseecom.ce_opp_freq_hz/CE_CLK_DIV);
+ return -EIO;
}
} else {
pr_warn("Unable to get CE core src clk, set to NULL\n");
@@ -8524,17 +8928,23 @@ static int qseecom_probe(struct platform_device *pdev)
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
- spin_lock_init(&qseecom.registered_listener_list_lock);
INIT_LIST_HEAD(&qseecom.registered_app_list_head);
spin_lock_init(&qseecom.registered_app_list_lock);
+ INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head);
INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
spin_lock_init(&qseecom.registered_kclient_list_lock);
init_waitqueue_head(&qseecom.send_resp_wq);
+ init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
+ init_waitqueue_head(&qseecom.unregister_lsnr_kthread_wq);
+ INIT_LIST_HEAD(&qseecom.unload_app_pending_list_head);
+ init_waitqueue_head(&qseecom.unload_app_kthread_wq);
qseecom.send_resp_flag = 0;
qseecom.qsee_version = QSEEE_VERSION_00;
+ mutex_lock(&app_access_lock);
rc = qseecom_scm_call(6, 3, &feature, sizeof(feature),
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
pr_info("qseecom.qsee_version = 0x%x\n", resp.result);
if (rc) {
pr_err("Failed to get QSEE version info %d\n", rc);
@@ -8549,11 +8959,7 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel");
if (IS_ERR_OR_NULL(qseecom.ion_clnt)) {
pr_err("Ion client cannot be created\n");
-
- if (qseecom.ion_clnt != ERR_PTR(-EPROBE_DEFER))
- rc = -ENOMEM;
- else
- rc = -EPROBE_DEFER;
+ rc = -ENOMEM;
goto exit_del_cdev;
}
@@ -8600,6 +9006,14 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.qsee_reentrancy_support);
}
+ qseecom.enable_key_wrap_in_ks =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,enable-key-wrap-in-ks");
+ if (qseecom.enable_key_wrap_in_ks) {
+ pr_warn("qseecom.enable_key_wrap_in_ks = %d\n",
+ qseecom.enable_key_wrap_in_ks);
+ }
+
/*
* The qseecom bus scaling flag can not be enabled when
* crypto clock is not handled by HLOS.
@@ -8685,9 +9099,11 @@ static int qseecom_probe(struct platform_device *pdev)
rc = -EIO;
goto exit_deinit_clock;
}
+ mutex_lock(&app_access_lock);
rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len,
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
__qseecom_disable_clk(CLK_QSEE);
if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
pr_err("send secapp reg fail %d resp.res %d\n",
@@ -8726,9 +9142,36 @@ static int qseecom_probe(struct platform_device *pdev)
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
+ /*create a kthread to process pending listener unregister task */
+ qseecom.unregister_lsnr_kthread_task = kthread_run(
+ __qseecom_unregister_listener_kthread_func,
+ NULL, "qseecom-unreg-lsnr");
+ if (IS_ERR(qseecom.unregister_lsnr_kthread_task)) {
+ pr_err("failed to create kthread to unregister listener\n");
+ rc = -EINVAL;
+ goto exit_deinit_clock;
+ }
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_SLEEP);
+
+ /*create a kthread to process pending ta unloading task */
+ qseecom.unload_app_kthread_task = kthread_run(
+ __qseecom_unload_app_kthread_func,
+ NULL, "qseecom-unload-ta");
+ if (IS_ERR(qseecom.unload_app_kthread_task)) {
+ pr_err("failed to create kthread to unload ta\n");
+ rc = -EINVAL;
+ goto exit_kill_unreg_lsnr_kthread;
+ }
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_SLEEP);
+
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
return 0;
+exit_kill_unreg_lsnr_kthread:
+ kthread_stop(qseecom.unregister_lsnr_kthread_task);
+
exit_deinit_clock:
__qseecom_deinit_clk(CLK_QSEE);
if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
@@ -8842,6 +9285,10 @@ static int qseecom_remove(struct platform_device *pdev)
ion_client_destroy(qseecom.ion_clnt);
+ kthread_stop(qseecom.unload_app_kthread_task);
+
+ kthread_stop(qseecom.unregister_lsnr_kthread_task);
+
cdev_del(&qseecom.cdev);
device_destroy(driver_class, qseecom_device_no);
@@ -8857,8 +9304,8 @@ static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
{
int ret = 0;
struct qseecom_clk *qclk;
- qclk = &qseecom.qsee;
+ qclk = &qseecom.qsee;
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_SUSPEND);
if (qseecom.no_clock_support)
return 0;
@@ -8899,8 +9346,8 @@ static int qseecom_resume(struct platform_device *pdev)
int mode = 0;
int ret = 0;
struct qseecom_clk *qclk;
- qclk = &qseecom.qsee;
+ qclk = &qseecom.qsee;
if (qseecom.no_clock_support)
goto exit;
@@ -8973,7 +9420,8 @@ exit:
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
return ret;
}
-static struct of_device_id qseecom_match[] = {
+
+static const struct of_device_id qseecom_match[] = {
{
.compatible = "qcom,qseecom",
},
@@ -9003,7 +9451,7 @@ static void qseecom_exit(void)
}
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
+MODULE_DESCRIPTION("QTI Secure Execution Environment Communicator");
module_init(qseecom_init);
module_exit(qseecom_exit);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b96f27f861ba..82bfc9df04e8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1845,7 +1845,9 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
else if (timing == MMC_TIMING_UHS_SDR12)
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- else if (timing == MMC_TIMING_UHS_SDR25)
+ else if (timing == MMC_TIMING_SD_HS ||
+ timing == MMC_TIMING_MMC_HS ||
+ timing == MMC_TIMING_UHS_SDR25)
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
else if (timing == MMC_TIMING_UHS_SDR50)
ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fb5a3052f144..7589d891b311 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1626,29 +1626,35 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
continue;
}
- if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+ /*
+ * We check "time_after" and "!chip_good" before checking
+ * "chip_good" to avoid the failure due to scheduling.
+ */
+ if (time_after(jiffies, timeo) && !chip_good(map, adr, datum)) {
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
xip_disable(map, chip, adr);
+ ret = -EIO;
break;
}
- if (chip_ready(map, adr))
+ if (chip_good(map, adr, datum))
break;
/* Latency issues. Drop the lock, wait a while and retry */
UDELAY(map, chip, adr, 1);
}
+
/* Did we succeed? */
- if (!chip_good(map, adr, datum)) {
+ if (ret) {
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- if (++retry_cnt <= MAX_RETRIES)
+ if (++retry_cnt <= MAX_RETRIES) {
+ ret = 0;
goto retry;
-
- ret = -EIO;
+ }
}
xip_enable(map, chip, adr);
op_done:
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 6ea963e3b89a..85ffd0561827 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -1009,31 +1009,34 @@ EXPORT_SYMBOL(arcnet_interrupt);
static void arcnet_rx(struct net_device *dev, int bufnum)
{
struct arcnet_local *lp = netdev_priv(dev);
- struct archdr pkt;
+ union {
+ struct archdr pkt;
+ char buf[512];
+ } rxdata;
struct arc_rfc1201 *soft;
int length, ofs;
- soft = &pkt.soft.rfc1201;
+ soft = &rxdata.pkt.soft.rfc1201;
- lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
- if (pkt.hard.offset[0]) {
- ofs = pkt.hard.offset[0];
+ lp->hw.copy_from_card(dev, bufnum, 0, &rxdata.pkt, ARC_HDR_SIZE);
+ if (rxdata.pkt.hard.offset[0]) {
+ ofs = rxdata.pkt.hard.offset[0];
length = 256 - ofs;
} else {
- ofs = pkt.hard.offset[1];
+ ofs = rxdata.pkt.hard.offset[1];
length = 512 - ofs;
}
/* get the full header, if possible */
- if (sizeof(pkt.soft) <= length) {
- lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft));
+ if (sizeof(rxdata.pkt.soft) <= length) {
+ lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft));
} else {
- memset(&pkt.soft, 0, sizeof(pkt.soft));
+ memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft));
lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
}
arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)\n",
- bufnum, pkt.hard.source, pkt.hard.dest, length);
+ bufnum, rxdata.pkt.hard.source, rxdata.pkt.hard.dest, length);
dev->stats.rx_packets++;
dev->stats.rx_bytes += length + ARC_HDR_SIZE;
@@ -1042,13 +1045,13 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
if (arc_proto_map[soft->proto]->is_ip) {
if (BUGLVL(D_PROTO)) {
struct ArcProto
- *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]],
+ *oldp = arc_proto_map[lp->default_proto[rxdata.pkt.hard.source]],
*newp = arc_proto_map[soft->proto];
if (oldp != newp) {
arc_printk(D_PROTO, dev,
"got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')\n",
- soft->proto, pkt.hard.source,
+ soft->proto, rxdata.pkt.hard.source,
newp->suffix, oldp->suffix);
}
}
@@ -1057,10 +1060,10 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
lp->default_proto[0] = soft->proto;
/* in striking contrast, the following isn't a hack. */
- lp->default_proto[pkt.hard.source] = soft->proto;
+ lp->default_proto[rxdata.pkt.hard.source] = soft->proto;
}
/* call the protocol-specific receiver. */
- arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
+ arc_proto_map[soft->proto]->rx(dev, bufnum, &rxdata.pkt, length);
}
static void null_rx(struct net_device *dev, int bufnum,
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 3bcbfcf0455a..83ddb7d8214a 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -627,7 +627,7 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
- u8 reg;
+ unsigned long timeout;
int ret;
/* Wait for oscillator startup timer after power up */
@@ -641,10 +641,19 @@ static int mcp251x_hw_reset(struct spi_device *spi)
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
- reg = mcp251x_read_reg(spi, CANSTAT);
- if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
- return -ENODEV;
-
+ /* Wait for reset to finish */
+ timeout = jiffies + HZ;
+ while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
+ CANCTRL_REQOP_CONF) {
+ usleep_range(MCP251X_OST_DELAY_MS * 1000,
+ MCP251X_OST_DELAY_MS * 1000 * 2);
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&spi->dev,
+ "MCP251x didn't enter in conf mode after reset\n");
+ return -EBUSY;
+ }
+ }
return 0;
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index ce20bc939b38..e651845c6605 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -362,6 +362,7 @@ struct bcmgenet_mib_counters {
#define EXT_ENERGY_DET_MASK (1 << 12)
#define EXT_RGMII_OOB_CTRL 0x0C
+#define RGMII_MODE_EN_V123 (1 << 0)
#define RGMII_LINK (1 << 4)
#define OOB_DISABLE (1 << 5)
#define RGMII_MODE_EN (1 << 6)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 0565efad6e6e..3ad016f500b5 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -328,7 +328,11 @@ int bcmgenet_mii_config(struct net_device *dev)
*/
if (priv->ext_phy) {
reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
- reg |= RGMII_MODE_EN | id_mode_dis;
+ reg |= id_mode_dis;
+ if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
+ reg |= RGMII_MODE_EN_V123;
+ else
+ reg |= RGMII_MODE_EN;
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
}
@@ -342,11 +346,12 @@ int bcmgenet_mii_probe(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device_node *dn = priv->pdev->dev.of_node;
struct phy_device *phydev;
- u32 phy_flags;
+ u32 phy_flags = 0;
int ret;
/* Communicate the integrated PHY revision */
- phy_flags = priv->gphy_rev;
+ if (priv->internal_phy)
+ phy_flags = priv->gphy_rev;
/* Initialize link state variables that bcmgenet_mii_setup() uses */
priv->old_link = -1;
diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
index 6ff13c559e52..09fcc821b7da 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -156,11 +156,15 @@ static int mdio_sc_cfg_reg_write(struct hns_mdio_device *mdio_dev,
{
u32 time_cnt;
u32 reg_value;
+ int ret;
regmap_write(mdio_dev->subctrl_vbase, cfg_reg, set_val);
for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) {
- regmap_read(mdio_dev->subctrl_vbase, st_reg, &reg_value);
+ ret = regmap_read(mdio_dev->subctrl_vbase, st_reg, &reg_value);
+ if (ret)
+ return ret;
+
reg_value &= st_msk;
if ((!!check_st) == (!!reg_value))
break;
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index c9f4b5412844..b97a070074b7 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -3114,7 +3114,7 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
skb_put(skb, len);
if (dev->features & NETIF_F_RXCSUM) {
- skb->csum = csum;
+ skb->csum = le16_to_cpu(csum);
skb->ip_summed = CHECKSUM_COMPLETE;
}
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 057665180f13..ba14bad81a21 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -1417,13 +1417,14 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
pldat->dma_buff_base_p = dma_handle;
netdev_dbg(ndev, "IO address space :%pR\n", res);
- netdev_dbg(ndev, "IO address size :%d\n", resource_size(res));
+ netdev_dbg(ndev, "IO address size :%zd\n",
+ (size_t)resource_size(res));
netdev_dbg(ndev, "IO address (mapped) :0x%p\n",
pldat->net_base);
netdev_dbg(ndev, "IRQ number :%d\n", ndev->irq);
- netdev_dbg(ndev, "DMA buffer size :%d\n", pldat->dma_buff_size);
- netdev_dbg(ndev, "DMA buffer P address :0x%08x\n",
- pldat->dma_buff_base_p);
+ netdev_dbg(ndev, "DMA buffer size :%zd\n", pldat->dma_buff_size);
+ netdev_dbg(ndev, "DMA buffer P address :%pad\n",
+ &pldat->dma_buff_base_p);
netdev_dbg(ndev, "DMA buffer V address :0x%p\n",
pldat->dma_buff_base_v);
@@ -1470,8 +1471,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
if (ret)
goto err_out_unregister_netdev;
- netdev_info(ndev, "LPC mac at 0x%08x irq %d\n",
- res->start, ndev->irq);
+ netdev_info(ndev, "LPC mac at 0x%08lx irq %d\n",
+ (unsigned long)res->start, ndev->irq);
phydev = pldat->phy_dev;
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 355c5fb802cd..c653b97d84d5 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2783,6 +2783,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
netdev_err(qdev->ndev,
"PCI mapping failed with error: %d\n",
err);
+ dev_kfree_skb_irq(skb);
ql_free_large_buffers(qdev);
return -ENOMEM;
}
diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
index 3a429f1a8002..d5e0e2aedc55 100644
--- a/drivers/net/ieee802154/atusb.c
+++ b/drivers/net/ieee802154/atusb.c
@@ -756,10 +756,11 @@ static void atusb_disconnect(struct usb_interface *interface)
ieee802154_unregister_hw(atusb->hw);
+ usb_put_dev(atusb->usb_dev);
+
ieee802154_free_hw(atusb->hw);
usb_set_intfdata(interface, NULL);
- usb_put_dev(atusb->usb_dev);
pr_debug("atusb_disconnect done\n");
}
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 0a7b9c7f09a2..5c40655ec808 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -110,14 +110,17 @@ static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
{
+ u16 lb_dis = BIT(1);
+
if (disable)
- ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1);
+ ns_exp_write(phydev, 0x1c0,
+ ns_exp_read(phydev, 0x1c0) | lb_dis);
else
ns_exp_write(phydev, 0x1c0,
- ns_exp_read(phydev, 0x1c0) & 0xfffe);
+ ns_exp_read(phydev, 0x1c0) & ~lb_dis);
pr_debug("10BASE-T HDX loopback %s\n",
- (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
+ (ns_exp_read(phydev, 0x1c0) & lb_dis) ? "off" : "on");
}
static int ns_config_init(struct phy_device *phydev)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 1e921e5eddc7..442efbccd005 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -636,8 +636,12 @@ cdc_ncm_find_endpoints(struct usbnet *dev, struct usb_interface *intf)
u8 ep;
for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
-
e = intf->cur_altsetting->endpoint + ep;
+
+ /* ignore endpoints which cannot transfer data */
+ if (!usb_endpoint_maxp(&e->desc))
+ continue;
+
switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_INT:
if (usb_endpoint_dir_in(&e->desc)) {
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 79cede19e0c4..cbbff16d438f 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2650,14 +2650,18 @@ static struct hso_device *hso_create_bulk_serial_device(
*/
if (serial->tiocmget) {
tiocmget = serial->tiocmget;
+ tiocmget->endp = hso_get_ep(interface,
+ USB_ENDPOINT_XFER_INT,
+ USB_DIR_IN);
+ if (!tiocmget->endp) {
+ dev_err(&interface->dev, "Failed to find INT IN ep\n");
+ goto exit;
+ }
+
tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
if (tiocmget->urb) {
mutex_init(&tiocmget->mutex);
init_waitqueue_head(&tiocmget->waitq);
- tiocmget->endp = hso_get_ep(
- interface,
- USB_ENDPOINT_XFER_INT,
- USB_DIR_IN);
} else
hso_free_tiomget(serial);
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index a3a66c481e91..db178e921e5d 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -114,6 +114,11 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
int intr = 0;
e = alt->endpoint + ep;
+
+ /* ignore endpoints which cannot transfer data */
+ if (!usb_endpoint_maxp(&e->desc))
+ continue;
+
switch (e->desc.bmAttributes) {
case USB_ENDPOINT_XFER_INT:
if (!usb_endpoint_dir_in(&e->desc))
@@ -349,6 +354,8 @@ void usbnet_update_max_qlen(struct usbnet *dev)
{
enum usb_device_speed speed = dev->udev->speed;
+ if (!dev->rx_urb_size || !dev->hard_mtu)
+ goto insanity;
switch (speed) {
case USB_SPEED_HIGH:
dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size;
@@ -364,6 +371,7 @@ void usbnet_update_max_qlen(struct usbnet *dev)
dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu;
break;
default:
+insanity:
dev->rx_qlen = dev->tx_qlen = 4;
}
}
diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile
index a4b177e7a981..b1c8c5e6461e 100644
--- a/drivers/net/wireless/cnss2/Makefile
+++ b/drivers/net/wireless/cnss2/Makefile
@@ -5,6 +5,7 @@ cnss2-y += bus.o
cnss2-y += debug.o
cnss2-y += pci.o
cnss2-y += usb.o
+cnss2-$(CONFIG_SDIO_QCN) += sdio.o
cnss2-y += power.o
cnss2-y += qmi.o
cnss2-y += wlan_firmware_service_v01.o
diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c
index 088593f9ae1c..e33eb647d9bb 100644
--- a/drivers/net/wireless/cnss2/bus.c
+++ b/drivers/net/wireless/cnss2/bus.c
@@ -14,6 +14,7 @@
#include "debug.h"
#include "pci.h"
#include "usb.h"
+#include "sdio.h"
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
{
@@ -27,6 +28,8 @@ enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
return CNSS_BUS_PCI;
else if (memcmp(dev->bus->name, "usb", 3) == 0)
return CNSS_BUS_USB;
+ else if (memcmp(dev->bus->name, "sdio", 4) == 0)
+ return CNSS_BUS_SDIO;
else
return CNSS_BUS_NONE;
}
@@ -44,20 +47,14 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
case QCN7605_VER20_STANDALONE_DEVICE_ID:
case QCN7605_VER20_COMPOSITE_DEVICE_ID:
return CNSS_BUS_USB;
+ case QCN7605_SDIO_DEVICE_ID:
+ return CNSS_BUS_SDIO;
default:
cnss_pr_err("Unknown device_id: 0x%lx\n", device_id);
return CNSS_BUS_NONE;
}
}
-bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv)
-{
- if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
- return false;
- else
- return true;
-}
-
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
@@ -89,6 +86,8 @@ struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
return cnss_pci_priv_to_plat_priv(bus_priv);
case CNSS_BUS_USB:
return cnss_usb_priv_to_plat_priv(bus_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_get_plat_priv(NULL);
default:
return NULL;
}
@@ -104,6 +103,8 @@ int cnss_bus_init(struct cnss_plat_data *plat_priv)
return cnss_pci_init(plat_priv);
case CNSS_BUS_USB:
return cnss_usb_init(plat_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_init(plat_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -119,13 +120,18 @@ void cnss_bus_deinit(struct cnss_plat_data *plat_priv)
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
cnss_pci_deinit(plat_priv);
+ break;
case CNSS_BUS_USB:
cnss_usb_deinit(plat_priv);
+ break;
+ case CNSS_BUS_SDIO:
+ cnss_sdio_deinit(plat_priv);
+ break;
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
- return;
}
+ return;
}
int cnss_bus_load_m3(struct cnss_plat_data *plat_priv)
@@ -200,6 +206,8 @@ void cnss_bus_fw_boot_timeout_hdlr(unsigned long data)
return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv);
case CNSS_BUS_USB:
return cnss_usb_fw_boot_timeout_hdlr(plat_priv->bus_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_fw_boot_timeout_hdlr(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -240,6 +248,8 @@ int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
return cnss_pci_call_driver_probe(plat_priv->bus_priv);
case CNSS_BUS_USB:
return cnss_usb_call_driver_probe(plat_priv->bus_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_call_driver_probe(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -257,6 +267,8 @@ int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
return cnss_pci_call_driver_remove(plat_priv->bus_priv);
case CNSS_BUS_USB:
return cnss_usb_call_driver_remove(plat_priv->bus_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_call_driver_remove(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -274,6 +286,8 @@ int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
return cnss_pci_dev_powerup(plat_priv->bus_priv);
case CNSS_BUS_USB:
return cnss_usb_dev_powerup(plat_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_dev_powerup(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -291,6 +305,8 @@ int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
return cnss_pci_dev_shutdown(plat_priv->bus_priv);
case CNSS_BUS_USB:
return 0;
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_dev_shutdown(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -338,6 +354,9 @@ int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
case CNSS_BUS_USB:
return cnss_usb_register_driver_hdlr(plat_priv->bus_priv, data);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_register_driver_hdlr(plat_priv->bus_priv,
+ data);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
@@ -355,6 +374,8 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
case CNSS_BUS_USB:
return cnss_usb_unregister_driver_hdlr(plat_priv->bus_priv);
+ case CNSS_BUS_SDIO:
+ return cnss_sdio_unregister_driver_hdlr(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h
index 1100fd66482a..30a93a06549f 100644
--- a/drivers/net/wireless/cnss2/bus.h
+++ b/drivers/net/wireless/cnss2/bus.h
@@ -26,6 +26,8 @@
#define QCA6290_EMULATION_DEVICE_ID 0xABCD
#define QCN7605_VENDOR_ID 0x17CB
#define QCN7605_DEVICE_ID 0x1102
+#define QCN7605_SDIO_VENDOR_ID 0x70
+#define QCN7605_SDIO_DEVICE_ID 0x400B
#define QCN7605_USB_VENDOR_ID 0x05C6
#define QCN7605_COMPOSITE_DEVICE_ID QCN7605_COMPOSITE_PRODUCT_ID
@@ -62,5 +64,4 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv);
int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status);
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
-bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_BUS_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index baa469ad2f6a..4507f57f5bd8 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -282,7 +282,7 @@ int cnss_wlan_enable(struct device *dev,
enum cnss_driver_mode mode,
const char *host_version)
{
- struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct wlfw_wlan_cfg_req_msg_v01 req;
u32 i, ce_id, num_vectors, user_base_data, base_vector;
int ret = 0;
@@ -293,7 +293,8 @@ int cnss_wlan_enable(struct device *dev,
if (qmi_bypass)
return 0;
- if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
+ if (plat_priv->bus_type == CNSS_BUS_USB ||
+ plat_priv->bus_type == CNSS_BUS_SDIO)
goto skip_cfg;
if (!config || !host_version) {
@@ -398,7 +399,7 @@ EXPORT_SYMBOL(cnss_wlan_enable);
int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
{
- struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
if (plat_priv->device_id == QCA6174_DEVICE_ID)
return 0;
@@ -1288,7 +1289,8 @@ static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
if (ret)
goto out;
- if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
+ if (plat_priv->bus_type == CNSS_BUS_USB ||
+ plat_priv->bus_type == CNSS_BUS_SDIO) {
ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
if (ret)
goto out;
@@ -1308,7 +1310,7 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
if (test_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state))
pwr_up_reqd = true;
- if (pwr_up_reqd || plat_priv->bus_type != CNSS_BUS_USB)
+ if (pwr_up_reqd || plat_priv->bus_type == CNSS_BUS_PCI)
ret = cnss_bus_dev_powerup(plat_priv);
if (ret)
@@ -1467,6 +1469,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv)
case QCN7605_COMPOSITE_DEVICE_ID:
case QCN7605_VER20_STANDALONE_DEVICE_ID:
case QCN7605_VER20_COMPOSITE_DEVICE_ID:
+ case QCN7605_SDIO_DEVICE_ID:
subsys_info->subsys_desc.name = "QCN7605";
break;
default:
@@ -1803,6 +1806,18 @@ static ssize_t cnss_fs_ready_store(struct device *dev,
return count;
}
+#ifdef CONFIG_SDIO_QCN
+static void cnss_set_card_state(bool state)
+{
+ qcn_sdio_card_state(state);
+}
+#else
+static void cnss_set_card_state(bool state)
+{
+ /* no op */
+}
+#endif
+
static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store);
static ssize_t cnss_wl_pwr_on(struct device *dev,
@@ -1823,12 +1838,14 @@ static ssize_t cnss_wl_pwr_on(struct device *dev,
timeout = cnss_get_qmi_timeout();
if (pwr_state) {
cnss_power_on_device(plat_priv);
+ cnss_set_card_state(true);
if (timeout) {
mod_timer(&plat_priv->fw_boot_timer,
jiffies + msecs_to_jiffies(timeout));
}
} else {
cnss_power_off_device(plat_priv);
+ cnss_set_card_state(false);
del_timer(&plat_priv->fw_boot_timer);
}
return count;
@@ -1921,6 +1938,7 @@ static const struct platform_device_id cnss_platform_id_table[] = {
{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
{ .name = "qcn7605", .driver_data = QCN7605_DEVICE_ID, },
+ { .name = "qcn7605_sdio", .driver_data = QCN7605_SDIO_DEVICE_ID, },
};
static const struct of_device_id cnss_of_match_table[] = {
@@ -1930,6 +1948,12 @@ static const struct of_device_id cnss_of_match_table[] = {
{
.compatible = "qcom,cnss-qca6290",
.data = (void *)&cnss_platform_id_table[1]},
+ {
+ .compatible = "qcom,cnss",
+ .data = (void *)&cnss_platform_id_table[2]},
+ {
+ .compatible = "qcom,cnss-sdio",
+ .data = (void *)&cnss_platform_id_table[3]},
{ },
};
MODULE_DEVICE_TABLE(of, cnss_of_match_table);
@@ -1980,7 +2004,9 @@ static int cnss_probe(struct platform_device *plat_dev)
goto free_res;
ret = cnss_bus_init(plat_priv);
- if (ret)
+ if (ret == -EPROBE_DEFER)
+ goto free_res;
+ else if (ret)
goto power_off;
}
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index 524a1fa0dcf4..969ff00b85ae 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -37,6 +37,7 @@ enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
CNSS_BUS_PCI,
CNSS_BUS_USB,
+ CNSS_BUS_SDIO,
};
struct cnss_vreg_info {
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 7dc419753a80..099aa9d38bb8 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -56,6 +56,7 @@
#ifdef CONFIG_PCI_MSM
static DEFINE_SPINLOCK(pci_link_down_lock);
#endif
+static DEFINE_SPINLOCK(pci_reg_window_lock);
static unsigned int pci_link_down_panic;
module_param(pci_link_down_panic, uint, 0600);
@@ -268,6 +269,18 @@ int cnss_pci_is_device_down(struct device *dev)
}
EXPORT_SYMBOL(cnss_pci_is_device_down);
+void cnss_pci_lock_reg_window(struct device *dev, unsigned long *flags)
+{
+ spin_lock_bh(&pci_reg_window_lock);
+}
+EXPORT_SYMBOL(cnss_pci_lock_reg_window);
+
+void cnss_pci_unlock_reg_window(struct device *dev, unsigned long *flags)
+{
+ spin_unlock_bh(&pci_reg_window_lock);
+}
+EXPORT_SYMBOL(cnss_pci_unlock_reg_window);
+
int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv;
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index 7945f59439f7..489a28e478bd 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -797,7 +797,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
plat_priv->device_id == QCN7605_COMPOSITE_DEVICE_ID ||
plat_priv->device_id == QCN7605_STANDALONE_DEVICE_ID ||
plat_priv->device_id == QCN7605_VER20_STANDALONE_DEVICE_ID ||
- plat_priv->device_id == QCN7605_VER20_COMPOSITE_DEVICE_ID)
+ plat_priv->device_id == QCN7605_VER20_COMPOSITE_DEVICE_ID ||
+ plat_priv->device_id == QCN7605_SDIO_DEVICE_ID)
bdf_type = CNSS_BDF_BIN;
if (plat_priv->board_info.board_id == 0xFF) {
diff --git a/drivers/net/wireless/cnss2/sdio.c b/drivers/net/wireless/cnss2/sdio.c
new file mode 100644
index 000000000000..f25a2b0aaaa8
--- /dev/null
+++ b/drivers/net/wireless/cnss2/sdio.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <net/cnss2.h>
+#include <linux/qcn_sdio_al.h>
+#include "main.h"
+#include "sdio.h"
+#include "debug.h"
+#include "bus.h"
+
+int cnss_sdio_call_driver_probe(struct cnss_sdio_data *sdio_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = sdio_priv->plat_priv;
+
+ if ((!sdio_priv->al_client_handle) ||
+ (!sdio_priv->al_client_handle->func)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (!sdio_priv->ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ ret = sdio_priv->ops->reinit(sdio_priv->al_client_handle->func,
+ sdio_priv->device_id);
+ if (ret) {
+ cnss_pr_err("Failed to reinit host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+ ret = sdio_priv->ops->probe(sdio_priv->al_client_handle->func,
+ sdio_priv->device_id);
+ if (ret) {
+ cnss_pr_err("Failed to probe host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+int cnss_sdio_call_driver_remove(struct cnss_sdio_data *sdio_priv)
+{
+ struct cnss_plat_data *plat_priv = sdio_priv->plat_priv;
+
+ if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+ test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Skip driver remove\n");
+ return 0;
+ }
+
+ if (!sdio_priv->ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ return -EINVAL;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Recovery set after driver probed.Call shutdown\n");
+ sdio_priv->ops->shutdown(sdio_priv->al_client_handle->func);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ cnss_pr_dbg("driver_ops->remove\n");
+ sdio_priv->ops->remove(sdio_priv->al_client_handle->func);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+ return 0;
+}
+
+/**
+ * cnss_sdio_wlan_register_driver() - cnss wlan register API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to register callback
+ * functions to cnss_sido platform driver. The callback will
+ * be invoked by corresponding wrapper function of this cnss
+ * platform driver.
+ */
+int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver_ops)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_sdio_data *cnss_info;
+ int ret = 0;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ cnss_info = plat_priv->bus_priv;
+ if ((!cnss_info) ||
+ (!cnss_info->al_client_handle) ||
+ (!cnss_info->al_client_handle->func)) {
+ cnss_pr_err("cnss_info is NULL\n");
+ return -ENODEV;
+ }
+
+ if (cnss_info->ops) {
+ cnss_pr_err("Driver has already registered\n");
+ return -EEXIST;
+ }
+ cnss_info->ops = driver_ops;
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
+ return ret;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);
+
+/**
+ * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to detach it from cnss_sido
+ * platform driver.
+ */
+void cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver_ops)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return;
+ }
+
+ cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);
+
+struct sdio_al_client_handle *cnss_sdio_wlan_get_sdio_al_client_handle(
+ struct sdio_func *func)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_sdio_data *cnss_info = plat_priv->bus_priv;
+
+ return cnss_info->al_client_handle;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_get_sdio_al_client_handle);
+
+struct sdio_al_channel_handle *cnss_sdio_wlan_register_sdio_al_channel(
+ struct sdio_al_channel_data *channel_data)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_sdio_data *cnss_info = plat_priv->bus_priv;
+
+ return sdio_al_register_channel(cnss_info->al_client_handle,
+ channel_data);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_sdio_al_channel);
+
+void cnss_sdio_wlan_unregister_sdio_al_channel(
+ struct sdio_al_channel_handle *ch_handle)
+{
+ sdio_al_deregister_channel(ch_handle);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_sdio_al_channel);
+
+int cnss_sdio_register_driver_hdlr(struct cnss_sdio_data *cnss_info,
+ void *data)
+{
+ struct cnss_plat_data *plat_priv = cnss_info->plat_priv;
+ int ret = 0;
+ unsigned int timeout;
+
+ set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ if (test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+ cnss_pr_info("CNSS SDIO driver register in FW_Ready state");
+ cnss_sdio_call_driver_probe(cnss_info);
+ } else if ((*cnss_get_qmi_bypass()) &&
+ (cnss_info->al_client_handle->func)) {
+ cnss_pr_info("qmi bypass enabled");
+ cnss_sdio_call_driver_probe(cnss_info);
+ } else {
+ cnss_pr_info("Wait for FW_Ready");
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ qcn_sdio_card_state(true);
+ timeout = cnss_get_qmi_timeout();
+ if (timeout) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout << 1));
+ }
+ }
+ return 0;
+}
+
+int cnss_sdio_unregister_driver_hdlr(struct cnss_sdio_data *cnss_info)
+{
+ struct cnss_plat_data *plat_priv = cnss_info->plat_priv;
+
+ set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+ cnss_sdio_call_driver_remove(cnss_info);
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ qcn_sdio_card_state(false);
+ cnss_power_off_device(plat_priv);
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ cnss_info->ops = NULL;
+ return 0;
+}
+
+int cnss_sdio_dev_powerup(struct cnss_sdio_data *cnss_info)
+{
+ struct cnss_plat_data *plat_priv = cnss_info->plat_priv;
+ int ret = 0;
+ unsigned int timeout;
+
+ switch (plat_priv->device_id) {
+ case QCN7605_SDIO_DEVICE_ID:
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ qcn_sdio_card_state(true);
+ timeout = cnss_get_qmi_timeout();
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout >> 1));
+ cnss_set_pin_connect_status(plat_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%lx\n",
+ plat_priv->device_id);
+ ret = -ENODEV;
+ }
+out:
+ return ret;
+}
+
+int cnss_sdio_dev_shutdown(struct cnss_sdio_data *cnss_info)
+{
+ struct cnss_plat_data *plat_priv = cnss_info->plat_priv;
+
+ cnss_sdio_call_driver_remove(cnss_info);
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ /*qcn_sdio_card_state(false);*/
+ cnss_power_off_device(plat_priv);
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return 0;
+}
+
+void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv)
+{
+ cnss_pr_err("Timeout waiting for FW ready indication\n");
+}
+
+static int cnss_sdio_probe(struct sdio_al_client_handle *pal_cli_handle)
+{
+ struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct sdio_device_id *device_id;
+
+ device_id = devm_kzalloc(&plat_priv->plat_dev->dev,
+ sizeof(struct sdio_device_id),
+ GFP_KERNEL);
+ device_id->class = pal_cli_handle->func->class;
+ device_id->vendor = pal_cli_handle->func->vendor;
+ device_id->device = pal_cli_handle->func->device;
+ sdio_info->device_id = device_id;
+
+ if (pal_cli_handle->func)
+ cnss_pr_info("CNSS SDIO AL Probe for device Id: 0x%x\n",
+ pal_cli_handle->func->device);
+ clear_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state);
+ plat_priv->device_id = pal_cli_handle->func->device;
+ cnss_register_subsys(sdio_info->plat_priv);
+ return 0;
+}
+
+static int cnss_sdio_remove(struct sdio_al_client_handle *pal_cli_handle)
+{
+ struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv;
+ struct cnss_plat_data *plat_priv = sdio_info->plat_priv;
+
+ if (pal_cli_handle->func)
+ cnss_pr_err(
+ "SDIO AL remove for device Id: 0x%x in driver state %lu\n",
+ pal_cli_handle->func->device,
+ plat_priv->driver_state);
+
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ set_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state);
+ if (sdio_info->ops &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ cnss_pr_err("Triggering driver_ops remove\n");
+ sdio_info->ops->update_status(
+ sdio_info->al_client_handle->func,
+ CNSS_FW_DOWN);
+ sdio_info->ops->remove(sdio_info->al_client_handle->func);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ cnss_unregister_subsys(plat_priv);
+ devm_kfree(&plat_priv->plat_dev->dev, (void *)sdio_info->device_id);
+
+ return 0;
+}
+
+static void cnss_sdio_pm(struct sdio_al_client_handle *pal_cli_handle,
+ enum sdio_al_lpm_event event)
+{
+ struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv;
+ struct sdio_func *func = sdio_info->al_client_handle->func;
+
+ if (!sdio_info->ops) {
+ cnss_pr_err("Ignore LPM event\n");
+ return;
+ }
+
+ if (event == LPM_ENTER) {
+ cnss_pr_info("Entering LPM\n");
+ sdio_info->ops->suspend(&func->dev);
+ } else {
+ cnss_pr_info("Exiting LPM\n");
+ sdio_info->ops->resume(&func->dev);
+ }
+}
+
+struct sdio_al_client_data al_cli_data = {
+ .name = "SDIO_AL_CLIENT_WLAN",
+ .probe = cnss_sdio_probe,
+ .remove = cnss_sdio_remove,
+ .lpm_notify_cb = cnss_sdio_pm,
+};
+
+int cnss_sdio_init(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_sdio_data *sdio_info;
+ struct sdio_al_client_handle *al_client_handle;
+ int ret = 0;
+
+ if (sdio_al_is_ready()) {
+ cnss_pr_err("sdio_al not ready, defer probe\n");
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
+
+ al_client_handle = sdio_al_register_client(&al_cli_data);
+ if (!al_client_handle) {
+ cnss_pr_err("sdio al registration failed!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ sdio_info = devm_kzalloc(&plat_priv->plat_dev->dev, sizeof(*sdio_info),
+ GFP_KERNEL);
+ if (!sdio_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ al_client_handle->client_priv = sdio_info;
+ sdio_info->al_client_handle = al_client_handle;
+ sdio_info->plat_priv = plat_priv;
+ plat_priv->bus_priv = sdio_info;
+
+out:
+ return ret;
+}
+
+int cnss_sdio_deinit(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_sdio_data *sdio_info = plat_priv->bus_priv;
+
+ sdio_al_deregister_client(sdio_info->al_client_handle);
+ return 0;
+}
diff --git a/drivers/net/wireless/cnss2/sdio.h b/drivers/net/wireless/cnss2/sdio.h
new file mode 100644
index 000000000000..1f782fa61f79
--- /dev/null
+++ b/drivers/net/wireless/cnss2/sdio.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_SDIO_H
+#define _CNSS_SDIO_H
+
+#include "main.h"
+#ifdef CONFIG_SDIO_QCN
+#include <linux/qcn_sdio_al.h>
+
+struct cnss_sdio_data {
+ struct cnss_plat_data *plat_priv;
+ struct sdio_al_client_handle *al_client_handle;
+ struct cnss_sdio_wlan_driver *ops;
+ struct sdio_device_id *device_id;
+ void *client_priv;
+};
+
+int cnss_sdio_init(struct cnss_plat_data *plat_priv);
+int cnss_sdio_deinit(struct cnss_plat_data *plat_priv);
+int cnss_sdio_register_driver_hdlr(struct cnss_sdio_data *sdio_info,
+ void *data);
+int cnss_sdio_unregister_driver_hdlr(struct cnss_sdio_data *sdio_info);
+int cnss_sdio_dev_powerup(struct cnss_sdio_data *cnss_info);
+int cnss_sdio_dev_shutdown(struct cnss_sdio_data *cnss_info);
+int cnss_sdio_call_driver_probe(struct cnss_sdio_data *sdio_priv);
+int cnss_sdio_call_driver_remove(struct cnss_sdio_data *sdio_priv);
+void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv);
+#else
+inline int cnss_sdio_init(void *plat_priv)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_deinit(void *plat_priv)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_register_driver_hdlr(void *sdio_info,
+ void *data)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_unregister_driver_hdlr(void *sdio_info)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_dev_powerup(void *cnss_info)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_dev_shutdown(void *cnss_info)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_call_driver_probe(void *sdio_priv)
+{
+ return -EINVAL;
+}
+
+inline int cnss_sdio_call_driver_remove(void *sdio_priv)
+{
+ return -EINVAL;
+}
+
+inline void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv)
+{
+ /* no op */
+}
+#endif
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index dff08a2896a3..d271eaf1f949 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -49,7 +49,8 @@ static const struct lbs_fw_table fw_table[] = {
{ MODEL_8388, "libertas/usb8388_v5.bin", NULL },
{ MODEL_8388, "libertas/usb8388.bin", NULL },
{ MODEL_8388, "usb8388.bin", NULL },
- { MODEL_8682, "libertas/usb8682.bin", NULL }
+ { MODEL_8682, "libertas/usb8682.bin", NULL },
+ { 0, NULL, NULL }
};
static struct usb_device_id if_usb_table[] = {
diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c
index 626ff300352b..1fd3f22796a7 100644
--- a/drivers/net/wireless/realtek/rtlwifi/ps.c
+++ b/drivers/net/wireless/realtek/rtlwifi/ps.c
@@ -781,6 +781,9 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
return;
} else {
noa_num = (noa_len - 2) / 13;
+ if (noa_num > P2P_MAX_NOA_NUM)
+ noa_num = P2P_MAX_NOA_NUM;
+
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
@@ -875,6 +878,9 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
return;
} else {
noa_num = (noa_len - 2) / 13;
+ if (noa_num > P2P_MAX_NOA_NUM)
+ noa_num = P2P_MAX_NOA_NUM;
+
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 60b26f32d31d..2008c6a02b8a 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -620,7 +620,6 @@ err_tx_unbind:
err_unmap:
xenvif_unmap_frontend_rings(queue);
err:
- module_put(THIS_MODULE);
return err;
}
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 574c93a24180..89eec6fead75 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -874,9 +874,9 @@ static int xennet_set_skb_gso(struct sk_buff *skb,
return 0;
}
-static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
- struct sk_buff *skb,
- struct sk_buff_head *list)
+static int xennet_fill_frags(struct netfront_queue *queue,
+ struct sk_buff *skb,
+ struct sk_buff_head *list)
{
RING_IDX cons = queue->rx.rsp_cons;
struct sk_buff *nskb;
@@ -895,7 +895,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
queue->rx.rsp_cons = ++cons + skb_queue_len(list);
kfree_skb(nskb);
- return ~0U;
+ return -ENOENT;
}
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
@@ -906,7 +906,9 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
kfree_skb(nskb);
}
- return cons;
+ queue->rx.rsp_cons = cons;
+
+ return 0;
}
static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
@@ -1032,8 +1034,7 @@ err:
skb->data_len = rx->status;
skb->len += rx->status;
- i = xennet_fill_frags(queue, skb, &tmpq);
- if (unlikely(i == ~0U))
+ if (unlikely(xennet_fill_frags(queue, skb, &tmpq)))
goto err;
if (rx->flags & XEN_NETRXF_csum_blank)
@@ -1043,7 +1044,7 @@ err:
__skb_queue_tail(&rxq, skb);
- queue->rx.rsp_cons = ++i;
+ i = ++queue->rx.rsp_cons;
work_done++;
}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 005ea632ba53..8524faf28acb 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -160,6 +160,15 @@ struct dino_device
(struct dino_device *)__pdata; })
+/* Check if PCI device is behind a Card-mode Dino. */
+static int pci_dev_is_behind_card_dino(struct pci_dev *dev)
+{
+ struct dino_device *dino_dev;
+
+ dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge));
+ return is_card_dino(&dino_dev->hba.dev->id);
+}
+
/*
* Dino Configuration Space Accessor Functions
*/
@@ -442,6 +451,21 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
+#ifdef CONFIG_TULIP
+static void pci_fixup_tulip(struct pci_dev *dev)
+{
+ if (!pci_dev_is_behind_card_dino(dev))
+ return;
+ if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM))
+ return;
+ pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n",
+ pci_name(dev));
+ /* Disable this card by zeroing the PCI resources */
+ memset(&dev->resource[0], 0, sizeof(dev->resource[0]));
+ memset(&dev->resource[1], 0, sizeof(dev->resource[1]));
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip);
+#endif /* CONFIG_TULIP */
static void __init
dino_bios_init(void)
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 98aac17a91b5..9be5d601d38a 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -2067,6 +2067,7 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
u32 ep_l1sub_cap_reg1_offset = 0;
u32 ep_link_ctrlstts_offset = 0;
u32 ep_dev_ctrl2stts2_offset = 0;
+ u32 wr_ofst = 0;
if (testcase >= 5 && testcase <= 10) {
current_offset =
@@ -2428,22 +2429,24 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
break;
}
+ wr_ofst = wr_offset;
+
PCIE_DBG_FS(dev,
"base: %s: 0x%p\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n",
dev->res[base_sel - 1].name,
dev->res[base_sel - 1].base,
- wr_offset, wr_mask, wr_value);
+ wr_ofst, wr_mask, wr_value);
base_sel_size = resource_size(dev->res[base_sel - 1].resource);
- if (wr_offset > base_sel_size - 4 ||
- msm_pcie_check_align(dev, wr_offset))
+ if (wr_ofst > base_sel_size - 4 ||
+ msm_pcie_check_align(dev, wr_ofst))
PCIE_DBG_FS(dev,
"PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n",
- dev->rc_idx, wr_offset, base_sel_size - 4);
+ dev->rc_idx, wr_ofst, base_sel_size - 4);
else
msm_pcie_write_reg_field(dev->res[base_sel - 1].base,
- wr_offset, wr_mask, wr_value);
+ wr_ofst, wr_mask, wr_value);
break;
case 13: /* dump all registers of base_sel */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 82b0c2cc2fd3..b7f65fc54dc2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -704,19 +704,6 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
}
/**
- * pci_power_up - Put the given device into D0 forcibly
- * @dev: PCI device to power up
- */
-void pci_power_up(struct pci_dev *dev)
-{
- if (platform_pci_power_manageable(dev))
- platform_pci_set_power_state(dev, PCI_D0);
-
- pci_raw_set_power_state(dev, PCI_D0);
- pci_update_current_state(dev, PCI_D0);
-}
-
-/**
* pci_platform_power_transition - Use platform to change device power state
* @dev: PCI device to handle.
* @state: State to put the device into.
@@ -892,6 +879,17 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
EXPORT_SYMBOL(pci_set_power_state);
/**
+ * pci_power_up - Put the given device into D0 forcibly
+ * @dev: PCI device to power up
+ */
+void pci_power_up(struct pci_dev *dev)
+{
+ __pci_start_power_transition(dev, PCI_D0);
+ pci_raw_set_power_state(dev, PCI_D0);
+ pci_update_current_state(dev, PCI_D0);
+}
+
+/**
* pci_choose_state - Choose the power state of a PCI device
* @dev: PCI device to be suspended
* @state: target sleep state for the whole system. This is the value
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 0fd7fd2b0f72..a30e967d75c2 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -52,7 +52,9 @@ static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
{
- writel(val, pmx->regs[bank] + reg);
+ writel_relaxed(val, pmx->regs[bank] + reg);
+ /* make sure pinmux register write completed */
+ pmx_readl(pmx, bank, reg);
}
static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 6d5308b3dd0b..c19abd4075a3 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017,2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1345,6 +1345,12 @@ int qcom_batt_init(void)
if (!chip->pl_ws)
goto cleanup;
+ INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
+ INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
+ INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
+ INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work);
+ INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work);
+
chip->fcc_votable = create_votable("FCC", VOTE_MIN,
pl_fcc_vote_callback,
chip);
@@ -1399,12 +1405,6 @@ int qcom_batt_init(void)
vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
- INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
- INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
- INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
- INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work);
- INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work);
-
rc = pl_register_notifier(chip);
if (rc < 0) {
pr_err("Couldn't register psy notifier rc = %d\n", rc);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e443b0d0b236..0d59c128f734 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -369,7 +369,7 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
goto error;
}
/* Check for trailing stuff. */
- if (i == num_devices && strlen(buf) > 0) {
+ if (i == num_devices && buf && strlen(buf) > 0) {
rc = -EINVAL;
goto error;
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 489e703dc82d..8ecc956ecb59 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1120,6 +1120,8 @@ device_initcall(cio_settle_init);
int sch_is_pseudo_sch(struct subchannel *sch)
{
+ if (!sch->dev.parent)
+ return 0;
return sch == to_css(sch->dev.parent)->pseudo_subchannel;
}
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 1964391db904..a3aaef4c53a3 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -20,6 +20,11 @@
struct kmem_cache *zfcp_fsf_qtcb_cache;
+static bool ber_stop = true;
+module_param(ber_stop, bool, 0600);
+MODULE_PARM_DESC(ber_stop,
+ "Shuts down FCP devices for FCP channels that report a bit-error count in excess of its threshold (default on)");
+
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
@@ -231,10 +236,15 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
case FSF_STATUS_READ_SENSE_DATA_AVAIL:
break;
case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
- dev_warn(&adapter->ccw_device->dev,
- "The error threshold for checksum statistics "
- "has been exceeded\n");
zfcp_dbf_hba_bit_err("fssrh_3", req);
+ if (ber_stop) {
+ dev_warn(&adapter->ccw_device->dev,
+ "All paths over this FCP device are disused because of excessive bit errors\n");
+ zfcp_erp_adapter_shutdown(adapter, 0, "fssrh_b");
+ } else {
+ dev_warn(&adapter->ccw_device->dev,
+ "The error threshold for checksum statistics has been exceeded\n");
+ }
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 19bffe0b2cc0..2cbfec6a7466 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4219,11 +4219,11 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
*/
if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
pdev->subsystem_device == 0xC000)
- return -ENODEV;
+ goto out_disable_device;
/* Now check the magic signature byte */
pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
- return -ENODEV;
+ goto out_disable_device;
/* Ok it is probably a megaraid */
}
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 824e27eec7a1..6c4f54aa60df 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -437,6 +437,7 @@ static void qlt_free_session_done(struct work_struct *work)
if (logout_started) {
bool traced = false;
+ u16 cnt = 0;
while (!ACCESS_ONCE(sess->logout_completed)) {
if (!traced) {
@@ -446,6 +447,9 @@ static void qlt_free_session_done(struct work_struct *work)
traced = true;
}
msleep(100);
+ cnt++;
+ if (cnt > 200)
+ break;
}
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087,
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
index bd70339c1242..03d9855a6afd 100644
--- a/drivers/scsi/scsi_logging.c
+++ b/drivers/scsi/scsi_logging.c
@@ -16,57 +16,15 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
-#define SCSI_LOG_SPOOLSIZE 4096
-
-#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG
-#warning SCSI logging bitmask too large
-#endif
-
-struct scsi_log_buf {
- char buffer[SCSI_LOG_SPOOLSIZE];
- unsigned long map;
-};
-
-static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log);
-
static char *scsi_log_reserve_buffer(size_t *len)
{
- struct scsi_log_buf *buf;
- unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE;
- unsigned long idx = 0;
-
- preempt_disable();
- buf = this_cpu_ptr(&scsi_format_log);
- idx = find_first_zero_bit(&buf->map, map_bits);
- if (likely(idx < map_bits)) {
- while (test_and_set_bit(idx, &buf->map)) {
- idx = find_next_zero_bit(&buf->map, map_bits, idx);
- if (idx >= map_bits)
- break;
- }
- }
- if (WARN_ON(idx >= map_bits)) {
- preempt_enable();
- return NULL;
- }
- *len = SCSI_LOG_BUFSIZE;
- return buf->buffer + idx * SCSI_LOG_BUFSIZE;
+ *len = 128;
+ return kmalloc(*len, GFP_ATOMIC);
}
static void scsi_log_release_buffer(char *bufptr)
{
- struct scsi_log_buf *buf;
- unsigned long idx;
- int ret;
-
- buf = this_cpu_ptr(&scsi_format_log);
- if (bufptr >= buf->buffer &&
- bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) {
- idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE;
- ret = test_and_clear_bit(idx, &buf->map);
- WARN_ON(!ret);
- }
- preempt_enable();
+ kfree(bufptr);
}
static inline const char *scmd_name(const struct scsi_cmnd *scmd)
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index bb17221d3d01..1290c542f6d6 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -679,6 +679,14 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct kernfs_node *kn;
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ /*
+ * We need to try to get module, avoiding the module been removed
+ * during delete.
+ */
+ if (scsi_device_get(sdev))
+ return -ENODEV;
kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
WARN_ON_ONCE(!kn);
@@ -693,9 +701,10 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr,
* state into SDEV_DEL.
*/
device_remove_file(dev, attr);
- scsi_remove_device(to_scsi_device(dev));
+ scsi_remove_device(sdev);
if (kn)
sysfs_unbreak_active_protection(kn);
+ scsi_device_put(sdev);
return count;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 02f89779ac81..9c77b89eb893 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -9372,6 +9372,9 @@ int ufshcd_shutdown(struct ufs_hba *hba)
{
int ret = 0;
+ if (!hba->is_powered)
+ goto out;
+
if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
goto out;
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 70fd4035a627..81db4fe93dbc 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -327,7 +327,7 @@ config MSM_IPC_ROUTER_GLINK_XPRT
message exchange.
config MSM_IPC_ROUTER_SDIO_XPRT
- depends on QCOM_SDIO_CLIENT
+ depends on QTI_SDIO_CLIENT
depends on IPC_ROUTER
bool "MSM SDIO XPRT Layer"
help
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 32a457730869..2a3b2a313c69 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -980,7 +980,9 @@ int pil_boot(struct pil_desc *desc)
trace_pil_event("before_init_image", desc);
if (desc->ops->init_image)
- ret = desc->ops->init_image(desc, fw->data, fw->size);
+ ret = desc->ops->init_image(desc, fw->data, fw->size,
+ priv->region_start,
+ priv->region_end - priv->region_start);
if (ret) {
pil_err(desc, "Initializing image failed(rc:%d)\n", ret);
subsys_set_error(desc->subsys_dev, firmware_error_msg);
@@ -997,20 +999,6 @@ int pil_boot(struct pil_desc *desc)
}
if (desc->subsys_vmid > 0) {
- /**
- * In case of modem ssr, we need to assign memory back to linux.
- * This is not true after cold boot since linux already owns it.
- * Also for secure boot devices, modem memory has to be released
- * after MBA is booted
- */
- trace_pil_event("before_assign_mem", desc);
- if (desc->modem_ssr) {
- ret = pil_assign_mem_to_linux(desc, priv->region_start,
- (priv->region_end - priv->region_start));
- if (ret)
- pil_err(desc, "Failed to assign to linux, ret- %d\n",
- ret);
- }
ret = pil_assign_mem_to_subsys_and_linux(desc,
priv->region_start,
(priv->region_end - priv->region_start));
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index 6e74743c8c21..6800fd83944a 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -116,7 +116,7 @@ struct md_ssr_toc /* Shared IMEM ToC struct */
*/
struct pil_reset_ops {
int (*init_image)(struct pil_desc *pil, const u8 *metadata,
- size_t size);
+ size_t size, phys_addr_t addr, size_t sz);
int (*mem_setup)(struct pil_desc *pil, phys_addr_t addr, size_t size);
int (*verify_blob)(struct pil_desc *pil, phys_addr_t phy_addr,
size_t size);
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index f7d183a7bbcc..b7f55bbfe267 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -685,7 +685,7 @@ err_invalid_fw:
}
static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
- size_t size)
+ size_t size, phys_addr_t phy_addr, size_t phy_sz)
{
struct modem_data *drv = dev_get_drvdata(pil->dev);
void *mdata_virt;
@@ -715,6 +715,19 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
wmb();
if (pil->subsys_vmid > 0) {
+ /**
+ * In case of modem ssr,we need to assign memory back to linux.
+ * This is not true after cold boot since linux already owns
+ * it. Also for secure boot devices, modem memory has to be
+ * released after MBA is booted
+ */
+ if (pil->modem_ssr) {
+ ret = pil_assign_mem_to_linux(pil, phy_addr, phy_sz);
+ if (ret)
+ dev_err(pil->dev,
+ "Failed to assign to linux, ret- %d\n",
+ ret);
+ }
ret = pil_assign_mem_to_subsys(pil, mdata_phys,
ALIGN(size, SZ_4K));
if (ret) {
@@ -769,7 +782,8 @@ fail:
}
static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil,
- const u8 *metadata, size_t size)
+ const u8 *metadata, size_t size,
+ phys_addr_t modem_reg, size_t sz_modem_reg)
{
int ret;
@@ -777,7 +791,8 @@ static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil,
if (ret)
return ret;
- return pil_msa_auth_modem_mdt(pil, metadata, size);
+ return pil_msa_auth_modem_mdt(pil, metadata, size,
+ modem_reg, sz_modem_reg);
}
static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index c6bdcee8131e..f4125113efff 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -635,28 +635,7 @@ static int allocate_extra_arg_buffer(struct scm_desc *desc, gfp_t flags)
return 0;
}
-/**
- * scm_call2() - Invoke a syscall in the secure world
- * @fn_id: The function ID for this syscall
- * @desc: Descriptor structure containing arguments and return values
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This should *only* be called in pre-emptible context.
- *
- * A note on cache maintenance:
- * Note that any buffers that are expected to be accessed by the secure world
- * must be flushed before invoking scm_call and invalidated in the cache
- * immediately after scm_call returns. An important point that must be noted
- * is that on ARMV8 architectures, invalidation actually also causes a dirty
- * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of
- * paramount importance that the buffer be flushed before invoking scm_call2,
- * even if you don't care about the contents of that buffer.
- *
- * Note that cache maintenance on the argument buffer (desc->args) is taken care
- * of by scm_call2; however, callers are responsible for any other cached
- * buffers passed over to the secure world.
-*/
-int scm_call2(u32 fn_id, struct scm_desc *desc)
+static int __scm_call2(u32 fn_id, struct scm_desc *desc, bool retry)
{
int arglen = desc->arginfo & 0xf;
int ret, retry_count = 0;
@@ -670,7 +649,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
return ret;
x0 = fn_id | scm_version_mask;
-
do {
mutex_lock(&scm_lock);
@@ -700,13 +678,15 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
mutex_unlock(&scm_lmh_lock);
mutex_unlock(&scm_lock);
+ if (!retry)
+ goto out;
if (ret == SCM_V2_EBUSY)
msleep(SCM_EBUSY_WAIT_MS);
if (retry_count == 33)
pr_warn("scm: secure world has been busy for 1 second!\n");
- } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
-
+ } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
+out:
if (ret < 0)
pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
@@ -717,9 +697,47 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
return scm_remap_error(ret);
return 0;
}
+
+/**
+ * scm_call2() - Invoke a syscall in the secure world
+ * @fn_id: The function ID for this syscall
+ * @desc: Descriptor structure containing arguments and return values
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This should *only* be called in pre-emptible context.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking scm_call and invalidated in the cache
+ * immediately after scm_call returns. An important point that must be noted
+ * is that on ARMV8 architectures, invalidation actually also causes a dirty
+ * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of
+ * paramount importance that the buffer be flushed before invoking scm_call2,
+ * even if you don't care about the contents of that buffer.
+ *
+ * Note that cache maintenance on the argument buffer (desc->args) is taken care
+ * of by scm_call2; however, callers are responsible for any other cached
+ * buffers passed over to the secure world.
+ */
+int scm_call2(u32 fn_id, struct scm_desc *desc)
+{
+ return __scm_call2(fn_id, desc, true);
+}
EXPORT_SYMBOL(scm_call2);
/**
+ * scm_call2_noretry() - Invoke a syscall in the secure world
+ *
+ * Similar to scm_call2 except that there is no retry mechanism
+ * implemented.
+ */
+int scm_call2_noretry(u32 fn_id, struct scm_desc *desc)
+{
+ return __scm_call2(fn_id, desc, false);
+}
+EXPORT_SYMBOL(scm_call2_noretry);
+
+/**
* scm_call2_atomic() - Invoke a syscall in the secure world
*
* Similar to scm_call2 except that this can be invoked in atomic context.
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index b448f5297f95..c6dff952ff3a 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -582,7 +582,8 @@ static void pil_remove_proxy_vote(struct pil_desc *pil)
}
static int pil_init_image_trusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
+ const u8 *metadata, size_t size,
+ phys_addr_t addr, size_t sz)
{
struct pil_tz_data *d = desc_to_data(pil);
struct pas_init_image_req {
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 799bf2988b30..cf1ea19dbc6a 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1390,8 +1390,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
dd->write_buf = dd->cur_transfer->tx_buf;
dd->tx_done = false;
dd->rx_done = false;
- init_completion(&dd->tx_transfer_complete);
- init_completion(&dd->rx_transfer_complete);
+ reinit_completion(&dd->tx_transfer_complete);
+ reinit_completion(&dd->rx_transfer_complete);
if (dd->cur_transfer->bits_per_word)
bpw = dd->cur_transfer->bits_per_word;
else
@@ -2716,6 +2716,8 @@ skip_dma_resources:
spin_lock_init(&dd->queue_lock);
mutex_init(&dd->core_lock);
init_waitqueue_head(&dd->continue_suspend);
+ init_completion(&dd->tx_transfer_complete);
+ init_completion(&dd->rx_transfer_complete);
if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr,
dd->mem_size, SPI_DRV_NAME)) {
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index c9e7b8b6e21c..80070f67a895 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -52,6 +52,7 @@
#include <linux/circ_buf.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
+#include <linux/poll.h>
#define CREATE_TRACE_POINTS
#include <trace/events/almk.h>
@@ -118,19 +119,6 @@ void handle_lmk_event(struct task_struct *selected, int selected_tasksize,
int tail;
struct lmk_event *events;
struct lmk_event *event;
- int res;
- char taskname[MAX_TASKNAME];
-
- res = get_cmdline(selected, taskname, MAX_TASKNAME - 1);
-
- /* No valid process name means this is definitely not associated with a
- * userspace activity.
- */
-
- if (res <= 0 || res >= MAX_TASKNAME)
- return;
-
- taskname[res] = '\0';
spin_lock(&lmk_event_lock);
@@ -146,7 +134,7 @@ void handle_lmk_event(struct task_struct *selected, int selected_tasksize,
events = (struct lmk_event *) event_buffer.buf;
event = &events[head];
- memcpy(event->taskname, taskname, res + 1);
+ strncpy(event->taskname, selected->comm, MAX_TASKNAME);
event->pid = selected->pid;
event->uid = from_kuid_munged(current_user_ns(), task_uid(selected));
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 18c2b6daf588..15937e0ef4d9 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -813,7 +813,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
if (par->gamma.curves && gamma) {
if (fbtft_gamma_parse_str(par,
par->gamma.curves, gamma, strlen(gamma)))
- goto alloc_fail;
+ goto release_framebuf;
}
/* Transmit buffer */
@@ -836,7 +836,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL);
}
if (!txbuf)
- goto alloc_fail;
+ goto release_framebuf;
par->txbuf.buf = txbuf;
par->txbuf.len = txbuflen;
}
@@ -872,6 +872,9 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
return info;
+release_framebuf:
+ framebuffer_release(info);
+
alloc_fail:
vfree(vmem);
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 58b6403458b7..2f3c9217d650 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -1668,8 +1668,10 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
priv->hw->max_signal = 100;
- if (vnt_init(priv))
+ if (vnt_init(priv)) {
+ device_free_info(priv);
return -ENODEV;
+ }
device_print_info(priv);
pci_set_drvdata(pcid, priv);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 04cf31c119ef..651fa346af44 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -804,7 +804,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
mod_delayed_work(system_freezable_wq, &tz->poll_queue,
msecs_to_jiffies(delay));
else
- cancel_delayed_work(&tz->poll_queue);
+ cancel_delayed_work_sync(&tz->poll_queue);
}
static void monitor_thermal_zone(struct thermal_zone_device *tz)
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index b1c6bd3d483f..c27db21b71ba 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -701,7 +701,8 @@ err_uart:
static void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
- uart_unregister_driver(&ulite_uart_driver);
+ if (ulite_uart_driver.state)
+ uart_unregister_driver(&ulite_uart_driver);
}
module_init(ulite_init);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 071964c7847f..07c3c3449147 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -458,6 +458,7 @@ static void usblp_cleanup(struct usblp *usblp)
kfree(usblp->readbuf);
kfree(usblp->device_id_string);
kfree(usblp->statusbuf);
+ usb_put_intf(usblp->intf);
kfree(usblp);
}
@@ -474,10 +475,12 @@ static int usblp_release(struct inode *inode, struct file *file)
mutex_lock(&usblp_mutex);
usblp->used = 0;
- if (usblp->present) {
+ if (usblp->present)
usblp_unlink_urbs(usblp);
- usb_autopm_put_interface(usblp->intf);
- } else /* finish cleanup from disconnect */
+
+ usb_autopm_put_interface(usblp->intf);
+
+ if (!usblp->present) /* finish cleanup from disconnect */
usblp_cleanup(usblp);
mutex_unlock(&usblp_mutex);
return 0;
@@ -1118,7 +1121,7 @@ static int usblp_probe(struct usb_interface *intf,
init_waitqueue_head(&usblp->wwait);
init_usb_anchor(&usblp->urbs);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
- usblp->intf = intf;
+ usblp->intf = usb_get_intf(intf);
/* Malloc device ID string buffer to the largest expected length,
* since we can re-query it on an ioctl and a dynamic string
@@ -1207,6 +1210,7 @@ abort:
kfree(usblp->readbuf);
kfree(usblp->statusbuf);
kfree(usblp->device_id_string);
+ usb_put_intf(usblp->intf);
kfree(usblp);
abort_ret:
return retval;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b63ecb487aff..5c9ec1fa563a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -441,6 +441,7 @@ config USB_CONFIGFS_F_PTP
config USB_CONFIGFS_F_ACC
boolean "Accessory gadget"
depends on USB_CONFIGFS
+ depends on HID=y
select USB_F_ACC
help
USB gadget Accessory support
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 85f1f282c1d5..0321b9ce9faf 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -50,6 +50,7 @@
#define DRIVER_VERSION "02 May 2005"
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
+#define POWER_BUDGET_3 900 /* in mA */
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -2435,7 +2436,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
- dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
+ dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET_3;
dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
#ifdef CONFIG_USB_OTG
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 90d24f62bd81..ea43cb74a6f2 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -1225,11 +1225,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
bl = bytes - n;
- if (bl > 3)
- bl = 3;
+ if (bl > 4)
+ bl = 4;
for (i = 0; i < bl; i++)
- data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
+ data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF);
}
break;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a283665e2ed5..89b4cc8265c5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1024,7 +1024,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
command |= CMD_CSS;
writel(command, &xhci->op_regs->command);
if (xhci_handshake(&xhci->op_regs->status,
- STS_SAVE, 0, 10 * 1000)) {
+ STS_SAVE, 0, 20 * 1000)) {
xhci_warn(xhci, "WARN: xHC save state timeout\n");
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
@@ -1085,6 +1085,18 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
hibernated = true;
if (!hibernated) {
+ /*
+ * Some controllers might lose power during suspend, so wait
+ * for controller not ready bit to clear, just as in xHC init.
+ */
+ retval = xhci_handshake(&xhci->op_regs->status,
+ STS_CNR, 0, 10 * 1000 * 1000);
+ if (retval) {
+ xhci_warn(xhci, "Controller not ready at resume %d\n",
+ retval);
+ spin_unlock_irq(&xhci->lock);
+ return retval;
+ }
/* step 1: restore register */
xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */
@@ -4575,12 +4587,12 @@ static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
desc, state, timeout);
- /* If we found we can't enable hub-initiated LPM, or
+ /* If we found we can't enable hub-initiated LPM, and
* the U1 or U2 exit latency was too high to allow
- * device-initiated LPM as well, just stop searching.
+ * device-initiated LPM as well, then we will disable LPM
+ * for this device, so stop searching any further.
*/
- if (alt_timeout == USB3_LPM_DISABLED ||
- alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+ if (alt_timeout == USB3_LPM_DISABLED) {
*timeout = alt_timeout;
return -E2BIG;
}
@@ -4691,10 +4703,12 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
if (driver && driver->disable_hub_initiated_lpm) {
- dev_dbg(&udev->dev, "Hub-initiated %s disabled "
- "at request of driver %s\n",
- state_name, driver->name);
- return xhci_get_timeout_no_hub_lpm(udev, state);
+ dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n",
+ state_name, driver->name);
+ timeout = xhci_get_timeout_no_hub_lpm(udev,
+ state);
+ if (timeout == USB3_LPM_DISABLED)
+ return timeout;
}
}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index a4dbb0cd80da..0fecc002fa9f 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -724,6 +724,10 @@ static int mts_usb_probe(struct usb_interface *intf,
}
+ if (ep_in_current != &ep_in_set[2]) {
+ MTS_WARNING("couldn't find two input bulk endpoints. Bailing out.\n");
+ return -ENODEV;
+ }
if ( ep_out == -1 ) {
MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index b8f3e4199e20..8006d75efc09 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -46,16 +46,6 @@ config USB_SEVSEG
To compile this driver as a module, choose M here: the
module will be called usbsevseg.
-config USB_RIO500
- tristate "USB Diamond Rio500 support"
- help
- Say Y here if you want to connect a USB Rio500 mp3 player to your
- computer's USB port. Please read <file:Documentation/usb/rio.txt>
- for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called rio500.
-
config USB_LEGOTOWER
tristate "USB Lego Infrared Tower support"
help
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 4f417e23cf1a..4986df051c22 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
-obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 3071c0ef909b..6d849e7dc842 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -80,6 +80,7 @@ struct adu_device {
char serial_number[8];
int open_count; /* number of times this port has been opened */
+ unsigned long disconnected:1;
char *read_buffer_primary;
int read_buffer_length;
@@ -121,7 +122,7 @@ static void adu_abort_transfers(struct adu_device *dev)
{
unsigned long flags;
- if (dev->udev == NULL)
+ if (dev->disconnected)
return;
/* shutdown transfer */
@@ -151,6 +152,7 @@ static void adu_delete(struct adu_device *dev)
kfree(dev->read_buffer_secondary);
kfree(dev->interrupt_in_buffer);
kfree(dev->interrupt_out_buffer);
+ usb_put_dev(dev->udev);
kfree(dev);
}
@@ -244,7 +246,7 @@ static int adu_open(struct inode *inode, struct file *file)
}
dev = usb_get_intfdata(interface);
- if (!dev || !dev->udev) {
+ if (!dev) {
retval = -ENODEV;
goto exit_no_device;
}
@@ -327,7 +329,7 @@ static int adu_release(struct inode *inode, struct file *file)
}
adu_release_internal(dev);
- if (dev->udev == NULL) {
+ if (dev->disconnected) {
/* the device was unplugged before the file was released */
if (!dev->open_count) /* ... and we're the last user */
adu_delete(dev);
@@ -356,7 +358,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
return -ERESTARTSYS;
/* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval);
goto exit;
@@ -525,7 +527,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
goto exit_nolock;
/* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval);
goto exit;
@@ -680,7 +682,7 @@ static int adu_probe(struct usb_interface *interface,
mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock);
- dev->udev = udev;
+ dev->udev = usb_get_dev(udev);
init_waitqueue_head(&dev->read_wait);
init_waitqueue_head(&dev->write_wait);
@@ -800,19 +802,21 @@ error:
static void adu_disconnect(struct usb_interface *interface)
{
struct adu_device *dev;
- int minor;
dev = usb_get_intfdata(interface);
- mutex_lock(&dev->mtx); /* not interruptible */
- dev->udev = NULL; /* poison */
- minor = dev->minor;
usb_deregister_dev(interface, &adu_class);
- mutex_unlock(&dev->mtx);
+
+ usb_poison_urb(dev->interrupt_in_urb);
+ usb_poison_urb(dev->interrupt_out_urb);
mutex_lock(&adutux_mutex);
usb_set_intfdata(interface, NULL);
+ mutex_lock(&dev->mtx); /* not interruptible */
+ dev->disconnected = 1;
+ mutex_unlock(&dev->mtx);
+
/* if the device is not opened, then we clean up right now */
if (!dev->open_count)
adu_delete(dev);
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 23c794813e6a..a3692811248b 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -96,6 +96,7 @@ static void chaoskey_free(struct chaoskey *dev)
usb_dbg(dev->interface, "free");
kfree(dev->name);
kfree(dev->buf);
+ usb_put_intf(dev->interface);
kfree(dev);
}
@@ -144,6 +145,8 @@ static int chaoskey_probe(struct usb_interface *interface,
if (dev == NULL)
return -ENOMEM;
+ dev->interface = usb_get_intf(interface);
+
dev->buf = kmalloc(size, GFP_KERNEL);
if (dev->buf == NULL) {
@@ -169,8 +172,6 @@ static int chaoskey_probe(struct usb_interface *interface,
strcat(dev->name, udev->serial);
}
- dev->interface = interface;
-
dev->in_ep = in_ep;
dev->size = size;
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 836fb65c3c72..83342e579233 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -89,6 +89,7 @@ struct iowarrior {
char chip_serial[9]; /* the serial number string of the chip connected */
int report_size; /* number of bytes in a report */
u16 product_id;
+ struct usb_anchor submitted;
};
/*--------------*/
@@ -248,6 +249,7 @@ static inline void iowarrior_delete(struct iowarrior *dev)
kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue);
+ usb_put_intf(dev->interface);
kfree(dev);
}
@@ -436,11 +438,13 @@ static ssize_t iowarrior_write(struct file *file,
retval = -EFAULT;
goto error;
}
+ usb_anchor_urb(int_out_urb, &dev->submitted);
retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
if (retval) {
dev_dbg(&dev->interface->dev,
"submit error %d for urb nr.%d\n",
retval, atomic_read(&dev->write_busy));
+ usb_unanchor_urb(int_out_urb);
goto error;
}
/* submit was ok */
@@ -782,11 +786,13 @@ static int iowarrior_probe(struct usb_interface *interface,
init_waitqueue_head(&dev->write_wait);
dev->udev = udev;
- dev->interface = interface;
+ dev->interface = usb_get_intf(interface);
iface_desc = interface->cur_altsetting;
dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
+ init_usb_anchor(&dev->submitted);
+
/* set up the endpoint information */
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
@@ -898,8 +904,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
dev = usb_get_intfdata(interface);
mutex_lock(&iowarrior_open_disc_lock);
usb_set_intfdata(interface, NULL);
- /* prevent device read, write and ioctl */
- dev->present = 0;
minor = dev->minor;
mutex_unlock(&iowarrior_open_disc_lock);
@@ -910,8 +914,7 @@ static void iowarrior_disconnect(struct usb_interface *interface)
mutex_lock(&dev->mutex);
/* prevent device read, write and ioctl */
-
- mutex_unlock(&dev->mutex);
+ dev->present = 0;
if (dev->opened) {
/* There is a process that holds a filedescriptor to the device ,
@@ -919,10 +922,13 @@ static void iowarrior_disconnect(struct usb_interface *interface)
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);
}
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index e9113238d9e3..7da242bbe37b 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -158,6 +158,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
struct ld_usb {
struct mutex mutex; /* locks this structure */
struct usb_interface* intf; /* save off the usb interface pointer */
+ unsigned long disconnected:1;
int open_count; /* number of times this port has been opened */
@@ -197,12 +198,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
/* shutdown transfer */
if (dev->interrupt_in_running) {
dev->interrupt_in_running = 0;
- if (dev->intf)
- usb_kill_urb(dev->interrupt_in_urb);
+ usb_kill_urb(dev->interrupt_in_urb);
}
if (dev->interrupt_out_busy)
- if (dev->intf)
- usb_kill_urb(dev->interrupt_out_urb);
+ usb_kill_urb(dev->interrupt_out_urb);
}
/**
@@ -210,8 +209,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
*/
static void ld_usb_delete(struct ld_usb *dev)
{
- ld_usb_abort_transfers(dev);
-
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -267,7 +264,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
resubmit:
/* resubmit if we're still running */
- if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) {
+ if (dev->interrupt_in_running && !dev->buffer_overflow) {
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
if (retval) {
dev_err(&dev->intf->dev,
@@ -387,16 +384,13 @@ static int ld_usb_release(struct inode *inode, struct file *file)
goto exit;
}
- if (mutex_lock_interruptible(&dev->mutex)) {
- retval = -ERESTARTSYS;
- goto exit;
- }
+ mutex_lock(&dev->mutex);
if (dev->open_count != 1) {
retval = -ENODEV;
goto unlock_exit;
}
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
/* the device was unplugged before the file was released */
mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
@@ -427,7 +421,7 @@ static unsigned int ld_usb_poll(struct file *file, poll_table *wait)
dev = file->private_data;
- if (!dev->intf)
+ if (dev->disconnected)
return POLLERR | POLLHUP;
poll_wait(file, &dev->read_wait, wait);
@@ -466,7 +460,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
}
/* verify that the device wasn't unplugged */
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -474,7 +468,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
/* wait for data */
spin_lock_irq(&dev->rbsl);
- if (dev->ring_head == dev->ring_tail) {
+ while (dev->ring_head == dev->ring_tail) {
dev->interrupt_in_done = 0;
spin_unlock_irq(&dev->rbsl);
if (file->f_flags & O_NONBLOCK) {
@@ -484,12 +478,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
if (retval < 0)
goto unlock_exit;
- } else {
- spin_unlock_irq(&dev->rbsl);
+
+ spin_lock_irq(&dev->rbsl);
}
+ spin_unlock_irq(&dev->rbsl);
/* actual_buffer contains actual_length + interrupt_in_buffer */
actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
+ if (*actual_buffer > dev->interrupt_in_endpoint_size) {
+ retval = -EIO;
+ goto unlock_exit;
+ }
bytes_to_read = min(count, *actual_buffer);
if (bytes_to_read < *actual_buffer)
dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
@@ -546,7 +545,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
}
/* verify that the device wasn't unplugged */
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -709,7 +708,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
- dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
+ dev->ring_buffer = kcalloc(ring_buffer_size,
+ sizeof(size_t) + dev->interrupt_in_endpoint_size,
+ GFP_KERNEL);
if (!dev->ring_buffer) {
dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
goto error;
@@ -782,6 +783,9 @@ static void ld_usb_disconnect(struct usb_interface *intf)
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
+ usb_poison_urb(dev->interrupt_in_urb);
+ usb_poison_urb(dev->interrupt_out_urb);
+
mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
@@ -789,7 +793,7 @@ static void ld_usb_disconnect(struct usb_interface *intf)
mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
- dev->intf = NULL;
+ dev->disconnected = 1;
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 0ec9ee573ffa..32b41eb07f00 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -185,7 +185,6 @@ static const struct usb_device_id tower_table[] = {
};
MODULE_DEVICE_TABLE (usb, tower_table);
-static DEFINE_MUTEX(open_disc_mutex);
#define LEGO_USB_TOWER_MINOR_BASE 160
@@ -197,6 +196,7 @@ struct lego_usb_tower {
unsigned char minor; /* the starting minor number for this device */
int open_count; /* number of times this port has been opened */
+ unsigned long disconnected:1;
char* read_buffer;
size_t read_buffer_length; /* this much came in */
@@ -296,14 +296,13 @@ static inline void lego_usb_tower_debug_data(struct device *dev,
*/
static inline void tower_delete (struct lego_usb_tower *dev)
{
- tower_abort_transfers (dev);
-
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
kfree (dev->read_buffer);
kfree (dev->interrupt_in_buffer);
kfree (dev->interrupt_out_buffer);
+ usb_put_dev(dev->udev);
kfree (dev);
}
@@ -338,18 +337,14 @@ static int tower_open (struct inode *inode, struct file *file)
goto exit;
}
- mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface);
-
if (!dev) {
- mutex_unlock(&open_disc_mutex);
retval = -ENODEV;
goto exit;
}
/* lock this device */
if (mutex_lock_interruptible(&dev->lock)) {
- mutex_unlock(&open_disc_mutex);
retval = -ERESTARTSYS;
goto exit;
}
@@ -357,12 +352,9 @@ static int tower_open (struct inode *inode, struct file *file)
/* allow opening only once */
if (dev->open_count) {
- mutex_unlock(&open_disc_mutex);
retval = -EBUSY;
goto unlock_exit;
}
- dev->open_count = 1;
- mutex_unlock(&open_disc_mutex);
/* reset the tower */
result = usb_control_msg (dev->udev,
@@ -402,13 +394,14 @@ static int tower_open (struct inode *inode, struct file *file)
dev_err(&dev->udev->dev,
"Couldn't submit interrupt_in_urb %d\n", retval);
dev->interrupt_in_running = 0;
- dev->open_count = 0;
goto unlock_exit;
}
/* save device in the file's private structure */
file->private_data = dev;
+ dev->open_count = 1;
+
unlock_exit:
mutex_unlock(&dev->lock);
@@ -429,22 +422,19 @@ static int tower_release (struct inode *inode, struct file *file)
if (dev == NULL) {
retval = -ENODEV;
- goto exit_nolock;
- }
-
- mutex_lock(&open_disc_mutex);
- if (mutex_lock_interruptible(&dev->lock)) {
- retval = -ERESTARTSYS;
goto exit;
}
+ mutex_lock(&dev->lock);
+
if (dev->open_count != 1) {
dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
__func__);
retval = -ENODEV;
goto unlock_exit;
}
- if (dev->udev == NULL) {
+
+ if (dev->disconnected) {
/* the device was unplugged before the file was released */
/* unlock here as tower_delete frees dev */
@@ -462,10 +452,7 @@ static int tower_release (struct inode *inode, struct file *file)
unlock_exit:
mutex_unlock(&dev->lock);
-
exit:
- mutex_unlock(&open_disc_mutex);
-exit_nolock:
return retval;
}
@@ -483,10 +470,9 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
if (dev->interrupt_in_running) {
dev->interrupt_in_running = 0;
mb();
- if (dev->udev)
- usb_kill_urb (dev->interrupt_in_urb);
+ usb_kill_urb(dev->interrupt_in_urb);
}
- if (dev->interrupt_out_busy && dev->udev)
+ if (dev->interrupt_out_busy)
usb_kill_urb(dev->interrupt_out_urb);
}
@@ -522,7 +508,7 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
dev = file->private_data;
- if (!dev->udev)
+ if (dev->disconnected)
return POLLERR | POLLHUP;
poll_wait(file, &dev->read_wait, wait);
@@ -569,7 +555,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
}
/* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -655,7 +641,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
}
/* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -764,7 +750,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
resubmit:
/* resubmit if we're still running */
- if (dev->interrupt_in_running && dev->udev) {
+ if (dev->interrupt_in_running) {
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
if (retval)
dev_err(&dev->udev->dev,
@@ -832,8 +818,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
mutex_init(&dev->lock);
- dev->udev = udev;
+ dev->udev = usb_get_dev(udev);
dev->open_count = 0;
+ dev->disconnected = 0;
dev->read_buffer = NULL;
dev->read_buffer_length = 0;
@@ -923,8 +910,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
get_version_reply,
sizeof(*get_version_reply),
1000);
- if (result < 0) {
- dev_err(idev, "LEGO USB Tower get version control request failed\n");
+ if (result < sizeof(*get_version_reply)) {
+ if (result >= 0)
+ result = -EIO;
+ dev_err(idev, "get version request failed: %d\n", result);
retval = result;
goto error;
}
@@ -942,7 +931,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
if (retval) {
/* something prevented us from registering this driver */
dev_err(idev, "Not able to get a minor for this device.\n");
- usb_set_intfdata (interface, NULL);
goto error;
}
dev->minor = interface->minor;
@@ -974,23 +962,24 @@ static void tower_disconnect (struct usb_interface *interface)
int minor;
dev = usb_get_intfdata (interface);
- mutex_lock(&open_disc_mutex);
- usb_set_intfdata (interface, NULL);
minor = dev->minor;
- /* give back our minor */
+ /* give back our minor and prevent further open() */
usb_deregister_dev (interface, &tower_class);
+ /* stop I/O */
+ usb_poison_urb(dev->interrupt_in_urb);
+ usb_poison_urb(dev->interrupt_out_urb);
+
mutex_lock(&dev->lock);
- mutex_unlock(&open_disc_mutex);
/* 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->udev = NULL;
+ dev->disconnected = 1;
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
deleted file mode 100644
index 6e761fabffca..000000000000
--- a/drivers/usb/misc/rio500.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/* -*- linux-c -*- */
-
-/*
- * Driver for USB Rio 500
- *
- * Cesar Miquel (miquel@df.uba.ar)
- *
- * based on hp_scanner.c by David E. Nelson (dnelson@jump.net)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
- *
- * Changelog:
- * 30/05/2003 replaced lock/unlock kernel with up/down
- * Daniele Bellucci bellucda@tiscali.it
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-
-#include "rio500_usb.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.1"
-#define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
-#define DRIVER_DESC "USB Rio 500 driver"
-
-#define RIO_MINOR 64
-
-/* stall/wait timeout for rio */
-#define NAK_TIMEOUT (HZ)
-
-#define IBUF_SIZE 0x1000
-
-/* Size of the rio buffer */
-#define OBUF_SIZE 0x10000
-
-struct rio_usb_data {
- struct usb_device *rio_dev; /* init: probe_rio */
- unsigned int ifnum; /* Interface number of the USB device */
- int isopen; /* nz if open */
- int present; /* Device is present on the bus */
- char *obuf, *ibuf; /* transfer buffers */
- char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
- wait_queue_head_t wait_q; /* for timeouts */
- struct mutex lock; /* general race avoidance */
-};
-
-static DEFINE_MUTEX(rio500_mutex);
-static struct rio_usb_data rio_instance;
-
-static int open_rio(struct inode *inode, struct file *file)
-{
- struct rio_usb_data *rio = &rio_instance;
-
- /* against disconnect() */
- mutex_lock(&rio500_mutex);
- mutex_lock(&(rio->lock));
-
- if (rio->isopen || !rio->present) {
- mutex_unlock(&(rio->lock));
- mutex_unlock(&rio500_mutex);
- return -EBUSY;
- }
- rio->isopen = 1;
-
- init_waitqueue_head(&rio->wait_q);
-
- mutex_unlock(&(rio->lock));
-
- dev_info(&rio->rio_dev->dev, "Rio opened.\n");
- mutex_unlock(&rio500_mutex);
-
- return 0;
-}
-
-static int close_rio(struct inode *inode, struct file *file)
-{
- struct rio_usb_data *rio = &rio_instance;
-
- /* against disconnect() */
- mutex_lock(&rio500_mutex);
- mutex_lock(&(rio->lock));
-
- rio->isopen = 0;
- if (!rio->present) {
- /* cleanup has been delayed */
- kfree(rio->ibuf);
- kfree(rio->obuf);
- rio->ibuf = NULL;
- rio->obuf = NULL;
- } else {
- dev_info(&rio->rio_dev->dev, "Rio closed.\n");
- }
- mutex_unlock(&(rio->lock));
- mutex_unlock(&rio500_mutex);
- return 0;
-}
-
-static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct RioCommand rio_cmd;
- struct rio_usb_data *rio = &rio_instance;
- void __user *data;
- unsigned char *buffer;
- int result, requesttype;
- int retries;
- int retval=0;
-
- mutex_lock(&(rio->lock));
- /* Sanity check to make sure rio is connected, powered, etc */
- if (rio->present == 0 || rio->rio_dev == NULL) {
- retval = -ENODEV;
- goto err_out;
- }
-
- switch (cmd) {
- case RIO_RECV_COMMAND:
- data = (void __user *) arg;
- if (data == NULL)
- break;
- if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
- retval = -EFAULT;
- goto err_out;
- }
- if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
- retval = -EINVAL;
- goto err_out;
- }
- buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (buffer == NULL) {
- retval = -ENOMEM;
- goto err_out;
- }
- if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
- retval = -EFAULT;
- free_page((unsigned long) buffer);
- goto err_out;
- }
-
- requesttype = rio_cmd.requesttype | USB_DIR_IN |
- USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dev_dbg(&rio->rio_dev->dev,
- "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
- /* Send rio control message */
- retries = 3;
- while (retries) {
- result = usb_control_msg(rio->rio_dev,
- usb_rcvctrlpipe(rio-> rio_dev, 0),
- rio_cmd.request,
- requesttype,
- rio_cmd.value,
- rio_cmd.index, buffer,
- rio_cmd.length,
- jiffies_to_msecs(rio_cmd.timeout));
- if (result == -ETIMEDOUT)
- retries--;
- else if (result < 0) {
- dev_err(&rio->rio_dev->dev,
- "Error executing ioctrl. code = %d\n",
- result);
- retries = 0;
- } else {
- dev_dbg(&rio->rio_dev->dev,
- "Executed ioctl. Result = %d (data=%02x)\n",
- result, buffer[0]);
- if (copy_to_user(rio_cmd.buffer, buffer,
- rio_cmd.length)) {
- free_page((unsigned long) buffer);
- retval = -EFAULT;
- goto err_out;
- }
- retries = 0;
- }
-
- /* rio_cmd.buffer contains a raw stream of single byte
- data which has been returned from rio. Data is
- interpreted at application level. For data that
- will be cast to data types longer than 1 byte, data
- will be little_endian and will potentially need to
- be swapped at the app level */
-
- }
- free_page((unsigned long) buffer);
- break;
-
- case RIO_SEND_COMMAND:
- data = (void __user *) arg;
- if (data == NULL)
- break;
- if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
- retval = -EFAULT;
- goto err_out;
- }
- if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
- retval = -EINVAL;
- goto err_out;
- }
- buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (buffer == NULL) {
- retval = -ENOMEM;
- goto err_out;
- }
- if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
- free_page((unsigned long)buffer);
- retval = -EFAULT;
- goto err_out;
- }
-
- requesttype = rio_cmd.requesttype | USB_DIR_OUT |
- USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dev_dbg(&rio->rio_dev->dev,
- "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
- /* Send rio control message */
- retries = 3;
- while (retries) {
- result = usb_control_msg(rio->rio_dev,
- usb_sndctrlpipe(rio-> rio_dev, 0),
- rio_cmd.request,
- requesttype,
- rio_cmd.value,
- rio_cmd.index, buffer,
- rio_cmd.length,
- jiffies_to_msecs(rio_cmd.timeout));
- if (result == -ETIMEDOUT)
- retries--;
- else if (result < 0) {
- dev_err(&rio->rio_dev->dev,
- "Error executing ioctrl. code = %d\n",
- result);
- retries = 0;
- } else {
- dev_dbg(&rio->rio_dev->dev,
- "Executed ioctl. Result = %d\n", result);
- retries = 0;
-
- }
-
- }
- free_page((unsigned long) buffer);
- break;
-
- default:
- retval = -ENOTTY;
- break;
- }
-
-
-err_out:
- mutex_unlock(&(rio->lock));
- return retval;
-}
-
-static ssize_t
-write_rio(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- DEFINE_WAIT(wait);
- struct rio_usb_data *rio = &rio_instance;
-
- unsigned long copy_size;
- unsigned long bytes_written = 0;
- unsigned int partial;
-
- int result = 0;
- int maxretry;
- int errn = 0;
- int intr;
-
- intr = mutex_lock_interruptible(&(rio->lock));
- if (intr)
- return -EINTR;
- /* Sanity check to make sure rio is connected, powered, etc */
- if (rio->present == 0 || rio->rio_dev == NULL) {
- mutex_unlock(&(rio->lock));
- return -ENODEV;
- }
-
-
-
- do {
- unsigned long thistime;
- char *obuf = rio->obuf;
-
- thistime = copy_size =
- (count >= OBUF_SIZE) ? OBUF_SIZE : count;
- if (copy_from_user(rio->obuf, buffer, copy_size)) {
- errn = -EFAULT;
- goto error;
- }
- maxretry = 5;
- while (thistime) {
- if (!rio->rio_dev) {
- errn = -ENODEV;
- goto error;
- }
- if (signal_pending(current)) {
- mutex_unlock(&(rio->lock));
- return bytes_written ? bytes_written : -EINTR;
- }
-
- result = usb_bulk_msg(rio->rio_dev,
- usb_sndbulkpipe(rio->rio_dev, 2),
- obuf, thistime, &partial, 5000);
-
- dev_dbg(&rio->rio_dev->dev,
- "write stats: result:%d thistime:%lu partial:%u\n",
- result, thistime, partial);
-
- if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
- if (!maxretry--) {
- errn = -ETIME;
- goto error;
- }
- prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
- schedule_timeout(NAK_TIMEOUT);
- finish_wait(&rio->wait_q, &wait);
- continue;
- } else if (!result && partial) {
- obuf += partial;
- thistime -= partial;
- } else
- break;
- }
- if (result) {
- dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
- result);
- errn = -EIO;
- goto error;
- }
- bytes_written += copy_size;
- count -= copy_size;
- buffer += copy_size;
- } while (count > 0);
-
- mutex_unlock(&(rio->lock));
-
- return bytes_written ? bytes_written : -EIO;
-
-error:
- mutex_unlock(&(rio->lock));
- return errn;
-}
-
-static ssize_t
-read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
-{
- DEFINE_WAIT(wait);
- struct rio_usb_data *rio = &rio_instance;
- ssize_t read_count;
- unsigned int partial;
- int this_read;
- int result;
- int maxretry = 10;
- char *ibuf;
- int intr;
-
- intr = mutex_lock_interruptible(&(rio->lock));
- if (intr)
- return -EINTR;
- /* Sanity check to make sure rio is connected, powered, etc */
- if (rio->present == 0 || rio->rio_dev == NULL) {
- mutex_unlock(&(rio->lock));
- return -ENODEV;
- }
-
- ibuf = rio->ibuf;
-
- read_count = 0;
-
-
- while (count > 0) {
- if (signal_pending(current)) {
- mutex_unlock(&(rio->lock));
- return read_count ? read_count : -EINTR;
- }
- if (!rio->rio_dev) {
- mutex_unlock(&(rio->lock));
- return -ENODEV;
- }
- this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
-
- result = usb_bulk_msg(rio->rio_dev,
- usb_rcvbulkpipe(rio->rio_dev, 1),
- ibuf, this_read, &partial,
- 8000);
-
- dev_dbg(&rio->rio_dev->dev,
- "read stats: result:%d this_read:%u partial:%u\n",
- result, this_read, partial);
-
- if (partial) {
- count = this_read = partial;
- } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
- if (!maxretry--) {
- mutex_unlock(&(rio->lock));
- dev_err(&rio->rio_dev->dev,
- "read_rio: maxretry timeout\n");
- return -ETIME;
- }
- prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
- schedule_timeout(NAK_TIMEOUT);
- finish_wait(&rio->wait_q, &wait);
- continue;
- } else if (result != -EREMOTEIO) {
- mutex_unlock(&(rio->lock));
- dev_err(&rio->rio_dev->dev,
- "Read Whoops - result:%u partial:%u this_read:%u\n",
- result, partial, this_read);
- return -EIO;
- } else {
- mutex_unlock(&(rio->lock));
- return (0);
- }
-
- if (this_read) {
- if (copy_to_user(buffer, ibuf, this_read)) {
- mutex_unlock(&(rio->lock));
- return -EFAULT;
- }
- count -= this_read;
- read_count += this_read;
- buffer += this_read;
- }
- }
- mutex_unlock(&(rio->lock));
- return read_count;
-}
-
-static const struct file_operations usb_rio_fops = {
- .owner = THIS_MODULE,
- .read = read_rio,
- .write = write_rio,
- .unlocked_ioctl = ioctl_rio,
- .open = open_rio,
- .release = close_rio,
- .llseek = noop_llseek,
-};
-
-static struct usb_class_driver usb_rio_class = {
- .name = "rio500%d",
- .fops = &usb_rio_fops,
- .minor_base = RIO_MINOR,
-};
-
-static int probe_rio(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct rio_usb_data *rio = &rio_instance;
- int retval = 0;
-
- mutex_lock(&rio500_mutex);
- if (rio->present) {
- dev_info(&intf->dev, "Second USB Rio at address %d refused\n", dev->devnum);
- retval = -EBUSY;
- goto bail_out;
- } else {
- dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum);
- }
-
- retval = usb_register_dev(intf, &usb_rio_class);
- if (retval) {
- dev_err(&dev->dev,
- "Not able to get a minor for this device.\n");
- retval = -ENOMEM;
- goto bail_out;
- }
-
- rio->rio_dev = dev;
-
- if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) {
- dev_err(&dev->dev,
- "probe_rio: Not enough memory for the output buffer\n");
- usb_deregister_dev(intf, &usb_rio_class);
- retval = -ENOMEM;
- goto bail_out;
- }
- dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf);
-
- if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) {
- dev_err(&dev->dev,
- "probe_rio: Not enough memory for the input buffer\n");
- usb_deregister_dev(intf, &usb_rio_class);
- kfree(rio->obuf);
- retval = -ENOMEM;
- goto bail_out;
- }
- dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf);
-
- mutex_init(&(rio->lock));
-
- usb_set_intfdata (intf, rio);
- rio->present = 1;
-bail_out:
- mutex_unlock(&rio500_mutex);
-
- return retval;
-}
-
-static void disconnect_rio(struct usb_interface *intf)
-{
- struct rio_usb_data *rio = usb_get_intfdata (intf);
-
- usb_set_intfdata (intf, NULL);
- mutex_lock(&rio500_mutex);
- if (rio) {
- usb_deregister_dev(intf, &usb_rio_class);
-
- mutex_lock(&(rio->lock));
- if (rio->isopen) {
- rio->isopen = 0;
- /* better let it finish - the release will do whats needed */
- rio->rio_dev = NULL;
- mutex_unlock(&(rio->lock));
- mutex_unlock(&rio500_mutex);
- return;
- }
- kfree(rio->ibuf);
- kfree(rio->obuf);
-
- dev_info(&intf->dev, "USB Rio disconnected.\n");
-
- rio->present = 0;
- mutex_unlock(&(rio->lock));
- }
- mutex_unlock(&rio500_mutex);
-}
-
-static const struct usb_device_id rio_table[] = {
- { USB_DEVICE(0x0841, 1) }, /* Rio 500 */
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, rio_table);
-
-static struct usb_driver rio_driver = {
- .name = "rio500",
- .probe = probe_rio,
- .disconnect = disconnect_rio,
- .id_table = rio_table,
-};
-
-module_usb_driver(rio_driver);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/misc/rio500_usb.h b/drivers/usb/misc/rio500_usb.h
deleted file mode 100644
index 359abc98e706..000000000000
--- a/drivers/usb/misc/rio500_usb.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* ----------------------------------------------------------------------
-
- Copyright (C) 2000 Cesar Miquel (miquel@df.uba.ar)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ---------------------------------------------------------------------- */
-
-
-
-#define RIO_SEND_COMMAND 0x1
-#define RIO_RECV_COMMAND 0x2
-
-#define RIO_DIR_OUT 0x0
-#define RIO_DIR_IN 0x1
-
-struct RioCommand {
- short length;
- int request;
- int requesttype;
- int value;
- int index;
- void __user *buffer;
- int timeout;
-};
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 1184390508e9..c77974fab29d 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mutex.h>
+#include <linux/rwsem.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
@@ -56,6 +57,8 @@ struct usb_lcd {
using up all RAM */
struct usb_anchor submitted; /* URBs to wait for
before suspend */
+ struct rw_semaphore io_rwsem;
+ unsigned long disconnected:1;
};
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
@@ -141,6 +144,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
dev = file->private_data;
+ down_read(&dev->io_rwsem);
+
+ if (dev->disconnected) {
+ retval = -ENODEV;
+ goto out_up_io;
+ }
+
/* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev,
@@ -157,6 +167,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
retval = bytes_read;
}
+out_up_io:
+ up_read(&dev->io_rwsem);
+
return retval;
}
@@ -236,11 +249,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
if (r < 0)
return -EINTR;
+ down_read(&dev->io_rwsem);
+
+ if (dev->disconnected) {
+ retval = -ENODEV;
+ goto err_up_io;
+ }
+
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
- goto err_no_buf;
+ goto err_up_io;
}
buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
@@ -277,6 +297,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
the USB core will eventually free it entirely */
usb_free_urb(urb);
+ up_read(&dev->io_rwsem);
exit:
return count;
error_unanchor:
@@ -284,7 +305,8 @@ error_unanchor:
error:
usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
-err_no_buf:
+err_up_io:
+ up_read(&dev->io_rwsem);
up(&dev->limit_sem);
return retval;
}
@@ -327,6 +349,7 @@ static int lcd_probe(struct usb_interface *interface,
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
+ init_rwsem(&dev->io_rwsem);
init_usb_anchor(&dev->submitted);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -437,6 +460,12 @@ static void lcd_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev(interface, &lcd_class);
+ down_write(&dev->io_rwsem);
+ dev->disconnected = 1;
+ up_write(&dev->io_rwsem);
+
+ usb_kill_anchored_urbs(&dev->submitted);
+
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 2222ec2275fc..44c6ced5d442 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -64,6 +64,7 @@ struct usb_yurex {
struct kref kref;
struct mutex io_mutex;
+ unsigned long disconnected:1;
struct fasync_struct *async_queue;
wait_queue_head_t waitq;
@@ -111,6 +112,7 @@ static void yurex_delete(struct kref *kref)
dev->int_buffer, dev->urb->transfer_dma);
usb_free_urb(dev->urb);
}
+ usb_put_intf(dev->interface);
usb_put_dev(dev->udev);
kfree(dev);
}
@@ -136,6 +138,7 @@ static void yurex_interrupt(struct urb *urb)
switch (status) {
case 0: /*success*/
break;
+ /* The device is terminated or messed up, give up */
case -EOVERFLOW:
dev_err(&dev->interface->dev,
"%s - overflow with length %d, actual length is %d\n",
@@ -144,12 +147,13 @@ static void yurex_interrupt(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
case -EILSEQ:
- /* The device is terminated, clean up */
+ case -EPROTO:
+ case -ETIME:
return;
default:
dev_err(&dev->interface->dev,
"%s - unknown status received: %d\n", __func__, status);
- goto exit;
+ return;
}
/* handle received message */
@@ -181,7 +185,6 @@ static void yurex_interrupt(struct urb *urb)
break;
}
-exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval) {
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
@@ -210,7 +213,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
init_waitqueue_head(&dev->waitq);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
- dev->interface = interface;
+ dev->interface = usb_get_intf(interface);
/* set up the endpoint information */
iface_desc = interface->cur_altsetting;
@@ -333,8 +336,9 @@ static void yurex_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */
usb_poison_urb(dev->urb);
+ usb_poison_urb(dev->cntl_urb);
mutex_lock(&dev->io_mutex);
- dev->interface = NULL;
+ dev->disconnected = 1;
mutex_unlock(&dev->io_mutex);
/* wakeup waiters */
@@ -422,7 +426,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
dev = file->private_data;
mutex_lock(&dev->io_mutex);
- if (!dev->interface) { /* already disconnected */
+ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex);
return -ENODEV;
}
@@ -457,7 +461,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
goto error;
mutex_lock(&dev->io_mutex);
- if (!dev->interface) { /* already disconnected */
+ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 8c5fc12ad778..b8620aa6b72e 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -213,6 +213,7 @@ struct usbhs_priv;
/* DCPCTR */
#define BSTS (1 << 15) /* Buffer Status */
#define SUREQ (1 << 14) /* Sending SETUP Token */
+#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */
#define CSSTS (1 << 12) /* CSSTS Status */
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
#define SQCLR (1 << 8) /* Toggle Bit Clear */
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 5e2aa4f85c81..79efb367e5ce 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -98,7 +98,7 @@ static void __usbhsf_pkt_del(struct usbhs_pkt *pkt)
list_del_init(&pkt->node);
}
-static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
{
if (list_empty(&pipe->list))
return NULL;
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index c7d9b86d51bf..3640340e94d6 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -106,5 +106,6 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void *buf, int len, int zero, int sequence);
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
void usbhs_pkt_start(struct usbhs_pipe *pipe);
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_FIFO_H */
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index c5553028e616..efe8d815cf2c 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -731,8 +731,7 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
unsigned long flags;
-
- usbhsg_pipe_disable(uep);
+ int ret = 0;
dev_dbg(dev, "set halt %d (pipe %d)\n",
halt, usbhs_pipe_number(pipe));
@@ -740,6 +739,18 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
/******************** spin lock ********************/
usbhs_lock(priv, flags);
+ /*
+ * According to usb_ep_set_halt()'s description, this function should
+ * return -EAGAIN if the IN endpoint has any queue or data. Note
+ * that the usbhs_pipe_is_dir_in() returns false if the pipe is an
+ * IN endpoint in the gadget mode.
+ */
+ if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) ||
+ usbhs_pipe_contains_transmittable_data(pipe))) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
if (halt)
usbhs_pipe_stall(pipe);
else
@@ -750,10 +761,11 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
else
usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE);
+out:
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
- return 0;
+ return ret;
}
static int usbhsg_ep_set_halt(struct usb_ep *ep, int value)
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 4f9c3356127a..75fb41d4e9fc 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -279,6 +279,21 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe)
return -EBUSY;
}
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe)
+{
+ u16 val;
+
+ /* Do not support for DCP pipe */
+ if (usbhs_pipe_is_dcp(pipe))
+ return false;
+
+ val = usbhsp_pipectrl_get(pipe);
+ if (val & INBUFM)
+ return true;
+
+ return false;
+}
+
/*
* PID ctrl
*/
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index b0bc7b603016..b7925d363bb4 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -89,6 +89,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
void usbhs_pipe_clear(struct usbhs_pipe *pipe);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 7edcd5a8d175..2998da6bd901 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1025,6 +1025,9 @@ static const struct usb_device_id id_table_combined[] = {
/* EZPrototypes devices */
{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
{ USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
+ /* Sienna devices */
+ { USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
+ { USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index ed6b36674c15..2e8161f79b49 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -38,6 +38,9 @@
#define FTDI_LUMEL_PD12_PID 0x6002
+/* Sienna Serial Interface by Secyourit GmbH */
+#define FTDI_SIENNA_PID 0x8348
+
/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
#define CYBER_CORTEX_AV_PID 0x8698
@@ -688,6 +691,12 @@
#define BANDB_ZZ_PROG1_USB_PID 0xBA02
/*
+ * Echelon USB Serial Interface
+ */
+#define ECHELON_VID 0x0920
+#define ECHELON_U20_PID 0x7500
+
+/*
* Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
*/
#define INTREPID_VID 0x093C
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 7faa901ee47f..38112be0dbae 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1249,8 +1249,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
ep_desc = find_ep(serial, endpoint);
if (!ep_desc) {
- /* leak the urb, something's wrong and the callers don't care */
- return urb;
+ usb_free_urb(urb);
+ return NULL;
}
if (usb_endpoint_xfer_int(ep_desc)) {
ep_type_name = "INT";
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 1bceb11f3782..00a6e62a68a8 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -421,6 +421,7 @@ static void option_instat_callback(struct urb *urb);
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
+#define CINTERION_PRODUCT_CLS8 0x00b0
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
@@ -1149,6 +1150,14 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
.driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1050, 0xff), /* Telit FN980 (rmnet) */
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1051, 0xff), /* Telit FN980 (MBIM) */
+ .driver_info = NCTRL(0) | RSVD(1) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1052, 0xff), /* Telit FN980 (RNDIS) */
+ .driver_info = NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1053, 0xff), /* Telit FN980 (ECM) */
+ .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
@@ -1842,6 +1851,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff),
+ .driver_info = RSVD(0) | RSVD(4) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index fe7f5ace6064..a33acb8c16d3 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -542,7 +542,6 @@ static void ti_close(struct usb_serial_port *port)
struct ti_port *tport;
int port_number;
int status;
- int do_unlock;
unsigned long flags;
tdev = usb_get_serial_data(port->serial);
@@ -569,16 +568,13 @@ static void ti_close(struct usb_serial_port *port)
"%s - cannot send close port command, %d\n"
, __func__, status);
- /* if mutex_lock is interrupted, continue anyway */
- do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
+ mutex_lock(&tdev->td_open_close_lock);
--tport->tp_tdev->td_open_port_count;
- if (tport->tp_tdev->td_open_port_count <= 0) {
+ if (tport->tp_tdev->td_open_port_count == 0) {
/* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
- tport->tp_tdev->td_open_port_count = 0;
}
- if (do_unlock)
- mutex_unlock(&tdev->td_open_close_lock);
+ mutex_unlock(&tdev->td_open_close_lock);
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index e7e29c797824..80ba818d3a21 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -314,10 +314,7 @@ static void serial_cleanup(struct tty_struct *tty)
serial = port->serial;
owner = serial->type->driver.owner;
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- usb_autopm_put_interface(serial->interface);
- mutex_unlock(&serial->disc_mutex);
+ usb_autopm_put_interface(serial->interface);
usb_serial_put(serial);
module_put(owner);
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 545d09b8081d..871c366d9229 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -63,6 +63,7 @@ struct usb_skel {
spinlock_t err_lock; /* lock for errors */
struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */
+ unsigned long disconnected:1;
wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
@@ -75,6 +76,7 @@ static void skel_delete(struct kref *kref)
struct usb_skel *dev = to_skel_dev(kref);
usb_free_urb(dev->bulk_in_urb);
+ usb_put_intf(dev->interface);
usb_put_dev(dev->udev);
kfree(dev->bulk_in_buffer);
kfree(dev);
@@ -126,10 +128,7 @@ static int skel_release(struct inode *inode, struct file *file)
return -ENODEV;
/* allow the device to be autosuspended */
- mutex_lock(&dev->io_mutex);
- if (dev->interface)
- usb_autopm_put_interface(dev->interface);
- mutex_unlock(&dev->io_mutex);
+ usb_autopm_put_interface(dev->interface);
/* decrement the count on our device */
kref_put(&dev->kref, skel_delete);
@@ -241,7 +240,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count,
if (rv < 0)
return rv;
- if (!dev->interface) { /* disconnect() was called */
+ if (dev->disconnected) { /* disconnect() was called */
rv = -ENODEV;
goto exit;
}
@@ -422,7 +421,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer,
/* this lock makes sure we don't submit URBs to gone devices */
mutex_lock(&dev->io_mutex);
- if (!dev->interface) { /* disconnect() was called */
+ if (dev->disconnected) { /* disconnect() was called */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
@@ -511,7 +510,7 @@ static int skel_probe(struct usb_interface *interface,
init_waitqueue_head(&dev->bulk_in_wait);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
- dev->interface = interface;
+ dev->interface = usb_get_intf(interface);
/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
@@ -590,7 +589,7 @@ static void skel_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */
mutex_lock(&dev->io_mutex);
- dev->interface = NULL;
+ dev->disconnected = 1;
mutex_unlock(&dev->io_mutex);
usb_kill_anchored_urbs(&dev->submitted);
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 47b229fa5e8e..4b62eb3b5923 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -221,11 +221,20 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
/*
- * Try to reset the device. The success of this is dependent on
- * being able to lock the device, which is not always possible.
+ * Try to get the locks ourselves to prevent a deadlock. The
+ * success of this is dependent on being able to lock the device,
+ * which is not always possible.
+ * We can not use the "try" reset interface here, which will
+ * overwrite the previously restored configuration information.
*/
- if (vdev->reset_works && !pci_try_reset_function(pdev))
- vdev->needs_reset = false;
+ if (vdev->reset_works && pci_cfg_access_trylock(pdev)) {
+ if (device_trylock(&pdev->dev)) {
+ if (!__pci_reset_function_locked(pdev))
+ vdev->needs_reset = false;
+ device_unlock(&pdev->dev);
+ }
+ pci_cfg_access_unlock(pdev);
+ }
pci_restore_state(pdev);
out:
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 419991a98d4e..c2cfc8e0532e 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -888,7 +888,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
{
struct buf_data *pcmds = file->private_data;
ssize_t ret = 0;
- int blen = 0;
+ unsigned int blen = 0;
char *string_buf;
mutex_lock(&pcmds->dbg_mutex);
@@ -900,6 +900,11 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
/* Allocate memory for the received string */
blen = count + (pcmds->sblen);
+ if (blen > U32_MAX - 1) {
+ mutex_unlock(&pcmds->dbg_mutex);
+ return -EINVAL;
+ }
+
string_buf = krealloc(pcmds->string_buf, blen + 1, GFP_KERNEL);
if (!string_buf) {
pr_err("%s: Failed to allocate memory\n", __func__);
@@ -907,6 +912,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
return -ENOMEM;
}
+ pcmds->string_buf = string_buf;
/* Writing in batches is possible */
ret = simple_write_to_buffer(string_buf, blen, ppos, p, count);
if (ret < 0) {
@@ -916,7 +922,6 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
}
string_buf[ret] = '\0';
- pcmds->string_buf = string_buf;
pcmds->sblen = count;
mutex_unlock(&pcmds->dbg_mutex);
return ret;
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index fa3480815cdb..88e0763edcc7 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -421,7 +421,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x0);
+ ret = ssd1307fb_write_cmd(par->client, par->page_offset);
if (ret < 0)
return ret;
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbeb4409..db58aaa4dc59 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -29,6 +29,8 @@
#include "../pci/pci.h"
#ifdef CONFIG_PCI_MMCONFIG
#include <asm/pci_x86.h>
+
+static int xen_mcfg_late(void);
#endif
static bool __read_mostly pci_seg_supported = true;
@@ -40,7 +42,18 @@ static int xen_add_device(struct device *dev)
#ifdef CONFIG_PCI_IOV
struct pci_dev *physfn = pci_dev->physfn;
#endif
-
+#ifdef CONFIG_PCI_MMCONFIG
+ static bool pci_mcfg_reserved = false;
+ /*
+ * Reserve MCFG areas in Xen on first invocation due to this being
+ * potentially called from inside of acpi_init immediately after
+ * MCFG table has been finally parsed.
+ */
+ if (!pci_mcfg_reserved) {
+ xen_mcfg_late();
+ pci_mcfg_reserved = true;
+ }
+#endif
if (pci_seg_supported) {
struct {
struct physdev_pci_device_add add;
@@ -213,7 +226,7 @@ static int __init register_xen_pci_notifier(void)
arch_initcall(register_xen_pci_notifier);
#ifdef CONFIG_PCI_MMCONFIG
-static int __init xen_mcfg_late(void)
+static int xen_mcfg_late(void)
{
struct pci_mmcfg_region *cfg;
int rc;
@@ -252,8 +265,4 @@ static int __init xen_mcfg_late(void)
}
return 0;
}
-/*
- * Needs to be done after acpi_init which are subsys_initcall.
- */
-subsys_initcall_sync(xen_mcfg_late);
#endif