修复展锐SL8541E 偶现开机无法启动OTG
哎,又是紫光展锐,真的拉啊!!!
问题是这样的,当USB口插上OTG线再开机,会偶现无法启动OTG。这个问题排查了好久,现在终于改好了,下面记录一下分析过程。
异常log【上】和正常log【下】
前面部分就不贴了,都是一样的。可以看到开机时通知器会上报两个通知,先来的是vbus notify,后来的id notify。出现异常时vbus的通知器函数会去设置状态机,但是状态机的work queue还没跑完呢,id的通知器函数就开始执行了。经过分析,正确设置状态机就需要让各个通知器先等状态机的work queue跑完了再进行。
最终修改方案,使用一个原子量来给id、vbus通知器回调函数与状态机的work_queue做同步。这里为什么要用原子量,因为展锐的这个驱动写的太烂了,work_queue有可能会出现长时间卡在里面,因此不得不使用原子量,死等肯定是不行的。
diff --git a/drivers/usb/musb/musb_sprd.c b/drivers/usb/musb/musb_sprd.c
index d32027a..c8dc027 100644
--- a/drivers/usb/musb/musb_sprd.c
+++ b/drivers/usb/musb/musb_sprd.c
@@ -34,6 +34,7 @@
#include <linux/wait.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/mutex.h>
#include "musb_core.h"
#include "sprd_musbhsdma.h"
@@ -44,6 +45,7 @@
MODULE_DESCRIPTION(DRIVER_INFO);
MODULE_LICENSE("GPL v2");
+static DEFINE_MUTEX(musb_sprd_extcon_mutex);
#define MUSB_RECOVER_TIMEOUT 100
struct sprd_glue {
@@ -53,6 +55,8 @@ struct sprd_glue {
struct phy *phy;
struct usb_phy *xceiv;
struct regulator *vbus;
+ struct regulator *eth;
+ struct regulator *usbnet;
struct wakeup_source pd_wake_lock;
struct regmap *pmu;
@@ -71,6 +75,9 @@ struct sprd_glue {
struct notifier_block vbus_nb;
struct notifier_block id_nb;
+ atomic_t workqueue_running; /* for extcon sync */
+ atomic_t extcon_running; /* for extcon sync */
+
bool bus_active;
bool vbus_active;
bool charging_mode;
@@ -85,6 +92,13 @@ struct sprd_glue {
};
static int boot_charging;
+static char* musb_dr_mode_show[] = {
+ "unknown",
+ "host",
+ "device",
+ "otg",
+};
+
static void sprd_musb_enable(struct musb *musb)
{
struct sprd_glue *glue = dev_get_drvdata(musb->controller->parent);
@@ -452,41 +466,44 @@ static int musb_sprd_vbus_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct sprd_glue *glue = container_of(nb, struct sprd_glue, vbus_nb);
- unsigned long flags;
+ int try = 500;
+
+ mutex_lock(&musb_sprd_extcon_mutex);
+ while (atomic_read(&glue->workqueue_running) && try--)
+ msleep(1);
if (event) {
- spin_lock_irqsave(&glue->lock, flags);
if (glue->vbus_active == 1 || glue->dr_mode == USB_DR_MODE_HOST) {
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"ignore device connection detected from VBUS GPIO.\n");
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
if (glue->dpdm_switch)
gpiod_set_value_cansleep(glue->dpdm_switch, 0);
glue->vbus_active = 1;
glue->wq_mode = USB_DR_MODE_PERIPHERAL;
+ atomic_set(&glue->workqueue_running, 1);
queue_work(system_unbound_wq, &glue->work);
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"device connection detected from VBUS GPIO.\n");
} else {
- spin_lock_irqsave(&glue->lock, flags);
if (glue->vbus_active == 0 || glue->dr_mode == USB_DR_MODE_HOST) {
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"ignore device disconnect detected from VBUS GPIO.\n");
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
glue->vbus_active = 0;
glue->wq_mode = USB_DR_MODE_PERIPHERAL;
+ atomic_set(&glue->workqueue_running, 1);
queue_work(system_unbound_wq, &glue->work);
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"device disconnect detected from VBUS GPIO.\n");
}
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
@@ -494,41 +511,44 @@ static int musb_sprd_id_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct sprd_glue *glue = container_of(nb, struct sprd_glue, id_nb);
- unsigned long flags;
+ int try = 500;
+
+ mutex_lock(&musb_sprd_extcon_mutex);
+ while (atomic_read(&glue->workqueue_running) && try--)
+ msleep(1);
if (event) {
- spin_lock_irqsave(&glue->lock, flags);
if (glue->vbus_active == 1 || glue->dr_mode == USB_DR_MODE_PERIPHERAL) {
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"ignore host connection detected from ID GPIO.\n");
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
if (glue->dpdm_switch)
gpiod_set_value_cansleep(glue->dpdm_switch, 1);
glue->vbus_active = 1;
glue->wq_mode = USB_DR_MODE_HOST;
+ atomic_set(&glue->workqueue_running, 1);
queue_work(system_unbound_wq, &glue->work);
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"host connection detected from ID GPIO.\n");
} else {
- spin_lock_irqsave(&glue->lock, flags);
if (glue->vbus_active == 0 || glue->dr_mode == USB_DR_MODE_PERIPHERAL) {
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"ignore host disconnect detected from ID GPIO.\n");
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
glue->vbus_active = 0;
glue->wq_mode = USB_DR_MODE_HOST;
+ atomic_set(&glue->workqueue_running, 1);
queue_work(system_unbound_wq, &glue->work);
- spin_unlock_irqrestore(&glue->lock, flags);
dev_info(glue->dev,
"host disconnect detected from ID GPIO.\n");
}
+ mutex_unlock(&musb_sprd_extcon_mutex);
return 0;
}
@@ -651,16 +671,16 @@ static bool musb_sprd_is_connect_host(struct sprd_glue *glue)
return false;
}
-static __init int musb_sprd_charger_mode(char *str)
-{
- if (strcmp(str, "charger"))
- boot_charging = 0;
- else
- boot_charging = 1;
+// static __init int musb_sprd_charger_mode(char *str)
+// {
+// if (strcmp(str, "charger"))
+// boot_charging = 0;
+// else
+// boot_charging = 1;
- return 0;
-}
-__setup("androidboot.mode=", musb_sprd_charger_mode);
+// return 0;
+// }
+// __setup("androidboot.mode=", musb_sprd_charger_mode);
static void sprd_musb_recover_work(struct work_struct *work)
{
@@ -704,13 +724,17 @@ static void sprd_musb_work(struct work_struct *work)
int ret;
int cnt = 100;
+ dev_info(glue->dev, "enter sprd_musb_work()\n");
+ atomic_set(&glue->workqueue_running, 1);
spin_lock_irqsave(&glue->lock, flags);
current_mode = glue->wq_mode;
current_state = glue->vbus_active;
glue->wq_mode = USB_DR_MODE_UNKNOWN;
spin_unlock_irqrestore(&glue->lock, flags);
- if (current_mode == USB_DR_MODE_UNKNOWN)
+ if (current_mode == USB_DR_MODE_UNKNOWN) {
+ atomic_set(&glue->workqueue_running, 0);
return;
+ }
/*
* There is a hidden danger, when system is going to suspend.
@@ -780,7 +804,10 @@ static void sprd_musb_work(struct work_struct *work)
if (glue->dr_mode == USB_DR_MODE_HOST) {
if (!glue->vbus) {
glue->vbus = devm_regulator_get(glue->dev, "vbus");
- if (IS_ERR(glue->vbus)) {
+ glue->eth = devm_regulator_get(glue->dev, "eth");
+ glue->usbnet = devm_regulator_get(glue->dev, "usbnet");
+ if (IS_ERR(glue->vbus) || IS_ERR(glue->eth) \
+ || IS_ERR(glue->usbnet)) {
dev_err(glue->dev,
"unable to get vbus supply\n");
glue->vbus = NULL;
@@ -788,10 +815,12 @@ static void sprd_musb_work(struct work_struct *work)
}
}
ret = regulator_enable(glue->vbus);
+ ret = regulator_enable(glue->eth);
+ ret = regulator_enable(glue->usbnet);
if (ret) {
dev_err(glue->dev,
"Failed to enable vbus: %d\n", ret);
- goto end;
+ // goto end;
}
}
@@ -869,10 +898,12 @@ static void sprd_musb_work(struct work_struct *work)
if (glue->dr_mode == USB_DR_MODE_HOST && glue->vbus) {
ret = regulator_disable(glue->vbus);
+ ret = regulator_disable(glue->eth);
+ ret = regulator_disable(glue->usbnet);
if (ret) {
dev_err(glue->dev,
"Failed to disable vbus: %d\n", ret);
- goto end;
+ // goto end;
}
}
@@ -909,6 +940,7 @@ static void sprd_musb_work(struct work_struct *work)
glue->schedule_work_done_flag = 1;
__pm_relax(&glue->pd_wake_lock);
enable_irq(glue->vbus_irq);
+ atomic_set(&glue->workqueue_running, 0);
}
/**
@@ -1031,7 +1063,38 @@ static ssize_t mode_switch_store(struct device *dev,
return count;
}
-DEVICE_ATTR_WO(mode_switch);
+static ssize_t mode_switch_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sprd_glue *glue = dev_get_drvdata(dev);
+ const char *str = NULL;
+
+ switch (glue->dr_mode) {
+ case USB_DR_MODE_UNKNOWN :
+ str = musb_dr_mode_show[USB_DR_MODE_UNKNOWN];
+ break;
+
+ case USB_DR_MODE_HOST :
+ str = musb_dr_mode_show[USB_DR_MODE_HOST];
+ break;
+
+ case USB_DR_MODE_PERIPHERAL :
+ str = musb_dr_mode_show[USB_DR_MODE_PERIPHERAL];
+ break;
+
+ case USB_DR_MODE_OTG :
+ str = musb_dr_mode_show[USB_DR_MODE_OTG];
+ break;
+
+ default:
+ str = musb_dr_mode_show[USB_DR_MODE_UNKNOWN];
+ break;
+ }
+
+ return sprintf(buf, "%s\n", str);
+}
+
+DEVICE_ATTR_RW(mode_switch);
static ssize_t maximum_speed_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1127,6 +1190,9 @@ static int musb_sprd_probe(struct platform_device *pdev)
else
dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
+ atomic_set(&glue->workqueue_running, 0);
+ atomic_set(&glue->extcon_running, 0);
+
glue->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(glue->clk)) {
dev_err(dev, "no core clk specified\n");
@@ -1148,6 +1214,8 @@ static int musb_sprd_probe(struct platform_device *pdev)
if (pdata.mode == MUSB_PORT_MODE_HOST ||
pdata.mode == MUSB_PORT_MODE_DUAL_ROLE) {
glue->vbus = devm_regulator_get(dev, "vbus");
+ glue->eth = devm_regulator_get(dev, "eth");
+ glue->usbnet = devm_regulator_get(dev, "usbnet");
if (IS_ERR(glue->vbus)) {
ret = PTR_ERR(glue->vbus);
dev_warn(dev, "unable to get vbus supply %d\n", ret);
@@ -1229,7 +1297,7 @@ static int musb_sprd_probe(struct platform_device *pdev)
goto err_glue_musb;
}
glue->id_nb.notifier_call = musb_sprd_id_notifier;
- glue->id_edev = extcon_get_edev_by_phandle(glue->dev, 1);
+ glue->id_edev = extcon_get_edev_by_phandle(glue->dev, 0);
if (IS_ERR(glue->id_edev)) {
glue->id_edev = NULL;
dev_info(dev, "No separate ID extcon device.\n");
@@ -1390,6 +1458,8 @@ static int musb_sprd_suspend(struct device *dev)
if (musb->is_offload && !musb->offload_used) {
if (glue->vbus) {
ret = regulator_disable(glue->vbus);
+ ret = regulator_disable(glue->eth);
+ ret = regulator_disable(glue->usbnet);
if (ret < 0)
dev_err(glue->dev,
"Failed to disable vbus: %d\n", ret);
@@ -1416,6 +1486,8 @@ static int musb_sprd_resume(struct device *dev)
if (musb->is_offload && !musb->offload_used) {
if (glue->vbus) {
ret = regulator_enable(glue->vbus);
+ ret = regulator_enable(glue->eth);
+ ret = regulator_enable(glue->usbnet);
if (ret < 0)
dev_err(glue->dev,
"Failed to enable vbus: %d\n", ret);
修复展锐SL8541E 偶现开机无法启动OTG的更多相关文章
- 偶现bug如何处理?
请先允许我对此类bug进行吐槽,相信做测试的同学都碰见过这种bug! 我们在测试过程中经常会碰见一类很头疼的bug,就是偶现性的bug,所谓偶现性,是相对于必现而言,这类bug有些可以有重现路径,但是 ...
- [转帖]紫光展锐5G芯片
紫光展锐5G芯片已流片:7nm工艺 2019年问世 https://news.mydrivers.com/1/612/612346.htm 本文转载自超能网,其他媒体转载需经超能网同意 高通骁龙X ...
- CAT偶现NPE的问题
1.背景 我们公司的调用链系统是基于大众点评的CAT客户端改造的,服务端完全有自己设计开发的.在是用CAT客户端收集dubbo调用信息的时候,我们发现了一个CAT偶现NPE的bug,该bug隐藏的很深 ...
- Ubuntu16.04下写的Qt程序,调试时没问题,运行时偶现崩溃 (需要在运行时生成core dump文件,QMAKE_CC += -g)
记录一下 Ubuntu16.04下写的Qt程序,调试时没问题,运行时偶现崩溃 需要在运行时生成core dump文件 首先在pro结尾里加入 QMAKE_CC += -g QMAKE_CXX += - ...
- 【Golang】嗅探抓包,解决线上偶现问题来不及抓包的情况
背景 测试群里经常看到客户端的同学反馈发现了偶现Bug,但是来不及抓包,最后不了了之,最近出现得比较频繁,所以写个小脚本解决这个问题. 实现思路 实现的思路比较简单: 抓包 存日志 做日志管理 具体实 ...
- 程序员的踩坑经验总结(一):如何把Bug的偶现变必现
程序员的踩过的坑也是可以分类的,很常见又很难解决的一类是偶然的现象,表现起来比较怪异. 而把一个问题Bug的偶现变成必现,是开发人员的一种能力.我认为也应该是测试人员的一种能力,但是各个公司要求不一样 ...
- 完美解决 开机无法启动 提示0xc000000e
注:昨天装系统碰到这个问题,这个方法说的较详细,我的是WIN7系统,开机提示引导文件错误,代码为0xc000000e 无法进入系统,使用PE进入后,在运行里输入CMD,然后按下文红字开始操作 完美解决 ...
- Android开机动画启动流程
android开机动画启动流程 从android的Surface Flinger服务启动分析知道,开机动画是在SurfaceFlinger实例通过调用startBootAnim()启动的. 下面我 ...
- 关于自定义脚本rc.local里开机不启动的问题--以tomcat和perl相关的脚本为例
本文将自己遇到的一些自定义脚本加入开机启动项却不成功的问题加以说明,花费了我很长时间才得以解决,当然也多谢了自己朋友的帮忙,正是因为他们的提醒,最后才找到了解决的办法,谢谢他们!!!! 系统是cent ...
- 在 win10 环境下,设置自己写的 程序 开机自动 启动的方法
原文:在 win10 环境下,设置自己写的 程序 开机自动 启动的方法 1.是登录自己用户时才能开机启 C:\Users\username\AppData\Roaming\Microsoft\Wind ...
随机推荐
- Machine Learning Week_1 Introduction 9-11
目录 1.9 Who are Mentors? unfamiliar words 1.10 Get to Know Your Classmates unfamiliar words 1.11 Freq ...
- 一文彻底搞透Redis的数据类型及具体的应用场景
Redis 提供了丰富的数据类型,每种数据类型都有其独特的存储结构和操作方法,可以满足不同的业务场景需求.下面详细介绍 Redis 支持的主要数据类型及其底层实现,并结合具体的应用场景说明其使用. 1 ...
- vue关于图片参数赋值
解决方法: 加个require()就可以了 <img :src="require('../xxx/images/'+imgsrc+'.png')"/> export d ...
- Windows下如何用virtualenv创建虚拟环境
虚拟环境可以有效的解决不同项目需要不同环境的问题,虚拟环境最大的好处就是可以将我们的开发环境进行隔离,让彼此之间不互相受影响.一.Windows下创建虚拟环境1.虚拟环境需要用到的库是virtuale ...
- UniswapV2Pair细节
UniswapV2Pair合约是Uniswap V2协议中的核心部分,用于管理流动性池.代币交换.流动性代币的铸造和销毁等操作.以下是对UniswapV2Pair合约中所有主要方法及其参数的详细讲解. ...
- QT中的宏定义
1.操作系统宏 //在<QtGlobal>中,定义了各个系统的宏定义 //Defined on AIX. #ifdef Q_OS_AIX // Defined on Android. #d ...
- setTimeout 的方式实现 setInteval
setTimeout(function fn(){ setTimeout(fn,interval); },interval); 这个模式链式调用了setTimeout(),每次函数执行的时候都会创建一 ...
- Python字典推导式
要求打印字典中值小于1的key和value d = {"a": 1, "b":2, "c":3} d = {key: value for k ...
- isObject:判断数据是不是引用类型的数据 (例如: arrays, functions, objects, regexes, new Number(0),以及 new String(''))
function isObject(value) { let type = typeof value; return value != null && (type == 'object ...
- ServiceMesh 4:实现流量染色和分级发布
★ ServiceMesh系列 1 什么是流量染色 在复杂的生产场景中,经常会有同一个服务中,存在多个版本长期共存的需求.为了让不同的用户在不一样的版本中使用,就需要对用户的请求进行采样和染色,打上不 ...