summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/Kconfig5
-rw-r--r--drivers/base/firmware_class.c8
-rw-r--r--drivers/char/adsprpc.c7
-rw-r--r--drivers/char/diag/Makefile1
-rw-r--r--drivers/char/diag/diag_debugfs.c10
-rw-r--r--drivers/char/diag/diag_ipc_logging.h4
-rw-r--r--drivers/char/diag/diagchar_core.c42
-rw-r--r--drivers/char/diag/diagfwd_bridge.c37
-rw-r--r--drivers/char/diag/diagfwd_bridge.h4
-rw-r--r--drivers/clk/msm/clock-mmss-8996.c4
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c2
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_phy.c3
-rw-r--r--drivers/gpu/drm/msm/edp/edp.c4
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c7
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h1
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c9
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c11
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c7
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c4
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c54
-rw-r--r--drivers/gpu/drm/msm/sde/sde_recovery_manager.c399
-rw-r--r--drivers/gpu/drm/msm/sde/sde_recovery_manager.h118
-rw-r--r--drivers/iommu/iommu-debug.c19
-rw-r--r--drivers/media/i2c/adv7481.c16
-rw-r--r--drivers/media/i2c/adv7481_reg.h4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c6
-rw-r--r--drivers/mmc/card/block.c4
-rw-r--r--drivers/mmc/core/core.c20
-rw-r--r--drivers/mmc/core/sd.c22
-rw-r--r--drivers/mmc/core/slot-gpio.c4
-rw-r--r--drivers/net/usb/usbnet.c142
-rw-r--r--drivers/net/wireless/cnss2/Makefile1
-rw-r--r--drivers/net/wireless/cnss2/bus.c356
-rw-r--r--drivers/net/wireless/cnss2/bus.h51
-rw-r--r--drivers/net/wireless/cnss2/main.c664
-rw-r--r--drivers/net/wireless/cnss2/main.h15
-rw-r--r--drivers/net/wireless/cnss2/pci.c631
-rw-r--r--drivers/net/wireless/cnss2/pci.h16
-rw-r--r--drivers/net/wireless/cnss2/qmi.c21
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c2
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c2
-rw-r--r--drivers/soc/qcom/hab/hab_mem_linux.c21
-rw-r--r--drivers/soc/qcom/hab/hab_mimex.c5
-rw-r--r--drivers/usb/core/message.c157
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c21
-rw-r--r--drivers/usb/gadget/function/f_fs.c5
-rw-r--r--drivers/usb/host/xhci.c1
-rw-r--r--drivers/usb/misc/diag_ipc_bridge.c2
57 files changed, 2073 insertions, 901 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 59992788966c..602cbb04bee8 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -165,6 +165,11 @@ config FW_LOADER_USER_HELPER_FALLBACK
If you are unsure about this, say N here.
+config FW_CACHE
+ bool "Enable firmware caching during suspend"
+ depends on PM_SLEEP
+ default n
+
config WANT_DEV_COREDUMP
bool
help
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a1696e1d199f..c1093c0d4dea 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1148,7 +1148,7 @@ static int fw_load_from_user_helper(struct firmware *firmware,
return _request_firmware_load(fw_priv, desc->opt_flags, timeout);
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
/* kill pending requests without uevent to avoid blocking suspend */
static void kill_requests_without_uevent(void)
{
@@ -1626,7 +1626,7 @@ request_firmware_nowait_into_buf(
}
EXPORT_SYMBOL_GPL(request_firmware_nowait_into_buf);
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
/**
@@ -1972,7 +1972,7 @@ static void __init fw_cache_init(void)
INIT_LIST_HEAD(&fw_cache.head);
fw_cache.state = FW_LOADER_NO_CACHE;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
spin_lock_init(&fw_cache.name_lock);
INIT_LIST_HEAD(&fw_cache.fw_names);
@@ -1999,7 +1999,7 @@ static int __init firmware_class_init(void)
static void __exit firmware_class_exit(void)
{
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
#endif
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index c0787608af56..165c5707a9f7 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2318,8 +2318,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
spin_unlock(&fl->apps->hlock);
if (!fl->sctx) {
- kfree(fl);
- return 0;
+ goto bail;
}
spin_lock(&fl->hlock);
@@ -2337,6 +2336,8 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
fastrpc_session_free(&fl->apps->channel[cid], fl->sctx);
if (fl->secsctx)
fastrpc_session_free(&fl->apps->channel[cid], fl->secsctx);
+bail:
+ mutex_destroy(&fl->map_mutex);
kfree(fl);
return 0;
}
@@ -2348,7 +2349,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
if (fl) {
if (fl->debugfs_file != NULL)
debugfs_remove(fl->debugfs_file);
- mutex_destroy(&fl->map_mutex);
+
fastrpc_file_free(fl);
file->private_data = NULL;
}
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index c5ec4f081c55..d57ebd8d671e 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_DIAG_CHAR) := diagchar.o
obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_bridge.o
obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o
-obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_smux.o
obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.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_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 5e455878ac3e..3d916e790814 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -23,7 +23,6 @@
#endif
#ifdef CONFIG_USB_QCOM_DIAG_BRIDGE
#include "diagfwd_hsic.h"
-#include "diagfwd_smux.h"
#endif
#ifdef CONFIG_MSM_MHI
#include "diagfwd_mhi.h"
@@ -801,6 +800,7 @@ static ssize_t diag_dbgfs_read_glinkinfo(struct file *file, char __user *ubuf,
return ret;
}
+#ifdef CONFIG_IPC_LOGGING
static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -831,6 +831,7 @@ static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf,
diag_debug_mask = (uint16_t)value;
return count;
}
+#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
#ifdef CONFIG_USB_QCOM_DIAG_BRIDGE
@@ -1088,9 +1089,11 @@ const struct file_operations diag_dbgfs_power_ops = {
.read = diag_dbgfs_read_power,
};
+#ifdef CONFIG_IPC_LOGGING
const struct file_operations diag_dbgfs_debug_ops = {
.write = diag_dbgfs_write_debug
};
+#endif
int diag_debugfs_init(void)
{
@@ -1145,11 +1148,12 @@ int diag_debugfs_init(void)
if (!entry)
goto err;
+#ifdef CONFIG_IPC_LOGGING
entry = debugfs_create_file("debug", 0444, diag_dbgfs_dent, 0,
&diag_dbgfs_debug_ops);
if (!entry)
goto err;
-
+#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
entry = debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0,
&diag_dbgfs_bridge_ops);
diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h
index 4b8dd1b12c1c..839c8ca02e7c 100644
--- a/drivers/char/diag/diag_ipc_logging.h
+++ b/drivers/char/diag/diag_ipc_logging.h
@@ -26,9 +26,7 @@
#define DIAG_DEBUG_BRIDGE 0x0040
#define DIAG_DEBUG_CONTROL 0x0080
-#define DIAG_DEBUG
-
-#ifdef DIAG_DEBUG
+#ifdef CONFIG_IPC_LOGGING
extern uint16_t diag_debug_mask;
extern void *diag_ipc_log;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 6df597dfa750..2bac98117c03 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -165,7 +165,7 @@ static struct mutex apps_data_mutex;
#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
-#ifdef DIAG_DEBUG
+#ifdef CONFIG_IPC_LOGGING
uint16_t diag_debug_mask;
void *diag_ipc_log;
#endif
@@ -1160,7 +1160,7 @@ static void diag_remote_exit(void)
return;
}
-int diagfwd_bridge_init(void)
+int diagfwd_bridge_init(bool use_mhi)
{
return 0;
}
@@ -3626,7 +3626,7 @@ void diag_ws_release()
pm_relax(driver->diag_dev);
}
-#ifdef DIAG_DEBUG
+#ifdef CONFIG_IPC_LOGGING
static void diag_debug_init(void)
{
diag_ipc_log = ipc_log_context_create(DIAG_IPC_LOG_PAGES, "diag", 0);
@@ -3743,7 +3743,7 @@ static int diag_mhi_probe(struct platform_device *pdev)
diag_remote_exit();
return ret;
}
- ret = diagfwd_bridge_init();
+ ret = diagfwd_bridge_init(true);
if (ret) {
diagfwd_bridge_exit();
return ret;
@@ -3766,6 +3766,39 @@ static struct platform_driver diag_mhi_driver = {
},
};
+static int diagfwd_usb_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ driver->pdev = pdev;
+ ret = diag_remote_init();
+ if (ret) {
+ diag_remote_exit();
+ return ret;
+ }
+ ret = diagfwd_bridge_init(false);
+ if (ret) {
+ diagfwd_bridge_exit();
+ return ret;
+ }
+ pr_debug("diag: usb device is ready\n");
+ return 0;
+}
+
+static const struct of_device_id diagfwd_usb_table[] = {
+ {.compatible = "qcom,diagfwd-usb"},
+ {},
+};
+
+static struct platform_driver diagfwd_usb_driver = {
+ .probe = diagfwd_usb_probe,
+ .driver = {
+ .name = "DIAGFWD USB Platform",
+ .owner = THIS_MODULE,
+ .of_match_table = diagfwd_usb_table,
+ },
+};
+
static int __init diagchar_init(void)
{
dev_t dev;
@@ -3892,6 +3925,7 @@ static int __init diagchar_init(void)
pr_debug("diagchar initialized now");
platform_driver_register(&diag_mhi_driver);
+ platform_driver_register(&diagfwd_usb_driver);
return 0;
fail:
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 3342984eb795..ad6203fe5684 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -18,22 +18,26 @@
#include <linux/workqueue.h>
#include <linux/ratelimit.h>
#include <linux/platform_device.h>
-#ifdef USB_QCOM_DIAG_BRIDGE
-#include <linux/smux.h>
-#endif
#include "diag_mux.h"
#include "diagfwd_bridge.h"
-#ifdef USB_QCOM_DIAG_BRIDGE
+#ifdef CONFIG_USB_QCOM_DIAG_BRIDGE
#include "diagfwd_hsic.h"
-#include "diagfwd_smux.h"
#endif
#include "diagfwd_mhi.h"
#include "diag_dci.h"
-#ifdef CONFIG_MSM_MHI
-#define diag_mdm_init diag_mhi_init
-#else
-#define diag_mdm_init diag_hsic_init
+#ifndef CONFIG_USB_QCOM_DIAG_BRIDGE
+static int diag_hsic_init(void)
+{
+ return -EINVAL;
+}
+#endif
+
+#ifndef CONFIG_MSM_MHI
+static int diag_mhi_init(void)
+{
+ return -EINVAL;
+}
#endif
#define BRIDGE_TO_MUX(x) (x + DIAG_MUX_BRIDGE_BASE)
@@ -265,18 +269,16 @@ int diag_remote_dev_write_done(int id, unsigned char *buf, int len, int ctxt)
return err;
}
-int diagfwd_bridge_init()
+int diagfwd_bridge_init(bool use_mhi)
{
int err = 0;
- err = diag_mdm_init();
+ if (use_mhi)
+ err = diag_mhi_init();
+ else
+ err = diag_hsic_init();
if (err)
goto fail;
- #ifdef USB_QCOM_DIAG_BRIDGE
- err = diag_smux_init();
- if (err)
- goto fail;
- #endif
return 0;
fail:
@@ -288,7 +290,6 @@ void diagfwd_bridge_exit()
{
#ifdef USB_QCOM_DIAG_BRIDGE
diag_hsic_exit();
- diag_smux_exit();
#endif
}
diff --git a/drivers/char/diag/diagfwd_bridge.h b/drivers/char/diag/diagfwd_bridge.h
index 62d6b08b5b89..250ef07b0b04 100644
--- a/drivers/char/diag/diagfwd_bridge.h
+++ b/drivers/char/diag/diagfwd_bridge.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -51,7 +51,7 @@ struct diagfwd_bridge_info {
};
extern struct diagfwd_bridge_info bridge_info[NUM_REMOTE_DEV];
-int diagfwd_bridge_init(void);
+int diagfwd_bridge_init(bool use_mhi);
void diagfwd_bridge_exit(void);
int diagfwd_bridge_close(int id);
int diagfwd_bridge_write(int id, unsigned char *buf, int len);
diff --git a/drivers/clk/msm/clock-mmss-8996.c b/drivers/clk/msm/clock-mmss-8996.c
index 91c871cae225..30169d3f3a98 100644
--- a/drivers/clk/msm/clock-mmss-8996.c
+++ b/drivers/clk/msm/clock-mmss-8996.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -1517,6 +1517,7 @@ static struct rcg_clk extpclk_clk_src = {
.dbg_name = "extpclk_clk_src",
.parent = &ext_extpclk_clk_src.c,
.ops = &clk_ops_byte,
+ .flags = CLKFLAG_NO_RATE_CACHE,
VDD_DIG_FMAX_MAP3(LOWER, 150000000, LOW, 300000000,
NOMINAL, 600000000),
CLK_INIT(extpclk_clk_src.c),
@@ -2532,6 +2533,7 @@ static struct branch_clk mdss_extpclk_clk = {
.dbg_name = "mdss_extpclk_clk",
.parent = &extpclk_clk_src.c,
.ops = &clk_ops_branch,
+ .flags = CLKFLAG_NO_RATE_CACHE,
CLK_INIT(mdss_extpclk_clk.c),
},
};
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 678b2178cb69..f8758e063146 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -49,6 +49,7 @@ msm_drm-y := \
sde/sde_color_processing.o \
sde/sde_vbif.o \
sde/sde_splash.o \
+ sde/sde_recovery_manager.o \
sde_dbg.o \
sde_dbg_evtlog.o \
sde_io_util.o \
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index b1cd666f8be4..252a6289881f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -484,7 +484,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev,
}
ctrl->hw.base = ptr;
- pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name,
+ pr_debug("[%s] map dsi_ctrl registers to %pK\n", ctrl->name,
ctrl->hw.base);
ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index da3b3b548e5f..5bcd0d0634b6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -93,7 +93,8 @@ static int dsi_phy_regmap_init(struct platform_device *pdev,
phy->hw.base = ptr;
- pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base);
+ pr_debug("[%s] map dsi_phy registers to %pK\n",
+ phy->name, phy->hw.base);
return rc;
}
diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
index 0940e84b2821..2c9d11638f29 100644
--- a/drivers/gpu/drm/msm/edp/edp.c
+++ b/drivers/gpu/drm/msm/edp/edp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015,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
@@ -54,7 +54,7 @@ static struct msm_edp *edp_init(struct platform_device *pdev)
ret = -ENOMEM;
goto fail;
}
- DBG("eDP probed=%p", edp);
+ DBG("eDP probed=%pK", edp);
edp->pdev = pdev;
platform_set_drvdata(pdev, edp);
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 46cc521a09f3..302ed39d9218 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -3069,6 +3069,8 @@ static int _sde_hdmi_parse_dt(struct device_node *node,
{
int rc = 0;
+ struct hdmi *hdmi = display->ctrl.ctrl;
+
display->name = of_get_property(node, "label", NULL);
display->display_type = of_get_property(node,
@@ -3079,6 +3081,11 @@ static int _sde_hdmi_parse_dt(struct device_node *node,
display->non_pluggable = of_property_read_bool(node,
"qcom,non-pluggable");
+ display->skip_ddc = of_property_read_bool(node,
+ "qcom,skip_ddc");
+ if (!display->non_pluggable)
+ hdmi_i2c_destroy(hdmi->i2c);
+
rc = _sde_hdmi_parse_dt_modes(node, &display->mode_list,
&display->num_of_modes);
if (rc)
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 9cf807e829c7..2aa8d9496c5b 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -154,6 +154,7 @@ struct sde_hdmi {
struct sde_edid_ctrl *edid_ctrl;
bool non_pluggable;
+ bool skip_ddc;
u32 num_of_modes;
struct list_head mode_list;
struct drm_display_mode mode;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index bae6b1c84420..2d65fc924f07 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -512,8 +512,8 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
}
hdmi->power_on = true;
}
-
- _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode);
+ if (!display->skip_ddc)
+ _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode);
if (phy)
phy->funcs->powerup(phy, hdmi->pixclock);
@@ -822,6 +822,8 @@ static u32 _sde_hdmi_choose_best_format(struct hdmi *hdmi,
*/
int dc_format;
struct drm_connector *connector = hdmi->connector;
+ struct sde_connector *c_conn = to_sde_connector(connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
dc_format = sde_hdmi_sink_dc_support(connector, mode);
if (dc_format & MSM_MODE_FLAG_RGB444_DC_ENABLE)
@@ -835,7 +837,8 @@ static u32 _sde_hdmi_choose_best_format(struct hdmi *hdmi,
else if (mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV)
return MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420;
- SDE_ERROR("Can't get available best display format\n");
+ if (display && !display->non_pluggable)
+ SDE_ERROR("Can't get available best display format\n");
return MSM_MODE_FLAG_COLOR_FORMAT_RGB444;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index b57663013dcb..f1bd9967ba81 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -145,7 +145,8 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
}
if (reglog)
- printk(KERN_DEBUG "IO:region %s %p %08lx\n", dbgname, ptr, size);
+ dev_dbg(&pdev->dev, "IO:region %s %pK %08lx\n",
+ dbgname, ptr, size);
return ptr;
}
@@ -158,7 +159,7 @@ void msm_iounmap(struct platform_device *pdev, void __iomem *addr)
void msm_writel(u32 data, void __iomem *addr)
{
if (reglog)
- printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
+ pr_debug("IO:W %pK %08x\n", addr, data);
writel(data, addr);
}
@@ -166,7 +167,7 @@ u32 msm_readl(const void __iomem *addr)
{
u32 val = readl(addr);
if (reglog)
- printk(KERN_ERR "IO:R %p %08x\n", addr, val);
+ pr_err("IO:R %pK %08x\n", addr, val);
return val;
}
@@ -895,7 +896,7 @@ static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe)
struct msm_kms *kms = priv->kms;
if (!kms)
return -ENXIO;
- DBG("dev=%p, crtc=%u", dev, pipe);
+ DBG("dev=%pK, crtc=%u", dev, pipe);
return vblank_ctrl_queue_work(priv, pipe, true);
}
@@ -905,7 +906,7 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe)
struct msm_kms *kms = priv->kms;
if (!kms)
return;
- DBG("dev=%p, crtc=%u", dev, pipe);
+ DBG("dev=%pK, crtc=%u", dev, pipe);
vblank_ctrl_queue_work(priv, pipe, false);
}
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index d222fdd69a57..8d6d83bf6540 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -59,7 +60,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb)
msm_fb = to_msm_framebuffer(fb);
n = drm_format_num_planes(fb->pixel_format);
- DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
+ DBG("destroy: FB ID: %d (%pK)", fb->base.id, fb);
drm_framebuffer_cleanup(fb);
@@ -239,7 +240,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
unsigned int hsub, vsub;
bool is_modified = false;
- DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
+ DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)",
dev, mode_cmd, mode_cmd->width, mode_cmd->height,
(char *)&mode_cmd->pixel_format);
@@ -322,7 +323,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
goto fail;
}
- DBG("create: FB ID: %d (%p)", fb->base.id, fb);
+ DBG("create: FB ID: %d (%pK)", fb->base.id, fb);
return fb;
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 28b98cc1433c..c71e662d0da1 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -144,7 +144,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
goto fail_unlock;
}
- DBG("fbi=%p, dev=%p", fbi, dev);
+ DBG("fbi=%pK, dev=%pK", fbi, dev);
fbdev->fb = fb;
helper->fb = fb;
@@ -166,7 +166,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
fbi->fix.smem_start = lower_32_bits(paddr);
fbi->fix.smem_len = fbdev->bo->size;
- DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
+ DBG("par=%pK, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 3610c8fca5f3..ce5adef21a00 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -410,7 +410,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
pfn = page_to_pfn(pages[pgoff]);
- VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
+ VERB("Inserting %pK pfn %lx, pa %lx", vmf->virtual_address,
pfn, pfn << PAGE_SHIFT);
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
@@ -770,7 +770,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
uint64_t off = drm_vma_node_start(&obj->vma_node);
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
- seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p\t",
+ seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %pK\t",
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
msm_obj->read_fence, msm_obj->write_fence,
obj->name, obj->refcount.refcount.counter,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6ad1ce16c20a..01da32ae5958 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1563,7 +1563,7 @@ void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc,
{
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
- SDE_DEBUG("%s: cancel: %p\n", sde_crtc->name, file);
+ SDE_DEBUG("%s: cancel: %pK\n", sde_crtc->name, file);
_sde_crtc_complete_flip(crtc, file);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index fa17768d9939..77fdcd86c920 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -21,6 +21,7 @@
#include <linux/seq_file.h>
#include "msm_drv.h"
+#include "sde_recovery_manager.h"
#include "sde_kms.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
@@ -603,6 +604,7 @@ static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc,
atomic_inc(&phy_enc->underrun_cnt);
SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt));
+ sde_recovery_set_events(SDE_UNDERRUN);
trace_sde_encoder_underrun(DRMID(drm_enc),
atomic_read(&phy_enc->underrun_cnt));
SDE_DBG_CTRL("stop_ftrace");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 2f89c571fcfc..8db77f2c60e8 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -11,6 +11,7 @@
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+#include "sde_recovery_manager.h"
#include "sde_encoder_phys.h"
#include "sde_hw_interrupts.h"
#include "sde_core_irq.h"
@@ -704,6 +705,7 @@ static int sde_encoder_phys_vid_wait_for_vblank(
SDE_EVT32(DRMID(phys_enc->parent),
vid_enc->hw_intf->idx - INTF_0);
SDE_ERROR_VIDENC(vid_enc, "kickoff timed out\n");
+ sde_recovery_set_events(SDE_VSYNC_MISS);
if (notify && phys_enc->parent_ops.handle_frame_done)
phys_enc->parent_ops.handle_frame_done(
phys_enc->parent, phys_enc,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
index 6a8d9e0cf2e3..76d99c1e8e65 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
@@ -367,7 +367,7 @@ void sde_setup_dspp_pcc_v1_7(struct sde_hw_dspp *ctx, void *cfg)
void __iomem *base;
if (!hw_cfg || (hw_cfg->len != sizeof(*pcc) && hw_cfg->payload)) {
- DRM_ERROR("invalid params hw %p payload %p payloadsize %d \"\
+ DRM_ERROR("invalid params hw %pK payload %pK payloadsize %d \"\
exp size %zd\n",
hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
((hw_cfg) ? hw_cfg->len : 0), sizeof(*pcc));
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 95ab14ffc3ac..676d480ca802 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -37,6 +37,7 @@
#include "sde_encoder.h"
#include "sde_plane.h"
#include "sde_crtc.h"
+#include "sde_recovery_manager.h"
#define CREATE_TRACE_POINTS
#include "sde_trace.h"
@@ -58,6 +59,19 @@
#define SDE_DEBUGFS_DIR "msm_sde"
#define SDE_DEBUGFS_HWMASKNAME "hw_log_mask"
+static int sde_kms_recovery_callback(int err_code,
+ struct recovery_client_info *client_info);
+
+static struct recovery_client_info info = {
+ .name = "sde_kms",
+ .recovery_cb = sde_kms_recovery_callback,
+ .err_supported[0] = {SDE_UNDERRUN, 0, 0},
+ .err_supported[1] = {SDE_VSYNC_MISS, 0, 0},
+ .no_of_err = 2,
+ .handle = NULL,
+ .pdata = NULL,
+};
+
/**
* sdecustom - enable certain driver customizations for sde clients
* Enabling this modifies the standard DRM behavior slightly and assumes
@@ -1062,6 +1076,8 @@ static void sde_kms_destroy(struct msm_kms *kms)
return;
}
+ sde_recovery_client_unregister(info.handle);
+ info.handle = NULL;
_sde_kms_hw_destroy(sde_kms, dev->platformdev);
kfree(sde_kms);
}
@@ -1264,6 +1280,11 @@ static int sde_kms_hw_init(struct msm_kms *kms)
goto end;
}
+ rc = sde_recovery_client_register(&info);
+ if (rc)
+ pr_err("%s recovery mgr register failed %d\n",
+ __func__, rc);
+
sde_kms = to_sde_kms(kms);
dev = sde_kms->dev;
if (!dev || !dev->platformdev) {
@@ -1283,7 +1304,7 @@ static int sde_kms_hw_init(struct msm_kms *kms)
SDE_ERROR("mdp register memory map failed\n");
goto error;
}
- DRM_INFO("mapped mdp address space @%p\n", sde_kms->mmio);
+ DRM_INFO("mapped mdp address space @%pK\n", sde_kms->mmio);
rc = sde_dbg_reg_register_base(SDE_DBG_NAME, sde_kms->mmio,
sde_kms->mmio_len);
@@ -1487,10 +1508,34 @@ end:
return rc;
}
+static int sde_kms_recovery_callback(int err_code,
+ struct recovery_client_info *client_info)
+{
+ int rc = 0;
+
+ switch (err_code) {
+ case SDE_UNDERRUN:
+ pr_debug("%s [SDE_UNDERRUN] error is auto HW receovered\n",
+ __func__);
+ break;
+
+ case SDE_VSYNC_MISS:
+ pr_debug("%s [SDE_VSYNC_MISS] trigger soft reset\n", __func__);
+ break;
+
+ default:
+ pr_err("%s error %d undefined\n", __func__, err_code);
+
+ }
+
+ return rc;
+}
+
struct msm_kms *sde_kms_init(struct drm_device *dev)
{
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
+ int rc = 0;
if (!dev || !dev->dev_private) {
SDE_ERROR("drm device node invalid\n");
@@ -1505,6 +1550,13 @@ struct msm_kms *sde_kms_init(struct drm_device *dev)
return ERR_PTR(-ENOMEM);
}
+ rc = sde_init_recovery_mgr(dev);
+ if (rc) {
+ SDE_ERROR("Failed SDE recovery mgr Init, err = %d\n", rc);
+ kfree(sde_kms);
+ return ERR_PTR(-EFAULT);
+ }
+
msm_kms_init(&sde_kms->base, &kms_funcs);
sde_kms->dev = dev;
diff --git a/drivers/gpu/drm/msm/sde/sde_recovery_manager.c b/drivers/gpu/drm/msm/sde/sde_recovery_manager.c
new file mode 100644
index 000000000000..ae42fd309293
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_recovery_manager.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#include "sde_recovery_manager.h"
+#include "sde_kms.h"
+
+
+static struct recovery_mgr_info *rec_mgr;
+
+static ssize_t sde_recovery_mgr_rda_clients_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ struct list_head *pos;
+ struct recovery_client_db *temp = NULL;
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ len = snprintf(buf, PAGE_SIZE, "Clients:\n");
+
+ list_for_each(pos, &rec_mgr->client_list) {
+ temp = list_entry(pos, struct recovery_client_db, list);
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+ temp->client_info.name);
+ }
+
+ mutex_unlock(&rec_mgr->rec_lock);
+
+ return len;
+}
+
+static DEVICE_ATTR(clients, S_IRUGO, sde_recovery_mgr_rda_clients_attr, NULL);
+
+static struct attribute *recovery_attrs[] = {
+ &dev_attr_clients.attr,
+ NULL,
+};
+
+static struct attribute_group recovery_mgr_attr_group = {
+ .attrs = recovery_attrs,
+};
+
+static void sde_recovery_mgr_notify(bool err_state)
+{
+ char *envp[2];
+ char *uevent_str = kzalloc(SZ_4K, GFP_KERNEL);
+
+ if (uevent_str == NULL) {
+ DRM_ERROR("failed to allocate event string\n");
+ return;
+ }
+ if (err_state == true)
+ snprintf(uevent_str, MAX_REC_UEVENT_LEN,
+ "DISPLAY_ERROR_RECOVERED\n");
+ else
+ snprintf(uevent_str, MAX_REC_UEVENT_LEN,
+ "DISPLAY_CRITICAL_ERROR\n");
+
+ DRM_DEBUG("generating uevent [%s]\n", uevent_str);
+
+ envp[0] = uevent_str;
+ envp[1] = NULL;
+
+ mutex_lock(&rec_mgr->dev->mode_config.mutex);
+ kobject_uevent_env(&rec_mgr->dev->primary->kdev->kobj,
+ KOBJ_CHANGE, envp);
+ mutex_unlock(&rec_mgr->dev->mode_config.mutex);
+ kfree(uevent_str);
+}
+
+static void sde_recovery_mgr_recover(int err_code)
+{
+ struct list_head *pos;
+ struct recovery_client_db *c = NULL;
+ int tmp_err, rc, pre, post, i;
+ bool found = false;
+ static bool rec_flag = true;
+
+ mutex_lock(&rec_mgr->rec_lock);
+ list_for_each(pos, &rec_mgr->client_list) {
+ c = list_entry(pos, struct recovery_client_db, list);
+
+ mutex_unlock(&rec_mgr->rec_lock);
+
+ for (i = 0; i < MAX_REC_ERR_SUPPORT; i++) {
+ tmp_err = c->client_info.err_supported[i].
+ reported_err_code;
+ if (tmp_err == err_code) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == true) {
+
+ pre = c->client_info.err_supported[i].pre_err_code;
+ if (pre && pre != '0')
+ sde_recovery_mgr_recover(pre);
+
+ if (c->client_info.recovery_cb) {
+ rc = c->client_info.recovery_cb(err_code,
+ &c->client_info);
+ if (rc) {
+ pr_err("%s failed to recover error %d\n",
+ __func__, err_code);
+ rec_flag = false;
+ } else {
+ pr_debug("%s Recovery successful[%d]\n",
+ __func__, err_code);
+ }
+ }
+
+ post = c->client_info.err_supported[i].post_err_code;
+ if (post && post != '0')
+ sde_recovery_mgr_recover(post);
+
+ }
+ mutex_lock(&rec_mgr->rec_lock);
+
+ if (found)
+ break;
+ }
+
+ if (rec_flag) {
+ pr_debug("%s successful full recovery\n", __func__);
+ sde_recovery_mgr_notify(true);
+ }
+
+ mutex_unlock(&rec_mgr->rec_lock);
+}
+
+static void sde_recovery_mgr_event_work(struct work_struct *work)
+{
+ struct list_head *pos, *q;
+ struct recovery_event_db *temp_event;
+ int err_code;
+
+ if (!rec_mgr) {
+ pr_err("%s recovery manager is NULL\n", __func__);
+ return;
+ }
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ list_for_each_safe(pos, q, &rec_mgr->event_list) {
+ temp_event = list_entry(pos, struct recovery_event_db, list);
+
+ err_code = temp_event->err;
+
+ rec_mgr->recovery_ongoing = true;
+
+ mutex_unlock(&rec_mgr->rec_lock);
+
+ /* notify error */
+ sde_recovery_mgr_notify(false);
+ /* recover error */
+ sde_recovery_mgr_recover(err_code);
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ list_del(pos);
+ kfree(temp_event);
+ }
+
+ rec_mgr->recovery_ongoing = false;
+ mutex_unlock(&rec_mgr->rec_lock);
+
+}
+
+int sde_recovery_set_events(int err)
+{
+ int rc = 0;
+ struct list_head *pos;
+ struct recovery_event_db *temp;
+ bool found = false;
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ /* check if there is same event in the list */
+ list_for_each(pos, &rec_mgr->event_list) {
+ temp = list_entry(pos, struct recovery_event_db, list);
+ if (err == temp->err) {
+ found = true;
+ pr_info("%s error %d is already present in list\n",
+ __func__, err);
+ break;
+ }
+ }
+
+ if (!found) {
+ temp = kzalloc(sizeof(struct recovery_event_db), GFP_KERNEL);
+ if (!temp) {
+ pr_err("%s out of memory\n", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ temp->err = err;
+
+ list_add_tail(&temp->list, &rec_mgr->event_list);
+ queue_work(rec_mgr->event_queue, &rec_mgr->event_work);
+ }
+
+out:
+ mutex_unlock(&rec_mgr->rec_lock);
+ return rc;
+}
+
+int sde_recovery_client_register(struct recovery_client_info *client)
+{
+ int rc = 0;
+ struct list_head *pos;
+ struct recovery_client_db *c = NULL;
+ bool found = false;
+
+ if (!rec_mgr) {
+ pr_err("%s recovery manager is not initialized\n", __func__);
+ return -EPERM;
+ }
+
+ if (!strlen(client->name)) {
+ pr_err("%s client name is empty\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ /* check if there is same client */
+ list_for_each(pos, &rec_mgr->client_list) {
+ c = list_entry(pos, struct recovery_client_db, list);
+ if (!strcmp(c->client_info.name,
+ client->name)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ pr_err("%s out of memory for client", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ } else {
+ pr_err("%s client = %s is already registered\n",
+ __func__, client->name);
+ client->handle = c;
+ goto out;
+ }
+
+ memcpy(&(c->client_info), client, sizeof(struct recovery_client_info));
+
+ list_add_tail(&c->list, &rec_mgr->client_list);
+ rec_mgr->num_of_clients++;
+
+ client->handle = c;
+
+out:
+ mutex_unlock(&rec_mgr->rec_lock);
+ return rc;
+}
+
+int sde_recovery_client_unregister(void *handle)
+{
+ struct list_head *pos, *q, *pos1;
+ struct recovery_client_db *temp_client;
+ struct recovery_event_db *temp;
+ int client_err = 0;
+ bool found = false;
+ bool found_pending = false;
+ int i, rc = 0;
+ struct recovery_client_info *client =
+ &((struct recovery_client_db *)handle)->client_info;
+
+ if (!handle) {
+ pr_err("%s handle is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!strlen(client->name)) {
+ pr_err("%s client name is empty\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rec_mgr->rec_lock);
+
+ if (rec_mgr->recovery_ongoing) {
+ pr_err("%s SDE Executing Recovery, Failed! Unregister client %s\n",
+ __func__, client->name);
+ goto out;
+ }
+
+ /* check if client is present in the list */
+ list_for_each_safe(pos, q, &rec_mgr->client_list) {
+ temp_client = list_entry(pos, struct recovery_client_db, list);
+ if (!strcmp(temp_client->client_info.name, client->name)) {
+ found = true;
+
+ /* free any pending event for this client */
+ list_for_each(pos1, &rec_mgr->event_list) {
+ temp = list_entry(pos1,
+ struct recovery_event_db, list);
+
+ found_pending = false;
+ for (i = 0; i < MAX_REC_ERR_SUPPORT; i++) {
+ client_err = temp_client->
+ client_info.err_supported[i].
+ reported_err_code;
+ if (temp->err == client_err)
+ found_pending = true;
+ }
+
+ if (found_pending) {
+ list_del(pos1);
+ kfree(temp);
+ }
+ }
+
+ list_del(pos);
+ kfree(temp_client);
+ rec_mgr->num_of_clients--;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("%s can't find the client[%s] from db\n",
+ __func__, client->name);
+ rc = -EFAULT;
+ }
+
+out:
+ mutex_unlock(&rec_mgr->rec_lock);
+ return rc;
+}
+
+int sde_init_recovery_mgr(struct drm_device *dev)
+{
+ struct recovery_mgr_info *rec = NULL;
+ int rc = 0;
+
+ if (!dev || !dev->dev_private) {
+ SDE_ERROR("drm device node invalid\n");
+ return -EINVAL;
+ }
+
+ rec = kzalloc(sizeof(struct recovery_mgr_info), GFP_KERNEL);
+ if (!rec)
+ return -ENOMEM;
+
+ mutex_init(&rec->rec_lock);
+
+ rec->dev = dev;
+ rc = sysfs_create_group(&dev->primary->kdev->kobj,
+ &recovery_mgr_attr_group);
+ if (rc) {
+ pr_err("%s sysfs_create_group fails=%d", __func__, rc);
+ rec->sysfs_created = false;
+ } else {
+ rec->sysfs_created = true;
+ }
+
+ INIT_LIST_HEAD(&rec->event_list);
+ INIT_LIST_HEAD(&rec->client_list);
+ INIT_WORK(&rec->event_work, sde_recovery_mgr_event_work);
+ rec->event_queue = create_workqueue("recovery_event");
+
+ if (IS_ERR_OR_NULL(rec->event_queue)) {
+ pr_err("%s unable to create queue; errno = %ld",
+ __func__, PTR_ERR(rec->event_queue));
+ rec->event_queue = NULL;
+ rc = -EFAULT;
+ goto err;
+ }
+
+ rec_mgr = rec;
+
+ return rc;
+
+err:
+ mutex_destroy(&rec->rec_lock);
+ if (rec->sysfs_created)
+ sysfs_remove_group(&rec_mgr->dev->primary->kdev->kobj,
+ &recovery_mgr_attr_group);
+ kfree(rec);
+ return rc;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_recovery_manager.h b/drivers/gpu/drm/msm/sde/sde_recovery_manager.h
new file mode 100644
index 000000000000..32fe17a187a0
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_recovery_manager.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 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 __SDE_RECOVERY_MANAGER_H__
+#define __SDE_RECOVERY_MANAGER_H__
+
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <drm/msm_drm.h>
+#include <linux/slab.h>
+#include <drm/drmP.h>
+
+
+
+/* MSM Recovery Manager related definitions */
+
+#define MAX_REC_NAME_LEN (16)
+#define MAX_REC_UEVENT_LEN (64)
+#define MAX_REC_ERR_SUPPORT (2)
+
+/* MSM Recovery Manager Error Code */
+#define SDE_UNDERRUN 222
+#define SDE_VSYNC_MISS 333
+
+/**
+ * struct recovery_mgr_info - Recovery manager information
+ * @dev: drm device.
+ * @rec_lock: mutex lock for synchronized access to recovery mgr data.
+ * @event_list: list of reported events.
+ * @client_list: list of registered clients.
+ * @event_work: work for event handling.
+ * @event_queue: Queue for scheduling the event work.
+ * @num_of_clients: no. of clients registered.
+ * @recovery_ongoing: status indicating execution of recovery thread.
+ */
+struct recovery_mgr_info {
+ struct drm_device *dev;
+ struct mutex rec_lock;
+ struct list_head event_list;
+ struct list_head client_list;
+ struct work_struct event_work;
+ struct workqueue_struct *event_queue;
+ int num_of_clients;
+ int sysfs_created;
+ int recovery_ongoing;
+};
+
+/**
+ * struct recovery_error_info - Error information
+ * @reported_err_code: error reported for recovery.
+ * @pre_err_code: list of errors to be recovered before reported_err_code.
+ * @post_err_code: list of errors to be recovered after reported_err_code.
+ */
+struct recovery_error_info {
+ int reported_err_code;
+ int pre_err_code;
+ int post_err_code;
+};
+
+/**
+ * struct recovery_client_info - Client information
+ * @name: name of the client.
+ * @recovery_cb: recovery callback to recover the errors reported.
+ * @err_supported: list of errors that can be detected by client.
+ * @no_of_err: no. of errors supported by the client.
+ * @handle: Opaque handle passed to client
+ */
+struct recovery_client_info {
+ char name[MAX_REC_NAME_LEN];
+ int (*recovery_cb)(int err_code,
+ struct recovery_client_info *client_info);
+ struct recovery_error_info
+ err_supported[MAX_REC_ERR_SUPPORT];
+ int no_of_err;
+ void *pdata;
+ void *handle;
+};
+
+/**
+ * struct recovery_event_db - event database.
+ * @err: error code that client reports.
+ * @list: list pointer.
+ */
+struct recovery_event_db {
+ int err;
+ struct list_head list;
+};
+
+/**
+ * struct recovery_client_db - client database.
+ * @client_info: information that client registers.
+ * @list: list pointer.
+ */
+struct recovery_client_db {
+ struct recovery_client_info client_info;
+ struct list_head list;
+};
+
+int sde_recovery_set_events(int err);
+int sde_recovery_client_register(struct recovery_client_info *client);
+int sde_recovery_client_unregister(void *handle);
+int sde_init_recovery_mgr(struct drm_device *dev);
+
+
+#endif /* __SDE_RECOVERY_MANAGER_H__ */
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index c21846c1f8d5..566572ae051e 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-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
@@ -168,6 +168,7 @@ struct iommu_debug_device {
size_t len;
struct list_head list;
struct mutex clk_lock;
+ struct mutex dev_lock;
unsigned int clk_count;
};
@@ -1239,6 +1240,7 @@ static ssize_t __iommu_debug_dma_attach_write(struct file *file,
ssize_t retval = -EINVAL;
int val;
+ mutex_lock(&ddev->dev_lock);
if (kstrtoint_from_user(ubuf, count, 0, &val)) {
pr_err("Invalid format. Expected a hex or decimal integer");
retval = -EFAULT;
@@ -1282,12 +1284,14 @@ static ssize_t __iommu_debug_dma_attach_write(struct file *file,
arm_iommu_release_mapping(dev->archdata.mapping);
pr_err("Detached\n");
}
+ mutex_unlock(&ddev->dev_lock);
retval = count;
return retval;
out_release_mapping:
arm_iommu_release_mapping(dma_mapping);
out:
+ mutex_unlock(&ddev->dev_lock);
return retval;
}
@@ -1300,6 +1304,7 @@ static ssize_t __iommu_debug_attach_write(struct file *file,
ssize_t retval;
int val;
+ mutex_lock(&ddev->dev_lock);
if (kstrtoint_from_user(ubuf, count, 0, &val)) {
pr_err("Invalid format. Expected a hex or decimal integer");
retval = -EFAULT;
@@ -1336,6 +1341,7 @@ static ssize_t __iommu_debug_attach_write(struct file *file,
retval = count;
out:
+ mutex_unlock(&ddev->dev_lock);
return retval;
}
@@ -1714,6 +1720,7 @@ static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
if (kstrtoint(comma3 + 1, 0, &prot))
goto invalid_format;
+ mutex_lock(&ddev->dev_lock);
ret = iommu_map(ddev->domain, iova, phys, size, prot);
if (ret) {
pr_err("iommu_map failed with %d\n", ret);
@@ -1725,6 +1732,7 @@ static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
pr_err("Mapped %pa to %pa (len=0x%zx, prot=0x%x)\n",
&iova, &phys, size, prot);
out:
+ mutex_unlock(&ddev->dev_lock);
return retval;
invalid_format:
@@ -1812,14 +1820,17 @@ static ssize_t iommu_debug_dma_map_write(struct file *file,
else
goto invalid_format;
+ mutex_lock(&ddev->dev_lock);
iova = dma_map_single_attrs(dev, v_addr, size,
DMA_TO_DEVICE, dma_attrs);
if (dma_mapping_error(dev, iova)) {
pr_err("Failed to perform dma_map_single\n");
ret = -EINVAL;
+ mutex_unlock(&ddev->dev_lock);
goto out;
}
+ mutex_unlock(&ddev->dev_lock);
retval = count;
pr_err("Mapped 0x%p to %pa (len=0x%zx)\n",
@@ -1926,12 +1937,15 @@ static ssize_t iommu_debug_unmap_write(struct file *file,
if (kstrtosize_t(comma1 + 1, 0, &size))
goto invalid_format;
+ mutex_lock(&ddev->dev_lock);
unmapped = iommu_unmap(ddev->domain, iova, size);
if (unmapped != size) {
pr_err("iommu_unmap failed. Expected to unmap: 0x%zx, unmapped: 0x%zx",
size, unmapped);
+ mutex_unlock(&ddev->dev_lock);
return -EIO;
}
+ mutex_unlock(&ddev->dev_lock);
retval = count;
pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
@@ -2017,7 +2031,9 @@ static ssize_t iommu_debug_dma_unmap_write(struct file *file,
else
goto invalid_format;
+ mutex_lock(&ddev->dev_lock);
dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs);
+ mutex_unlock(&ddev->dev_lock);
retval = count;
pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
@@ -2112,6 +2128,7 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
if (!ddev)
return -ENODEV;
mutex_init(&ddev->clk_lock);
+ mutex_init(&ddev->dev_lock);
ddev->dev = dev;
dir = debugfs_create_dir(name, debugfs_tests_dir);
if (!dir) {
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 713a47cfea7f..eb2b37ce1095 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -1134,11 +1134,12 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
case VIDIOC_G_AVI_INFOFRAME: {
int int_raw = adv7481_rd_byte(&state->i2c_client,
state->i2c_io_addr,
- IO_HDMI_EDG_RAW_STATUS_1_ADDR);
+ IO_HDMI_LVL_RAW_STATUS_1_ADDR);
adv7481_wr_byte(&state->i2c_client,
state->i2c_io_addr,
- IO_HDMI_EDG_INT_CLEAR_1_ADDR, int_raw);
- if (ADV_REG_GETFIELD(int_raw, IO_NEW_AVI_INFO_RAW)) {
+ IO_HDMI_LVL_INT_CLEAR_1_ADDR, int_raw);
+ pr_debug("%s: VIDIOC_G_AVI_INFOFRAME\n", __func__);
+ if (ADV_REG_GETFIELD(int_raw, IO_AVI_INFO_RAW)) {
inf_buffer[0] = adv7481_rd_byte(&state->i2c_client,
state->i2c_hdmi_inf_addr,
HDMI_REG_AVI_PACKET_ID_ADDR);
@@ -1154,13 +1155,13 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
&inf_buffer[3],
INFOFRAME_DATA_SIZE);
if (ret) {
- pr_err("%s:Error in VIDIOC_G_AVI_INFOFRAME\n",
+ pr_err("%s: Error in reading AVI Infoframe\n",
__func__);
return -EINVAL;
}
if (hdmi_infoframe_unpack(&hdmi_info_frame,
(void *)inf_buffer) < 0) {
- pr_err("%s: infoframe unpack fail\n", __func__);
+ pr_err("%s: Infoframe unpack fail\n", __func__);
return -EINVAL;
}
hdmi_infoframe_log(KERN_ERR, dev, &hdmi_info_frame);
@@ -1173,12 +1174,13 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
state->hdmi_avi_infoframe.video_code =
hdmi_info_frame.avi.video_code;
} else {
- pr_err("%s: No new AVI Infoframe\n", __func__);
+ pr_err("%s: No AVI Infoframe\n", __func__);
+ return -EINVAL;
}
if (copy_to_user((void __user *)adv_arg.ptr,
(void *)&state->hdmi_avi_infoframe,
sizeof(struct avi_infoframe_params))) {
- pr_err("%s: Failed to copy Infoframe\n", __func__);
+ pr_err("%s: Failed to copy AVI Infoframe\n", __func__);
return -EINVAL;
}
break;
diff --git a/drivers/media/i2c/adv7481_reg.h b/drivers/media/i2c/adv7481_reg.h
index 403e538b6127..e1984f17d125 100644
--- a/drivers/media/i2c/adv7481_reg.h
+++ b/drivers/media/i2c/adv7481_reg.h
@@ -73,6 +73,10 @@
#define IO_CTRL_MASTER_PWDN_REG_VALUE 0x01
/* Interrupts */
+#define IO_HDMI_LVL_RAW_STATUS_1_ADDR 0x67
+#define IO_AVI_INFO_RAW_BMSK 0x0001
+#define IO_AVI_INFO_RAW_SHFT 0
+
#define IO_HDMI_LVL_INT_CLEAR_1_ADDR 0x69
#define IO_HDMI_LVL_INT_MASKB_1_ADDR 0x6B
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 925a89601636..da4db983f367 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -528,6 +528,12 @@ static void msm_isp_cfg_framedrop_reg(
enum msm_vfe_input_src frame_src = SRC_TO_INTF(stream_info->stream_src);
int i;
+ if (vfe_dev == NULL) {
+ pr_err("%s %d returning vfe_dev is NULL\n",
+ __func__, __LINE__);
+ return;
+ }
+
if (vfe_dev->axi_data.src_info[frame_src].frame_id >=
stream_info->init_frame_drop)
runtime_init_frame_drop = 0;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 0747f22ce56c..38ed503c637b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -4725,9 +4725,7 @@ static int mmc_blk_probe(struct mmc_card *card)
dev_set_drvdata(&card->dev, md);
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
mmc_set_bus_resume_policy(card->host, 1);
-#endif
if (mmc_add_disk(md))
goto out;
@@ -4772,9 +4770,7 @@ static void mmc_blk_remove(struct mmc_card *card)
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
dev_set_drvdata(&card->dev, NULL);
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
mmc_set_bus_resume_policy(card->host, 0);
-#endif
}
static int _mmc_blk_suspend(struct mmc_card *card, bool wait)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 151643caac84..e4e4e04e1d0c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1883,10 +1883,9 @@ EXPORT_SYMBOL(mmc_start_req);
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
if (mmc_bus_needs_resume(host))
mmc_resume_bus(host);
-#endif
+
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
}
@@ -2322,10 +2321,9 @@ void mmc_get_card(struct mmc_card *card)
{
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+
if (mmc_bus_needs_resume(card->host))
mmc_resume_bus(card->host);
-#endif
}
EXPORT_SYMBOL(mmc_get_card);
@@ -3277,6 +3275,7 @@ int mmc_resume_bus(struct mmc_host *host)
{
unsigned long flags;
int err = 0;
+ int card_present = true;
if (!mmc_bus_needs_resume(host))
return -EINVAL;
@@ -3287,7 +3286,10 @@ int mmc_resume_bus(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead && host->card) {
+ if (host->ops->get_cd)
+ card_present = host->ops->get_cd(host);
+
+ if (host->bus_ops && !host->bus_dead && host->card && card_present) {
mmc_power_up(host, host->card->ocr);
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
@@ -4523,7 +4525,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
- int err = 0;
+ int err = 0, present = 0;
switch (mode) {
case PM_RESTORE_PREPARE:
@@ -4570,8 +4572,12 @@ int mmc_pm_notify(struct notifier_block *notify_block,
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
+ if (host->ops->get_cd)
+ present = host->ops->get_cd(host);
+
if (mmc_bus_manual_resume(host) &&
- !host->ignore_bus_resume_flags) {
+ !host->ignore_bus_resume_flags &&
+ present) {
spin_unlock_irqrestore(&host->lock, flags);
break;
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2aa04b6bdfb3..bf896b605487 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1143,6 +1143,9 @@ static void mmc_sd_remove(struct mmc_host *host)
*/
static int mmc_sd_alive(struct mmc_host *host)
{
+ if (host->ops->get_cd && !host->ops->get_cd(host))
+ return -ENOMEDIUM;
+
return mmc_send_status(host->card, NULL);
}
@@ -1171,7 +1174,15 @@ static void mmc_sd_detect(struct mmc_host *host)
return;
}
- mmc_power_up(host, host->ocr_avail);
+ if (mmc_bus_needs_resume(host))
+ mmc_resume_bus(host);
+
+ if (host->ops->get_cd && !host->ops->get_cd(host)) {
+ err = -ENOMEDIUM;
+ mmc_card_set_removed(host->card);
+ mmc_card_clr_suspended(host->card);
+ goto out;
+ }
/*
* Just check if our card has been removed.
@@ -1195,6 +1206,7 @@ static void mmc_sd_detect(struct mmc_host *host)
err = _mmc_detect_card_removed(host);
#endif
+out:
mmc_put_card(host->card);
if (err) {
@@ -1279,6 +1291,11 @@ static int _mmc_sd_resume(struct mmc_host *host)
if (!mmc_card_suspended(host->card))
goto out;
+ if (host->ops->get_cd && !host->ops->get_cd(host)) {
+ mmc_card_clr_suspended(host->card);
+ goto out;
+ }
+
mmc_power_up(host, host->card->ocr);
#ifdef CONFIG_MMC_PARANOID_SD_INIT
retries = 5;
@@ -1379,6 +1396,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
static int mmc_sd_reset(struct mmc_host *host)
{
+ if (host->ops->get_cd && !host->ops->get_cd(host))
+ return -ENOMEDIUM;
+
mmc_power_cycle(host, host->card->ocr);
return mmc_sd_init_card(host, host->card->ocr, host->card);
}
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 27117ba47073..baa60fbccbae 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -34,6 +34,10 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id;
+ int present = host->ops->get_cd(host);
+
+ pr_debug("%s: cd gpio irq, gpio state %d (CARD_%s)\n",
+ mmc_hostname(host), present, present?"INSERT":"REMOVAL");
host->trigger_card_event = true;
mmc_detect_change(host, msecs_to_jiffies(200));
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 9710cf71054a..c0bcfa979253 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -42,7 +42,6 @@
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
-#include <linux/usb/cdc.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/pm_runtime.h>
@@ -1964,147 +1963,6 @@ out:
return err;
}
-int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
- struct usb_interface *intf,
- u8 *buffer,
- int buflen)
-{
- /* duplicates are ignored */
- struct usb_cdc_union_desc *union_header = NULL;
-
- /* duplicates are not tolerated */
- struct usb_cdc_header_desc *header = NULL;
- struct usb_cdc_ether_desc *ether = NULL;
- struct usb_cdc_mdlm_detail_desc *detail = NULL;
- struct usb_cdc_mdlm_desc *desc = NULL;
-
- unsigned int elength;
- int cnt = 0;
-
- memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
- hdr->phonet_magic_present = false;
- while (buflen > 0) {
- elength = buffer[0];
- if (!elength) {
- dev_err(&intf->dev, "skipping garbage byte\n");
- elength = 1;
- goto next_desc;
- }
- if ((buflen < elength) || (elength < 3)) {
- dev_err(&intf->dev, "invalid descriptor buffer length\n");
- break;
- }
- if (buffer[1] != USB_DT_CS_INTERFACE) {
- dev_err(&intf->dev, "skipping garbage\n");
- goto next_desc;
- }
-
- switch (buffer[2]) {
- case USB_CDC_UNION_TYPE: /* we've found it */
- if (elength < sizeof(struct usb_cdc_union_desc))
- goto next_desc;
- if (union_header) {
- dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
- goto next_desc;
- }
- union_header = (struct usb_cdc_union_desc *)buffer;
- break;
- case USB_CDC_COUNTRY_TYPE:
- if (elength < sizeof(struct usb_cdc_country_functional_desc))
- goto next_desc;
- hdr->usb_cdc_country_functional_desc =
- (struct usb_cdc_country_functional_desc *)buffer;
- break;
- case USB_CDC_HEADER_TYPE:
- if (elength != sizeof(struct usb_cdc_header_desc))
- goto next_desc;
- if (header)
- return -EINVAL;
- header = (struct usb_cdc_header_desc *)buffer;
- break;
- case USB_CDC_ACM_TYPE:
- if (elength < sizeof(struct usb_cdc_acm_descriptor))
- goto next_desc;
- hdr->usb_cdc_acm_descriptor =
- (struct usb_cdc_acm_descriptor *)buffer;
- break;
- case USB_CDC_ETHERNET_TYPE:
- if (elength != sizeof(struct usb_cdc_ether_desc))
- goto next_desc;
- if (ether)
- return -EINVAL;
- ether = (struct usb_cdc_ether_desc *)buffer;
- break;
- case USB_CDC_CALL_MANAGEMENT_TYPE:
- if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
- goto next_desc;
- hdr->usb_cdc_call_mgmt_descriptor =
- (struct usb_cdc_call_mgmt_descriptor *)buffer;
- break;
- case USB_CDC_DMM_TYPE:
- if (elength < sizeof(struct usb_cdc_dmm_desc))
- goto next_desc;
- hdr->usb_cdc_dmm_desc =
- (struct usb_cdc_dmm_desc *)buffer;
- break;
- case USB_CDC_MDLM_TYPE:
- if (elength < sizeof(struct usb_cdc_mdlm_desc *))
- goto next_desc;
- if (desc)
- return -EINVAL;
- desc = (struct usb_cdc_mdlm_desc *)buffer;
- break;
- case USB_CDC_MDLM_DETAIL_TYPE:
- if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
- goto next_desc;
- if (detail)
- return -EINVAL;
- detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
- break;
- case USB_CDC_NCM_TYPE:
- if (elength < sizeof(struct usb_cdc_ncm_desc))
- goto next_desc;
- hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
- break;
- case USB_CDC_MBIM_TYPE:
- if (elength < sizeof(struct usb_cdc_mbim_desc))
- goto next_desc;
-
- hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
- break;
- case USB_CDC_MBIM_EXTENDED_TYPE:
- if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
- break;
- hdr->usb_cdc_mbim_extended_desc =
- (struct usb_cdc_mbim_extended_desc *)buffer;
- break;
- case CDC_PHONET_MAGIC_NUMBER:
- hdr->phonet_magic_present = true;
- break;
- default:
- /*
- * there are LOTS more CDC descriptors that
- * could legitimately be found here.
- */
- dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
- buffer[2], elength);
- goto next_desc;
- }
- cnt++;
-next_desc:
- buflen -= elength;
- buffer += elength;
- }
- hdr->usb_cdc_union_desc = union_header;
- hdr->usb_cdc_header_desc = header;
- hdr->usb_cdc_mdlm_detail_desc = detail;
- hdr->usb_cdc_mdlm_desc = desc;
- hdr->usb_cdc_ether_desc = ether;
- return cnt;
-}
-
-EXPORT_SYMBOL(cdc_parse_cdc_header);
-
/*
* The function can't be called inside suspend/resume callback,
* otherwise deadlock will be caused.
diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile
index b49d0898178b..318076f23213 100644
--- a/drivers/net/wireless/cnss2/Makefile
+++ b/drivers/net/wireless/cnss2/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_CNSS2) += cnss2.o
cnss2-y := main.o
+cnss2-y += bus.o
cnss2-y += debug.o
cnss2-y += pci.o
cnss2-y += power.o
diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c
new file mode 100644
index 000000000000..0d46b4f6b6a4
--- /dev/null
+++ b/drivers/net/wireless/cnss2/bus.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 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.
+ */
+
+#include "bus.h"
+#include "debug.h"
+#include "pci.h"
+
+enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
+{
+ if (!dev)
+ return CNSS_BUS_NONE;
+
+ if (!dev->bus)
+ return CNSS_BUS_NONE;
+
+ if (memcmp(dev->bus->name, "pci", 3) == 0)
+ return CNSS_BUS_PCI;
+ else
+ return CNSS_BUS_NONE;
+}
+
+enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
+{
+ switch (device_id) {
+ case QCA6174_DEVICE_ID:
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ return CNSS_BUS_PCI;
+ default:
+ cnss_pr_err("Unknown device_id: 0x%lx\n", device_id);
+ return CNSS_BUS_NONE;
+ }
+}
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev)
+{
+ if (!dev)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_get_pci_priv(to_pci_dev(dev));
+ default:
+ return NULL;
+ }
+}
+
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
+{
+ void *bus_priv;
+
+ if (!dev)
+ return cnss_get_plat_priv(NULL);
+
+ bus_priv = cnss_bus_dev_to_bus_priv(dev);
+ if (!bus_priv)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_priv_to_plat_priv(bus_priv);
+ default:
+ return NULL;
+ }
+}
+
+int cnss_bus_init(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_init(plat_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+void cnss_bus_deinit(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ cnss_pci_deinit(plat_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return;
+ }
+}
+
+int cnss_bus_load_m3(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_load_m3(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_get_wake_msi(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_force_fw_assert_hdlr(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+void cnss_bus_fw_boot_timeout_hdlr(unsigned long data)
+{
+ struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data;
+
+ if (!plat_priv)
+ return;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return;
+ }
+}
+
+void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv)
+{
+ int ret;
+
+ if (!plat_priv)
+ return;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
+ CNSS_MHI_RDDM);
+ if (ret) {
+ cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
+ break;
+ }
+ return cnss_pci_collect_dump_info(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return;
+ }
+}
+
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_probe(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_remove(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_powerup(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_shutdown(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_crash_shutdown(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_ramdump(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
+ int modem_current_status)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_modem_status(plat_priv->bus_priv,
+ modem_current_status);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_recovery_update_status(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h
new file mode 100644
index 000000000000..4e3d1500bd76
--- /dev/null
+++ b/drivers/net/wireless/cnss2/bus.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 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_BUS_H
+#define _CNSS_BUS_H
+
+#include "main.h"
+
+#define QCA6174_VENDOR_ID 0x168C
+#define QCA6174_DEVICE_ID 0x003E
+#define QCA6174_REV_ID_OFFSET 0x08
+#define QCA6174_REV3_VERSION 0x5020000
+#define QCA6174_REV3_2_VERSION 0x5030000
+#define QCA6290_VENDOR_ID 0x17CB
+#define QCA6290_DEVICE_ID 0x1100
+#define QCA6290_EMULATION_VENDOR_ID 0x168C
+#define QCA6290_EMULATION_DEVICE_ID 0xABCD
+
+enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
+enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id);
+void *cnss_bus_dev_to_bus_priv(struct device *dev);
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+int cnss_bus_init(struct cnss_plat_data *plat_priv);
+void cnss_bus_deinit(struct cnss_plat_data *plat_priv);
+int cnss_bus_load_m3(struct cnss_plat_data *plat_priv);
+int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv);
+u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv);
+int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv);
+void cnss_bus_fw_boot_timeout_hdlr(unsigned long data);
+void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data);
+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);
+#endif /* _CNSS_BUS_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 5183f3de7c9b..10bcad10bb20 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -23,8 +23,8 @@
#include <soc/qcom/subsystem_notif.h>
#include "main.h"
+#include "bus.h"
#include "debug.h"
-#include "pci.h"
#define CNSS_DUMP_FORMAT_VER 0x11
#define CNSS_DUMP_FORMAT_VER_V2 0x22
@@ -37,7 +37,6 @@
#define FW_READY_TIMEOUT 20000
#define FW_ASSERT_TIMEOUT 5000
#define CNSS_EVENT_PENDING 2989
-#define WAKE_MSI_NAME "WAKE"
static struct cnss_plat_data *plat_env;
@@ -55,13 +54,6 @@ module_param(enable_waltest, bool, 0600);
MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
#endif
-enum cnss_debug_quirks {
- LINK_DOWN_SELF_RECOVERY,
- SKIP_DEVICE_BOOT,
- USE_CORE_ONLY_FW,
- SKIP_RECOVERY,
-};
-
unsigned long quirks;
#ifdef CONFIG_CNSS2_DEBUG
module_param(quirks, ulong, 0600);
@@ -87,64 +79,17 @@ struct cnss_driver_event {
void *data;
};
-static enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
-{
- if (!dev)
- return CNSS_BUS_NONE;
-
- if (!dev->bus)
- return CNSS_BUS_NONE;
-
- if (memcmp(dev->bus->name, "pci", 3) == 0)
- return CNSS_BUS_PCI;
- else
- return CNSS_BUS_NONE;
-}
-
static void cnss_set_plat_priv(struct platform_device *plat_dev,
struct cnss_plat_data *plat_priv)
{
plat_env = plat_priv;
}
-static struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
- *plat_dev)
+struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
{
return plat_env;
}
-void *cnss_bus_dev_to_bus_priv(struct device *dev)
-{
- if (!dev)
- return NULL;
-
- switch (cnss_get_dev_bus_type(dev)) {
- case CNSS_BUS_PCI:
- return cnss_get_pci_priv(to_pci_dev(dev));
- default:
- return NULL;
- }
-}
-
-struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
-{
- void *bus_priv;
-
- if (!dev)
- return cnss_get_plat_priv(NULL);
-
- bus_priv = cnss_bus_dev_to_bus_priv(dev);
- if (!bus_priv)
- return NULL;
-
- switch (cnss_get_dev_bus_type(dev)) {
- case CNSS_BUS_PCI:
- return cnss_pci_priv_to_plat_priv(bus_priv);
- default:
- return NULL;
- }
-}
-
static int cnss_pm_notify(struct notifier_block *b,
unsigned long event, void *p)
{
@@ -274,23 +219,6 @@ int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap)
}
EXPORT_SYMBOL(cnss_get_platform_cap);
-int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
-{
- int ret = 0;
- struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
- void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
-
- if (!plat_priv)
- return -ENODEV;
-
- ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa);
- if (ret)
- return ret;
-
- return 0;
-}
-EXPORT_SYMBOL(cnss_get_soc_info);
-
void cnss_request_pm_qos(struct device *dev, u32 qos_val)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
@@ -506,22 +434,14 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
}
EXPORT_SYMBOL(cnss_set_fw_log_mode);
-u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv)
+unsigned long *cnss_get_debug_quirks(void)
{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- int ret, num_vectors;
- u32 user_base_data, base_vector;
-
- ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
- WAKE_MSI_NAME, &num_vectors,
- &user_base_data, &base_vector);
-
- if (ret) {
- cnss_pr_err("WAKE MSI is not valid\n");
- return 0;
- }
+ return &quirks;
+}
- return user_base_data;
+bool *cnss_get_qmi_bypass(void)
+{
+ return &qmi_bypass;
}
static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
@@ -541,7 +461,7 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
if (ret)
goto out;
- ret = cnss_pci_load_m3(plat_priv->bus_priv);
+ ret = cnss_bus_load_m3(plat_priv);
if (ret)
goto out;
@@ -554,79 +474,6 @@ out:
return ret;
}
-static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- cnss_pr_dbg("Skip driver probe\n");
- goto out;
- }
-
- if (!plat_priv->driver_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 = plat_priv->driver_ops->reinit(pci_priv->pci_dev,
- pci_priv->pci_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 = plat_priv->driver_ops->probe(pci_priv->pci_dev,
- pci_priv->pci_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;
-}
-
-static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_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 (!plat_priv->driver_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)) {
- plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
- } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- plat_priv->driver_ops->remove(pci_priv->pci_dev);
- clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
- }
-
- return 0;
-}
-
static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -650,7 +497,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
QMI_WLFW_CALIBRATION_V01);
} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
- ret = cnss_driver_call_probe(plat_priv);
+ ret = cnss_bus_call_driver_probe(plat_priv);
} else {
complete(&plat_priv->power_up_complete);
}
@@ -663,9 +510,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
return 0;
shutdown:
- cnss_pci_stop_mhi(plat_priv->bus_priv);
- cnss_suspend_pci_link(plat_priv->bus_priv);
- cnss_power_off_device(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
@@ -837,44 +682,6 @@ int cnss_power_down(struct device *dev)
}
EXPORT_SYMBOL(cnss_power_down);
-int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
-{
- int ret = 0;
- struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
-
- if (!plat_priv) {
- cnss_pr_err("plat_priv is NULL!\n");
- return -ENODEV;
- }
-
- if (plat_priv->driver_ops) {
- cnss_pr_err("Driver has already registered!\n");
- return -EEXIST;
- }
-
- ret = cnss_driver_event_post(plat_priv,
- CNSS_DRIVER_EVENT_REGISTER_DRIVER,
- CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
- driver_ops);
- return ret;
-}
-EXPORT_SYMBOL(cnss_wlan_register_driver);
-
-void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
-{
- struct cnss_plat_data *plat_priv = cnss_get_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_wlan_unregister_driver);
-
static int cnss_get_resources(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -906,13 +713,11 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
{
struct cnss_plat_data *plat_priv =
container_of(nb, struct cnss_plat_data, modem_nb);
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_esoc_info *esoc_info;
- struct cnss_wlan_driver *driver_ops;
cnss_pr_dbg("Modem notifier: event %lu\n", code);
- if (!pci_priv)
+ if (!plat_priv)
return NOTIFY_DONE;
esoc_info = &plat_priv->esoc_info;
@@ -924,13 +729,10 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
else
return NOTIFY_DONE;
- driver_ops = plat_priv->driver_ops;
- if (!driver_ops || !driver_ops->modem_status)
+ if (!cnss_bus_call_driver_modem_status(plat_priv,
+ esoc_info->modem_current_status))
return NOTIFY_DONE;
- driver_ops->modem_status(pci_priv->pci_dev,
- esoc_info->modem_current_status);
-
return NOTIFY_OK;
}
@@ -1004,246 +806,6 @@ static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
}
-static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv) {
- cnss_pr_err("pci_priv is NULL!\n");
- return -ENODEV;
- }
-
- ret = cnss_power_on_device(plat_priv);
- if (ret) {
- cnss_pr_err("Failed to power on device, err = %d\n", ret);
- goto out;
- }
-
- ret = cnss_resume_pci_link(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
- goto power_off;
- }
-
- ret = cnss_driver_call_probe(plat_priv);
- if (ret)
- goto suspend_link;
-
- return 0;
-suspend_link:
- cnss_suspend_pci_link(pci_priv);
-power_off:
- cnss_power_off_device(plat_priv);
-out:
- return ret;
-}
-
-static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv)
- return -ENODEV;
-
- cnss_pm_request_resume(pci_priv);
-
- cnss_driver_call_remove(plat_priv);
-
- cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
- CNSS_BUS_WIDTH_NONE);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
-
- ret = cnss_suspend_pci_link(pci_priv);
- if (ret)
- cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
-
- cnss_power_off_device(plat_priv);
-
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
-
- return ret;
-}
-
-static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!plat_priv->driver_ops)
- return;
-
- plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
-}
-
-static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- unsigned int timeout;
-
- if (!pci_priv) {
- cnss_pr_err("pci_priv is NULL!\n");
- return -ENODEV;
- }
-
- if (plat_priv->ramdump_info_v2.dump_data_valid ||
- test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
- cnss_pci_clear_dump_info(pci_priv);
- }
-
- ret = cnss_power_on_device(plat_priv);
- if (ret) {
- cnss_pr_err("Failed to power on device, err = %d\n", ret);
- goto out;
- }
-
- ret = cnss_resume_pci_link(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
- goto power_off;
- }
-
- timeout = cnss_get_qmi_timeout();
-
- ret = cnss_pci_start_mhi(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to start MHI, err = %d\n", ret);
- if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
- !pci_priv->pci_link_down_ind && timeout)
- mod_timer(&plat_priv->fw_boot_timer,
- jiffies + msecs_to_jiffies(timeout >> 1));
- return 0;
- }
-
- if (test_bit(USE_CORE_ONLY_FW, &quirks)) {
- clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- return 0;
- }
-
- cnss_set_pin_connect_status(plat_priv);
-
- if (qmi_bypass) {
- ret = cnss_driver_call_probe(plat_priv);
- if (ret)
- goto stop_mhi;
- } else if (timeout) {
- mod_timer(&plat_priv->fw_boot_timer,
- jiffies + msecs_to_jiffies(timeout << 1));
- }
-
- return 0;
-
-stop_mhi:
- cnss_pci_stop_mhi(pci_priv);
- cnss_suspend_pci_link(pci_priv);
-power_off:
- cnss_power_off_device(plat_priv);
-out:
- return ret;
-}
-
-static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv)
- return -ENODEV;
-
- cnss_pm_request_resume(pci_priv);
-
- cnss_driver_call_remove(plat_priv);
-
- cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
- CNSS_BUS_WIDTH_NONE);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
-
- cnss_pci_stop_mhi(pci_priv);
-
- ret = cnss_suspend_pci_link(pci_priv);
- if (ret)
- cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
-
- cnss_power_off_device(plat_priv);
-
- clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
- clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
-
- return ret;
-}
-
-static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- int ret = 0;
-
- cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
- plat_priv->driver_state);
-
- if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
- test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
- test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- cnss_pr_dbg("Ignore crash shutdown\n");
- return;
- }
-
- ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
- if (ret) {
- cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
- return;
- }
-
- cnss_pci_collect_dump_info(pci_priv);
-}
-
-static int cnss_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret;
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_powerup(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_powerup(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
-}
-
-static int cnss_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret;
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_shutdown(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_shutdown(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
-}
-
static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
{
struct cnss_plat_data *plat_priv;
@@ -1264,7 +826,7 @@ static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
return 0;
}
- return cnss_powerup(plat_priv);
+ return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
@@ -1288,68 +850,12 @@ static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
return 0;
}
- return cnss_shutdown(plat_priv);
-}
-
-static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv)
-{
- struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
- struct cnss_dump_data *dump_data = &info_v2->dump_data;
- struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
- struct ramdump_segment *ramdump_segs, *s;
- int i, ret = 0;
-
- if (!info_v2->dump_data_valid ||
- dump_data->nentries == 0)
- return 0;
-
- ramdump_segs = kcalloc(dump_data->nentries,
- sizeof(*ramdump_segs),
- GFP_KERNEL);
- if (!ramdump_segs)
- return -ENOMEM;
-
- s = ramdump_segs;
- for (i = 0; i < dump_data->nentries; i++) {
- s->address = dump_seg->address;
- s->v_address = dump_seg->v_address;
- s->size = dump_seg->size;
- s++;
- dump_seg++;
- }
-
- ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
- dump_data->nentries);
- kfree(ramdump_segs);
-
- cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
- cnss_pci_clear_dump_info(plat_priv->bus_priv);
-
- return ret;
-}
-
-static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_ramdump_info *ramdump_info;
- struct ramdump_segment segment;
-
- ramdump_info = &plat_priv->ramdump_info;
- if (!ramdump_info->ramdump_size)
- return -EINVAL;
-
- memset(&segment, 0, sizeof(segment));
- segment.v_address = ramdump_info->ramdump_va;
- segment.size = ramdump_info->ramdump_size;
- ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
-
- return ret;
+ return cnss_bus_dev_shutdown(plat_priv);
}
static int cnss_subsys_ramdump(int enable,
const struct subsys_desc *subsys_desc)
{
- int ret = 0;
struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
if (!plat_priv) {
@@ -1360,21 +866,7 @@ static int cnss_subsys_ramdump(int enable,
if (!enable)
return 0;
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_ramdump(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_ramdump(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
+ return cnss_bus_dev_ramdump(plat_priv);
}
void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
@@ -1417,19 +909,7 @@ static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
cnss_pr_err("plat_priv is NULL!\n");
return;
}
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- cnss_qca6174_crash_shutdown(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- cnss_qca6290_crash_shutdown(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- }
+ cnss_bus_dev_crash_shutdown(plat_priv);
}
static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
@@ -1451,20 +931,15 @@ static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
enum cnss_recovery_reason reason)
{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_subsys_info *subsys_info =
&plat_priv->subsys_info;
- int ret = 0;
plat_priv->recovery_count++;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
goto self_recovery;
- if (plat_priv->driver_ops &&
- test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
- plat_priv->driver_ops->update_status(pci_priv->pci_dev,
- CNSS_RECOVERY);
+ cnss_bus_recovery_update_status(plat_priv);
if (test_bit(SKIP_RECOVERY, &quirks)) {
cnss_pr_dbg("Skip device recovery\n");
@@ -1478,12 +953,7 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
break;
case CNSS_REASON_RDDM:
clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
- ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM);
- if (ret) {
- cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
- break;
- }
- cnss_pci_collect_dump_info(pci_priv);
+ cnss_bus_collect_dump_info(plat_priv);
break;
case CNSS_REASON_DEFAULT:
case CNSS_REASON_TIMEOUT:
@@ -1503,8 +973,8 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
return 0;
self_recovery:
- cnss_shutdown(plat_priv);
- cnss_powerup(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
+ cnss_bus_dev_powerup(plat_priv);
return 0;
}
@@ -1590,28 +1060,6 @@ void cnss_schedule_recovery(struct device *dev,
}
EXPORT_SYMBOL(cnss_schedule_recovery);
-static int cnss_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- int ret;
-
- ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
- CNSS_MHI_TRIGGER_RDDM);
- if (ret) {
- cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret);
- cnss_schedule_recovery(&pci_priv->pci_dev->dev,
- CNSS_REASON_DEFAULT);
- return 0;
- }
-
- if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
- mod_timer(&plat_priv->fw_boot_timer,
- jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT));
- }
-
- return 0;
-}
-
int cnss_force_fw_assert(struct device *dev)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
@@ -1639,49 +1087,12 @@ int cnss_force_fw_assert(struct device *dev)
}
EXPORT_SYMBOL(cnss_force_fw_assert);
-void fw_boot_timeout(unsigned long data)
-{
- struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- cnss_pr_err("Timeout waiting for FW ready indication!\n");
-
- cnss_schedule_recovery(&pci_priv->pci_dev->dev,
- CNSS_REASON_TIMEOUT);
-}
-
-static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv,
- void *data)
-{
- int ret = 0;
-
- set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
- plat_priv->driver_ops = data;
-
- ret = cnss_powerup(plat_priv);
- if (ret) {
- clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
- plat_priv->driver_ops = NULL;
- }
-
- return ret;
-}
-
-static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
-{
- set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
- cnss_shutdown(plat_priv);
- plat_priv->driver_ops = NULL;
-
- return 0;
-}
-
static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
- ret = cnss_powerup(plat_priv);
+ ret = cnss_bus_dev_powerup(plat_priv);
if (ret)
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
@@ -1692,7 +1103,7 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
{
plat_priv->cal_done = true;
cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
- cnss_shutdown(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
return 0;
@@ -1700,12 +1111,12 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
{
- return cnss_powerup(plat_priv);
+ return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
{
- cnss_shutdown(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
return 0;
}
@@ -1746,7 +1157,7 @@ static void cnss_driver_event_work(struct work_struct *work)
ret = cnss_wlfw_server_exit(plat_priv);
break;
case CNSS_DRIVER_EVENT_REQUEST_MEM:
- ret = cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
+ ret = cnss_bus_alloc_fw_mem(plat_priv);
if (ret)
break;
ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
@@ -1764,18 +1175,18 @@ static void cnss_driver_event_work(struct work_struct *work)
ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
- ret = cnss_register_driver_hdlr(plat_priv,
- event->data);
+ ret = cnss_bus_register_driver_hdlr(plat_priv,
+ event->data);
break;
case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
- ret = cnss_unregister_driver_hdlr(plat_priv);
+ ret = cnss_bus_unregister_driver_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_RECOVERY:
ret = cnss_driver_recovery_hdlr(plat_priv,
event->data);
break;
case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
- ret = cnss_force_fw_assert_hdlr(plat_priv);
+ ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_POWER_UP:
ret = cnss_power_up_hdlr(plat_priv);
@@ -2232,6 +1643,7 @@ static int cnss_probe(struct platform_device *plat_dev)
plat_priv->plat_dev = plat_dev;
plat_priv->device_id = device_id->driver_data;
+ plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
cnss_set_plat_priv(plat_dev, plat_priv);
platform_set_drvdata(plat_dev, plat_priv);
@@ -2244,14 +1656,14 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto free_res;
- ret = cnss_pci_init(plat_priv);
+ ret = cnss_bus_init(plat_priv);
if (ret)
goto power_off;
}
ret = cnss_register_esoc(plat_priv);
if (ret)
- goto deinit_pci;
+ goto deinit_bus;
ret = cnss_register_bus_scale(plat_priv);
if (ret)
@@ -2274,7 +1686,7 @@ static int cnss_probe(struct platform_device *plat_dev)
goto deinit_qmi;
setup_timer(&plat_priv->fw_boot_timer,
- fw_boot_timeout, (unsigned long)plat_priv);
+ cnss_bus_fw_boot_timeout_hdlr, (unsigned long)plat_priv);
register_pm_notifier(&cnss_pm_notifier);
@@ -2300,9 +1712,9 @@ unreg_bus_scale:
cnss_unregister_bus_scale(plat_priv);
unreg_esoc:
cnss_unregister_esoc(plat_priv);
-deinit_pci:
+deinit_bus:
if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
- cnss_pci_deinit(plat_priv);
+ cnss_bus_deinit(plat_priv);
power_off:
if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
cnss_power_off_device(plat_priv);
@@ -2329,7 +1741,7 @@ static int cnss_remove(struct platform_device *plat_dev)
cnss_remove_sysfs(plat_priv);
cnss_unregister_bus_scale(plat_priv);
cnss_unregister_esoc(plat_priv);
- cnss_pci_deinit(plat_priv);
+ cnss_bus_deinit(plat_priv);
cnss_put_resources(plat_priv);
platform_set_drvdata(plat_dev, NULL);
plat_env = NULL;
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index a36281cb560f..9dc64e016d82 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -164,9 +164,17 @@ struct cnss_pin_connect_result {
u32 host_pin_result;
};
+enum cnss_debug_quirks {
+ LINK_DOWN_SELF_RECOVERY,
+ SKIP_DEVICE_BOOT,
+ USE_CORE_ONLY_FW,
+ SKIP_RECOVERY,
+};
+
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
+ enum cnss_dev_bus_type bus_type;
struct cnss_vreg_info *vreg_info;
struct cnss_pinctrl_info pinctrl_info;
struct cnss_subsys_info subsys_info;
@@ -178,7 +186,6 @@ struct cnss_plat_data {
struct cnss_platform_cap cap;
struct pm_qos_request qos_request;
unsigned long device_id;
- struct cnss_wlan_driver *driver_ops;
enum cnss_driver_status driver_status;
u32 recovery_count;
unsigned long driver_state;
@@ -209,8 +216,8 @@ struct cnss_plat_data {
bool cal_done;
};
-void *cnss_bus_dev_to_bus_priv(struct device *dev);
-struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
+unsigned long *cnss_get_debug_quirks(void);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
u32 flags, void *data);
@@ -237,5 +244,5 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
-
+bool *cnss_get_qmi_bypass(void);
#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 2356caa3af78..ff053b098c22 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -16,8 +16,11 @@
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/memblock.h>
+#include <soc/qcom/ramdump.h>
#include "main.h"
+#include "bus.h"
#include "debug.h"
#include "pci.h"
@@ -40,10 +43,15 @@
#endif
#define MHI_NODE_NAME "qcom,mhi"
+#define MHI_MSI_NAME "MHI"
#define MAX_M3_FILE_NAME_LENGTH 13
#define DEFAULT_M3_FILE_NAME "m3.bin"
+#define WAKE_MSI_NAME "WAKE"
+
+#define FW_ASSERT_TIMEOUT 5000
+
#ifdef CONFIG_PCI_MSM
static DEFINE_SPINLOCK(pci_link_down_lock);
#endif
@@ -178,7 +186,6 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
goto out;
}
-
pci_set_master(pci_priv->pci_dev);
if (pci_priv->pci_link_down_ind)
@@ -228,6 +235,532 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
}
#endif /* CONFIG_PCI_MSM */
+int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+
+ plat_priv = pci_priv->plat_priv;
+
+ if (pci_priv->driver_ops &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
+ pci_priv->driver_ops->update_status(pci_priv->pci_dev,
+ CNSS_RECOVERY);
+ return 0;
+}
+
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ plat_priv = pci_priv->plat_priv;
+
+ if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ cnss_pr_dbg("Skip driver probe\n");
+ goto out;
+ }
+
+ if (!pci_priv->driver_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 = pci_priv->driver_ops->reinit(pci_priv->pci_dev,
+ pci_priv->pci_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 = pci_priv->driver_ops->probe(pci_priv->pci_dev,
+ pci_priv->pci_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_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ plat_priv = pci_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 (!pci_priv->driver_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)) {
+ pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ pci_priv->driver_ops->remove(pci_priv->pci_dev);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+}
+
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+ int modem_current_status)
+{
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ driver_ops = pci_priv->driver_ops;
+ if (!driver_ops || !driver_ops->modem_status)
+ return -EINVAL;
+
+ driver_ops->modem_status(pci_priv->pci_dev, modem_current_status);
+
+ return 0;
+}
+
+static int cnss_qca6174_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ ret = cnss_pci_call_driver_probe(pci_priv);
+ if (ret)
+ goto suspend_link;
+
+ return 0;
+suspend_link:
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6174_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_pci_call_driver_remove(pci_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+ cnss_power_off_device(plat_priv);
+
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6174_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ if (pci_priv->driver_ops && pci_priv->driver_ops->crash_shutdown)
+ pci_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
+}
+
+static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_ramdump_info *ramdump_info;
+ struct ramdump_segment segment;
+
+ ramdump_info = &plat_priv->ramdump_info;
+ if (!ramdump_info->ramdump_size)
+ return -EINVAL;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = ramdump_info->ramdump_va;
+ segment.size = ramdump_info->ramdump_size;
+ ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
+
+ return ret;
+}
+
+static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ unsigned int timeout;
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(pci_priv);
+ }
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ timeout = cnss_get_qmi_timeout();
+
+ ret = cnss_pci_start_mhi(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to start MHI, err = %d\n", ret);
+ if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+ !pci_priv->pci_link_down_ind && timeout)
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout >> 1));
+ return 0;
+ }
+
+ if (test_bit(USE_CORE_ONLY_FW, cnss_get_debug_quirks())) {
+ clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ return 0;
+ }
+
+ cnss_set_pin_connect_status(plat_priv);
+
+ if (*cnss_get_qmi_bypass()) {
+ ret = cnss_pci_call_driver_probe(pci_priv);
+ if (ret)
+ goto stop_mhi;
+ } else if (timeout) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout << 1));
+ }
+
+ return 0;
+
+stop_mhi:
+ cnss_pci_stop_mhi(pci_priv);
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_pci_call_driver_remove(pci_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ cnss_pci_stop_mhi(pci_priv);
+
+ ret = cnss_suspend_pci_link(pci_priv);
+ if (ret)
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+ cnss_power_off_device(plat_priv);
+
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6290_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ int ret = 0;
+
+ cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Ignore crash shutdown\n");
+ return;
+ }
+
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
+ if (ret) {
+ cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
+ return;
+ }
+
+ cnss_pci_collect_dump_info(pci_priv);
+}
+
+static int cnss_qca6290_ramdump(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+ struct cnss_dump_data *dump_data = &info_v2->dump_data;
+ struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+ struct ramdump_segment *ramdump_segs, *s;
+ int i, ret = 0;
+
+ if (!info_v2->dump_data_valid ||
+ dump_data->nentries == 0)
+ return 0;
+
+ ramdump_segs = kcalloc(dump_data->nentries,
+ sizeof(*ramdump_segs),
+ GFP_KERNEL);
+ if (!ramdump_segs)
+ return -ENOMEM;
+
+ s = ramdump_segs;
+ for (i = 0; i < dump_data->nentries; i++) {
+ s->address = dump_seg->address;
+ s->v_address = dump_seg->v_address;
+ s->size = dump_seg->size;
+ s++;
+ dump_seg++;
+ }
+
+ ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
+ dump_data->nentries);
+ kfree(ramdump_segs);
+
+ cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(plat_priv->bus_priv);
+
+ return ret;
+}
+
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_powerup(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_powerup(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_shutdown(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_shutdown(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ cnss_qca6174_crash_shutdown(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ cnss_qca6290_crash_shutdown(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_ramdump(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_ramdump(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+ struct cnss_pci_data *pci_priv;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ pci_priv = plat_priv->bus_priv;
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (pci_priv->driver_ops) {
+ cnss_pr_err("Driver has already registered\n");
+ return -EEXIST;
+ }
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
+ return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_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_wlan_unregister_driver);
+
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv,
+ void *data)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ pci_priv->driver_ops = data;
+
+ ret = cnss_pci_dev_powerup(pci_priv);
+ if (ret) {
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ pci_priv->driver_ops = NULL;
+ }
+
+ return ret;
+}
+
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+ cnss_pci_dev_shutdown(pci_priv);
+ pci_priv->driver_ops = NULL;
+
+ return 0;
+}
+
static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
{
int ret = 0;
@@ -381,7 +914,7 @@ static int cnss_pci_suspend(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend) {
ret = driver_ops->suspend(pci_dev, state);
if (ret) {
@@ -453,7 +986,7 @@ static int cnss_pci_resume(struct device *dev)
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
}
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume) {
ret = driver_ops->resume(pci_dev);
if (ret)
@@ -482,7 +1015,7 @@ static int cnss_pci_suspend_noirq(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend_noirq)
ret = driver_ops->suspend_noirq(pci_dev);
@@ -505,7 +1038,7 @@ static int cnss_pci_resume_noirq(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume_noirq &&
!pci_priv->pci_link_down_ind)
ret = driver_ops->resume_noirq(pci_dev);
@@ -536,7 +1069,7 @@ static int cnss_pci_runtime_suspend(struct device *dev)
cnss_pr_dbg("Runtime suspend start\n");
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_suspend)
ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
@@ -568,7 +1101,7 @@ static int cnss_pci_runtime_resume(struct device *dev)
cnss_pr_dbg("Runtime resume start\n");
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_resume)
ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
@@ -841,6 +1374,63 @@ static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv)
m3_mem->size = 0;
}
+int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+ int ret;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ plat_priv = pci_priv->plat_priv;
+ if (!plat_priv)
+ return -ENODEV;
+
+ ret = cnss_pci_set_mhi_state(pci_priv,
+ CNSS_MHI_TRIGGER_RDDM);
+ if (ret) {
+ cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret);
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+ CNSS_REASON_DEFAULT);
+ return 0;
+ }
+
+ if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT));
+ }
+
+ return 0;
+}
+
+void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv)
+{
+ if (!pci_priv)
+ return;
+
+ cnss_pr_err("Timeout waiting for FW ready indication\n");
+
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+ CNSS_REASON_TIMEOUT);
+}
+
+int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
+
+ if (!plat_priv)
+ return -ENODEV;
+
+ ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_get_soc_info);
+
int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
phys_addr_t *pa)
{
@@ -991,6 +1581,29 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
}
EXPORT_SYMBOL(cnss_get_msi_address);
+static char *get_wake_msi_name(void)
+{
+ return (char *)WAKE_MSI_NAME;
+}
+
+u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv)
+{
+ int ret, num_vectors;
+ u32 user_base_data, base_vector;
+ char *wake_msi_name = get_wake_msi_name();
+
+ ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+ wake_msi_name, &num_vectors,
+ &user_base_data, &base_vector);
+
+ if (ret) {
+ cnss_pr_err("WAKE MSI is not valid\n");
+ return 0;
+ }
+
+ return user_base_data;
+}
+
#ifdef CONFIG_PCI_MSM
static inline int cnss_pci_set_dma_mask(struct pci_dev *pci_dev)
{
@@ -1206,8 +1819,8 @@ static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv)
cnss_pr_dbg("MHI status cb is called with reason %d\n", reason);
- if (plat_priv->driver_ops && plat_priv->driver_ops->update_status)
- plat_priv->driver_ops->update_status(pci_priv->pci_dev,
+ if (pci_priv->driver_ops && pci_priv->driver_ops->update_status)
+ pci_priv->driver_ops->update_status(pci_priv->pci_dev,
CNSS_FW_DOWN);
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h
index a00ca61972f0..182355ae7577 100644
--- a/drivers/net/wireless/cnss2/pci.h
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -62,6 +62,7 @@ struct cnss_pci_data {
const struct pci_device_id *pci_device_id;
u32 device_id;
u16 revision_id;
+ struct cnss_wlan_driver *driver_ops;
bool pci_link_state;
bool pci_link_down_ind;
struct pci_saved_state *saved_state;
@@ -152,5 +153,18 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv);
void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv);
void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv);
int cnss_pm_request_resume(struct cnss_pci_data *pci_priv);
-
+u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv);
+int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv);
+void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv);
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, void *data);
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+ int modem_current_status);
+int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv);
#endif /* _CNSS_PCI_H */
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index b8777c18d252..669816c84e37 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -15,8 +15,9 @@
#include <linux/qmi_encdec.h>
#include <soc/qcom/msm_qmi_interface.h>
-#include "main.h"
+#include "bus.h"
#include "debug.h"
+#include "main.h"
#include "qmi.h"
#define WLFW_SERVICE_INS_ID_V01 1
@@ -163,7 +164,7 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
req.num_clients = daemon_support ? 2 : 1;
cnss_pr_dbg("Number of clients is %d\n", req.num_clients);
- req.wake_msi = cnss_get_wake_msi(plat_priv);
+ req.wake_msi = cnss_bus_get_wake_irq(plat_priv);
if (req.wake_msi) {
cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi);
req.wake_msi_valid = 1;
@@ -514,17 +515,17 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
BDF_FILE_NAME_PREFIX "%02x",
plat_priv->board_info.board_id);
+ if (bdf_bypass) {
+ cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n");
+ temp = filename;
+ remaining = MAX_BDF_FILE_NAME;
+ goto bypass_bdf;
+ }
+
ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev);
if (ret) {
cnss_pr_err("Failed to load BDF: %s\n", filename);
- if (bdf_bypass) {
- cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n");
- temp = filename;
- remaining = MAX_BDF_FILE_NAME;
- goto bypass_bdf;
- } else {
- goto err_req_fw;
- }
+ goto err_req_fw;
}
temp = fw_entry->data;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index b510bbd7d6c7..ad7d2d6175bd 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -3883,7 +3883,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
if (ipa_ctx->logbuf == NULL)
- IPAERR("failed to create IPC log, continue...\n");
+ IPADBG("failed to create IPC log, continue...\n");
ipa_ctx->pdev = ipa_dev;
ipa_ctx->uc_pdev = ipa_dev;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index 1a704ffab07a..e17526e46323 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -1901,7 +1901,7 @@ static ssize_t ipa_enable_ipc_low(struct file *file,
ipc_log_context_create(IPA_IPC_LOG_PAGES,
"ipa_low", 0);
if (ipa_ipc_low_buff == NULL)
- IPAERR("failed to get logbuf_low\n");
+ IPADBG("failed to get logbuf_low\n");
}
ipa_ctx->logbuf_low = ipa_ipc_low_buff;
} else {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index a869b6419e5e..681b2d945945 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -4549,7 +4549,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
if (ipa3_ctx->logbuf == NULL)
- IPAERR("failed to create IPC log, continue...\n");
+ IPADBG("failed to create IPC log, continue...\n");
ipa3_ctx->pdev = ipa_dev;
ipa3_ctx->uc_pdev = ipa_dev;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index eb9a6877c39f..0dd5b8165ac1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -1872,7 +1872,7 @@ static ssize_t ipa3_enable_ipc_low(struct file *file,
"ipa_low", 0);
}
if (ipa_ipc_low_buff == NULL)
- IPAERR("failed to get logbuf_low\n");
+ IPADBG("failed to get logbuf_low\n");
ipa3_ctx->logbuf_low = ipa_ipc_low_buff;
} else {
ipa3_ctx->logbuf_low = NULL;
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 8b501f9d08c6..6e307b5dce81 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -2722,7 +2722,7 @@ static void ufs_qcom_print_utp_hci_testbus(struct ufs_hba *hba)
return;
host->testbus.select_major = TSTBUS_UTP_HCI;
- for (i = 0; i <= nminor; i++) {
+ for (i = 0; i < nminor; i++) {
host->testbus.select_minor = i;
ufs_qcom_testbus_config(host);
testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c
index 74ee88a037af..e9e42554cbe2 100644
--- a/drivers/soc/qcom/hab/hab_mem_linux.c
+++ b/drivers/soc/qcom/hab/hab_mem_linux.c
@@ -361,18 +361,19 @@ static int hab_map_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct page *page;
struct pages_list *pglist;
-
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-
- /* PHY address */
- unsigned long fault_offset =
- (unsigned long)vmf->virtual_address - vma->vm_start + offset;
- unsigned long fault_index = fault_offset>>PAGE_SHIFT;
+ unsigned long offset, fault_offset, fault_index;
int page_idx;
if (vma == NULL)
return VM_FAULT_SIGBUS;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* PHY address */
+ fault_offset =
+ (unsigned long)vmf->virtual_address - vma->vm_start + offset;
+ fault_index = fault_offset>>PAGE_SHIFT;
+
pglist = vma->vm_private_data;
page_idx = fault_index - pglist->index;
@@ -463,6 +464,7 @@ static int habmem_imp_hyp_map_fd(void *imp_ctx,
int i, j, k = 0;
pgprot_t prot = PAGE_KERNEL;
int32_t fd, size;
+ int ret;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
if (!pfn_table || !priv)
@@ -505,9 +507,10 @@ static int habmem_imp_hyp_map_fd(void *imp_ctx,
exp_info.priv = pglist;
pglist->dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(pglist->dmabuf)) {
+ ret = PTR_ERR(pglist->dmabuf);
kfree(pages);
kfree(pglist);
- return PTR_ERR(pglist->dmabuf);
+ return ret;
}
fd = dma_buf_fd(pglist->dmabuf, O_CLOEXEC);
@@ -579,8 +582,8 @@ static int habmem_imp_hyp_map_kva(void *imp_ctx,
pglist->kva = vmap(pglist->pages, pglist->npages, VM_MAP, prot);
if (pglist->kva == NULL) {
kfree(pages);
- kfree(pglist);
pr_err("%ld pages vmap failed\n", pglist->npages);
+ kfree(pglist);
return -ENOMEM;
}
diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c
index 86d763f65657..3e9046381b12 100644
--- a/drivers/soc/qcom/hab/hab_mimex.c
+++ b/drivers/soc/qcom/hab/hab_mimex.c
@@ -124,8 +124,7 @@ void habmem_remove_export(struct export_desc *exp)
struct uhab_context *ctx;
if (!exp || !exp->ctx || !exp->pchan) {
- pr_err("failed to find valid info in exp %pK ctx %pK pchan %pK\n",
- exp, exp->ctx, exp->pchan);
+ pr_err("failed to find valid info in exp %pK\n", exp);
return;
}
@@ -240,7 +239,7 @@ int hab_mem_export(struct uhab_context *ctx,
int page_count;
int compressed = 0;
- if (!ctx || !param)
+ if (!ctx || !param || !param->buffer)
return -EINVAL;
vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 29adabdb305f..7855b3e9a97f 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -12,6 +12,7 @@
#include <linux/nls.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
+#include <linux/usb/cdc.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h> /* for usbcore internals */
#include <asm/byteorder.h>
@@ -2031,3 +2032,159 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
+
+/**
+ * cdc_parse_cdc_header - parse the extra headers present in CDC devices
+ * @hdr: the place to put the results of the parsing
+ * @intf: the interface for which parsing is requested
+ * @buffer: pointer to the extra headers to be parsed
+ * @buflen: length of the extra headers
+ *
+ * This evaluates the extra headers present in CDC devices which
+ * bind the interfaces for data and control and provide details
+ * about the capabilities of the device.
+ *
+ * Return: number of descriptors parsed or -EINVAL
+ * if the header is contradictory beyond salvage
+ */
+
+int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
+ struct usb_interface *intf,
+ u8 *buffer,
+ int buflen)
+{
+ /* duplicates are ignored */
+ struct usb_cdc_union_desc *union_header = NULL;
+
+ /* duplicates are not tolerated */
+ struct usb_cdc_header_desc *header = NULL;
+ struct usb_cdc_ether_desc *ether = NULL;
+ struct usb_cdc_mdlm_detail_desc *detail = NULL;
+ struct usb_cdc_mdlm_desc *desc = NULL;
+
+ unsigned int elength;
+ int cnt = 0;
+
+ memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
+ hdr->phonet_magic_present = false;
+ while (buflen > 0) {
+ elength = buffer[0];
+ if (!elength) {
+ dev_err(&intf->dev, "skipping garbage byte\n");
+ elength = 1;
+ goto next_desc;
+ }
+ if ((buflen < elength) || (elength < 3)) {
+ dev_err(&intf->dev, "invalid descriptor buffer length\n");
+ break;
+ }
+ if (buffer[1] != USB_DT_CS_INTERFACE) {
+ dev_err(&intf->dev, "skipping garbage\n");
+ goto next_desc;
+ }
+
+ switch (buffer[2]) {
+ case USB_CDC_UNION_TYPE: /* we've found it */
+ if (elength < sizeof(struct usb_cdc_union_desc))
+ goto next_desc;
+ if (union_header) {
+ dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
+ goto next_desc;
+ }
+ union_header = (struct usb_cdc_union_desc *)buffer;
+ break;
+ case USB_CDC_COUNTRY_TYPE:
+ if (elength < sizeof(struct usb_cdc_country_functional_desc))
+ goto next_desc;
+ hdr->usb_cdc_country_functional_desc =
+ (struct usb_cdc_country_functional_desc *)buffer;
+ break;
+ case USB_CDC_HEADER_TYPE:
+ if (elength != sizeof(struct usb_cdc_header_desc))
+ goto next_desc;
+ if (header)
+ return -EINVAL;
+ header = (struct usb_cdc_header_desc *)buffer;
+ break;
+ case USB_CDC_ACM_TYPE:
+ if (elength < sizeof(struct usb_cdc_acm_descriptor))
+ goto next_desc;
+ hdr->usb_cdc_acm_descriptor =
+ (struct usb_cdc_acm_descriptor *)buffer;
+ break;
+ case USB_CDC_ETHERNET_TYPE:
+ if (elength != sizeof(struct usb_cdc_ether_desc))
+ goto next_desc;
+ if (ether)
+ return -EINVAL;
+ ether = (struct usb_cdc_ether_desc *)buffer;
+ break;
+ case USB_CDC_CALL_MANAGEMENT_TYPE:
+ if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
+ goto next_desc;
+ hdr->usb_cdc_call_mgmt_descriptor =
+ (struct usb_cdc_call_mgmt_descriptor *)buffer;
+ break;
+ case USB_CDC_DMM_TYPE:
+ if (elength < sizeof(struct usb_cdc_dmm_desc))
+ goto next_desc;
+ hdr->usb_cdc_dmm_desc =
+ (struct usb_cdc_dmm_desc *)buffer;
+ break;
+ case USB_CDC_MDLM_TYPE:
+ if (elength < sizeof(struct usb_cdc_mdlm_desc *))
+ goto next_desc;
+ if (desc)
+ return -EINVAL;
+ desc = (struct usb_cdc_mdlm_desc *)buffer;
+ break;
+ case USB_CDC_MDLM_DETAIL_TYPE:
+ if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
+ goto next_desc;
+ if (detail)
+ return -EINVAL;
+ detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
+ break;
+ case USB_CDC_NCM_TYPE:
+ if (elength < sizeof(struct usb_cdc_ncm_desc))
+ goto next_desc;
+ hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
+ break;
+ case USB_CDC_MBIM_TYPE:
+ if (elength < sizeof(struct usb_cdc_mbim_desc))
+ goto next_desc;
+
+ hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
+ break;
+ case USB_CDC_MBIM_EXTENDED_TYPE:
+ if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
+ break;
+ hdr->usb_cdc_mbim_extended_desc =
+ (struct usb_cdc_mbim_extended_desc *)buffer;
+ break;
+ case CDC_PHONET_MAGIC_NUMBER:
+ hdr->phonet_magic_present = true;
+ break;
+ default:
+ /*
+ * there are LOTS more CDC descriptors that
+ * could legitimately be found here.
+ */
+ dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
+ buffer[2], elength);
+ goto next_desc;
+ }
+ cnt++;
+next_desc:
+ buflen -= elength;
+ buffer += elength;
+ }
+ hdr->usb_cdc_union_desc = union_header;
+ hdr->usb_cdc_header_desc = header;
+ hdr->usb_cdc_mdlm_detail_desc = detail;
+ hdr->usb_cdc_mdlm_desc = desc;
+ hdr->usb_cdc_ether_desc = ether;
+ return cnt;
+}
+
+EXPORT_SYMBOL(cdc_parse_cdc_header);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f94d0ba2f966..de6bb295bf67 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -46,6 +46,7 @@
#include <linux/irq.h>
#include <linux/extcon.h>
#include <linux/reset.h>
+#include <soc/qcom/boot_stats.h>
#include "power.h"
#include "core.h"
@@ -2162,10 +2163,12 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
* case of host bus suspend and device bus suspend.
*/
if (mdwc->vbus_active || mdwc->in_host_mode) {
- enable_irq_wake(mdwc->hs_phy_irq);
+ if (!mdwc->no_wakeup_src_in_hostmode)
+ enable_irq_wake(mdwc->hs_phy_irq);
enable_irq(mdwc->hs_phy_irq);
if (mdwc->ss_phy_irq) {
- enable_irq_wake(mdwc->ss_phy_irq);
+ if (!mdwc->no_wakeup_src_in_hostmode)
+ enable_irq_wake(mdwc->ss_phy_irq);
enable_irq(mdwc->ss_phy_irq);
}
mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
@@ -2287,10 +2290,12 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
/* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */
if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) {
- disable_irq_wake(mdwc->hs_phy_irq);
+ if (!mdwc->no_wakeup_src_in_hostmode)
+ disable_irq_wake(mdwc->hs_phy_irq);
disable_irq_nosync(mdwc->hs_phy_irq);
if (mdwc->ss_phy_irq) {
- disable_irq_wake(mdwc->ss_phy_irq);
+ if (!mdwc->no_wakeup_src_in_hostmode)
+ disable_irq_wake(mdwc->ss_phy_irq);
disable_irq_nosync(mdwc->ss_phy_irq);
}
mdwc->lpm_flags &= ~MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
@@ -2913,6 +2918,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
int ret = 0;
int ext_hub_reset_gpio;
u32 val;
+ char boot_marker[40];
mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL);
if (!mdwc)
@@ -3260,8 +3266,15 @@ static int dwc3_msm_probe(struct platform_device *pdev)
mdwc->host_only_mode = true;
mdwc->id_state = DWC3_ID_GROUND;
dwc3_ext_event_notify(mdwc);
+ snprintf(boot_marker, sizeof(boot_marker),
+ "M - DRIVER %s Host Ready", dev_name(&pdev->dev));
+ } else {
+ snprintf(boot_marker, sizeof(boot_marker),
+ "M - DRIVER %s Device Ready", dev_name(&pdev->dev));
}
+ place_marker(boot_marker);
+
return 0;
put_dwc3:
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 4ec0dd4f0a8c..5ccc09888345 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -4299,11 +4299,8 @@ DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
static int ffs_init(void)
{
ffs_ipc_log = ipc_log_context_create(NUM_PAGES, "f_fs", 0);
- if (IS_ERR_OR_NULL(ffs_ipc_log)) {
+ if (IS_ERR_OR_NULL(ffs_ipc_log))
ffs_ipc_log = NULL;
- pr_err("%s: Create IPC log context failure\n",
- __func__);
- }
return 0;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 4954e22a421b..50a1b0a34617 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3659,6 +3659,7 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
}
+ virt_dev->udev = NULL;
spin_lock_irqsave(&xhci->lock, flags);
/* Don't disable the slot if the host controller is dead. */
state = readl(&xhci->op_regs->status);
diff --git a/drivers/usb/misc/diag_ipc_bridge.c b/drivers/usb/misc/diag_ipc_bridge.c
index b9ced8d0062d..a652c8f9bab7 100644
--- a/drivers/usb/misc/diag_ipc_bridge.c
+++ b/drivers/usb/misc/diag_ipc_bridge.c
@@ -730,6 +730,8 @@ static int diag_bridge_resume(struct usb_interface *ifc)
static const struct usb_device_id diag_bridge_ids[] = {
{ USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9001, 0),
.driver_info = DEV_ID(0), },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901D, 0),
+ .driver_info = DEV_ID(0), },
{ USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9034, 0),
.driver_info = DEV_ID(0), },
{ USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 0),