[android][sensor][cts] ctsv device suspend test fail —— qrtr改为非唤醒模式

文章分析了在设备休眠测试中由于qrtr(AP与modem间通信)唤醒源导致无法进入suspendmode的问题。提出了修改qrtr通信为非唤醒模式的解决方案,涉及kernel源码的多处变更,包括qrtr_haven_probe、qcom_mhi_qrtr_probe、qrtr_get_service_id等函数的更新,并建议通过配置选项CONFIG_QRTR_GKI来区分不同产品的唤醒需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cts-verifier device suspend test fail —— qrtr改为非唤醒模式

device suspend test

设备休眠测试

install CtsVerifier.apk

手动执行device suspend test项:
按要求设置相应环境后开始测试,测试时需要灭屏,待几分钟后会有测试结束提示音

结果

testAccelBatchingInAPSuspendZeroReportLatency 该项测试失败
显示:

[TestExecution] Device did not go into suspend during test execution

分析

ap侧无法进入suspend mode

从log中可以看到如下内容:

Abort: Last active Wakeup Source: qrtr_ws PM: suspend exit

在测试过程中,灭屏后ap侧被唤醒源qrtr_ws持续唤醒,即qrtr通信(ap与modem之间通信)唤醒kernel,导致无法进入suspend mode

修改

据了解,该问题为高通老平台共性问题,需要修改qrtr通信改为非唤醒模式

原理:增加对从子系统接收数据时过滤的服务支持,如果service id在白名单中,它将不会持有唤醒源。

修改参考(kernel-5.4,system t,chip t):
kernel/msm-5.4/net/qrtr/haven.c

static int qrtr_haven_probe(struct platform_device *pdev)
{
...
 	qdev->ep.xmit = qrtr_haven_send;
-	ret = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NET_ID_AUTO, false);
+	ret = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NET_ID_AUTO, false, NULL);
 	if (ret)
 		goto register_fail;
...

kernel/msm-5.4/net/qrtr/mhi.c

static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
			       const struct mhi_device_id *id)
{
 ...
 	dev_set_drvdata(&mhi_dev->dev, qdev);
 
-	rc = qrtr_endpoint_register(&qdev->ep, net_id, rt);
+	rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, NULL);
 	if (rc)
 		return rc;
 ...

kernel/msm-5.4/net/qrtr/ns.c

unsigned int qrtr_get_service_id(unsigned int node_id, unsigned int port_id)
{
	struct qrtr_server *srv;
	struct qrtr_node *node;
	unsigned long index;
 
-	node = node_get(node_id);
+	node = xa_load(&nodes, node_id);
 	if (!node)
 		return 0;
...

kernel/msm-5.4/net/qrtr/qrtr.h

+ #define MAX_NON_WAKE_SVC_LEN    5

int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id,
-			   bool rt);
+			   bool rt, u32 *svc_arr);
...

kernel/msm-5.4/net/qrtr/qrtr.c

struct qrtr_node {
...
 	struct wakeup_source *ws;
 	void *ilc;
+	u32 nonwake_svc[MAX_NON_WAKE_SVC_LEN];
 };
...
int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
...
	unsigned int ver;
	size_t hdrlen;
-	int errcode;
+	int errcode,i;
+	bool wake = true;
+	int svc_id;
...
		/* Force wakeup for all packets except for sensors */
-		if (node->nid != 9)
+		if (node->nid != 9 && node->nid != 5)
			pm_wakeup_ws_event(node->ws, qrtr_wakeup_ms, true);

+		if (node->nid == 5) {
+			svc_id = qrtr_get_service_id(cb->src_node, cb->src_port);
+			if (svc_id > 0) {
+				for (i = 0; i < MAX_NON_WAKE_SVC_LEN; i++) {
+					if (svc_id == node->nonwake_svc[i]) {
+						wake = false;
+						break;
+					}
+				}
+			}
+			if (wake)
+				pm_wakeup_ws_event(node->ws, qrtr_wakeup_ms, true);
+		}
		qrtr_port_put(ipc);
	}
...
}
...
int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id,
-			   bool rt)
+			   bool rt, u32 *svc_arr)
{
...
	if (rt)
		sched_setscheduler(node->task, SCHED_FIFO, &param);

+	if (svc_arr)
+		memcpy(node->nonwake_svc, svc_arr, MAX_NON_WAKE_SVC_LEN * sizeof(int));
	mutex_init(&node->qrtr_tx_lock);
...

kernel/msm-5.4/net/qrtr/smd.c

static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
{
 	struct qrtr_smd_dev *qdev;
 	u32 net_id;
 	bool rt;
- 	int rc;
+	int rc,size;
	u32 *svc_arr = NULL;
	pr_info("%s:Entered\n", __func__);
...
 	rt = of_property_read_bool(rpdev->dev.of_node, "qcom,low-latency");

-	rc = qrtr_endpoint_register(&qdev->ep, net_id, rt);
+	size = of_property_count_u32_elems(rpdev->dev.of_node, "qcom,non-wake-svc");
+	if (size > 0) {
+		if (size > MAX_NON_WAKE_SVC_LEN)
+			size = MAX_NON_WAKE_SVC_LEN;
+		svc_arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
+
+		of_property_read_u32_array(rpdev->dev.of_node, "qcom,non-wake-svc",
+					   svc_arr, size);
+	}
+	rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, svc_arr);
+	kfree(svc_arr);
+ 
 	if (rc)
 		return rc;
...

platform/vendor/qcom-proprietary/devicetree/qcom/xxx.dtsi

			qcom,adsp_qrtr {
				qcom,glink-channels = "IPCRTR";
				qcom,intents = <0x800  5
						0x2000 3
						0x4400 2>;
+				qcom,non-wake-svc = <0x190>;
			};

如果该仓有多个产品共用,且有些产品需要qrtr唤醒,而一些产品需要qrtr在非唤醒模式,那么可以加config进行区分:
kernel/msm-5.4/net/qrtr/Kconfig 添加

+config QRTR_GKI
+	bool "QRTR GKI"
+	default n
+	help
+	 To solve the abi check fail, this macro is added.

在需要添加qrtr非唤醒的的产品上添加:
kernel/msm-5.4/arch/arm64/configs/vendor/xxx.config

+CONFIG_QRTR_GKI=y

在前边修改的地方添加宏控以区分:

+#ifdef CONFIG_QRTR_GKI
...
+#else
...
+#endif
`qrtr_print_wakeup_reason` 并未在所提供的引用材料中直接提及,但从其名称可以推测该函数可能与 `wakeup_source` 和调试日志记录有关。以下是对其潜在用途和意义的分析: ### 函数背景 Linux 内核提供了多种机制来管理电源状态以及唤醒事件。其中,`__pm_stay_awake()`、`__pm_relax()` 和 `__pm_wakeup_event()` 是典型的 API,用于处理唤醒源的操作[^1]。这些接口允许设备驱动程序注册并管理唤醒事件。 假设 `qrtr_print_wakeup_reason` 存在于某个特定模块或子系统中,则它的功能很可能是为了打印导致系统从低功耗模式唤醒的原因。这种行为常见于调试场景下,帮助开发者理解哪些硬件组件或软件逻辑触发了系统的唤醒过程。 ### 可能的功能实现 #### 打印唤醒原因的日志信息 基于命名约定,“print” 表明此方法会输出某种形式的信息;而 “wakeup_reason” 则暗示内容涉及为何发生唤醒动作的具体描述。因此,合理推断如下伪代码结构: ```c void qrtr_print_wakeup_reason(struct wakeup_source *ws) { printk(KERN_INFO "Wakeup Source: %s triggered at time %llu\n", ws->name, ktime_to_ms(ws->total_time)); } ``` 上述例子展示了如何利用给定参数(即指向 `struct wakeup_source` 的指针)提取相关信息并通过内核日志服务展示出来。实际应用时可能会更加复杂一些,比如加入额外的状态检查或是格式化更多细节数据。 #### 调试辅助工具角色 另外值得注意的是,在开发阶段经常需要用到各种诊断手段以便定位问题所在。正如提到过的关于 WARN_ON() 或者 DEBUG_ON()[^3], 如果存在类似的条件编译选项控制下的专用打印语句,则进一步增强了这一猜测——即当启用了相应级别的跟踪支持之后才会执行此类操作。 综上所述,虽然无法确切知道未经公开文档化的具体内部工作原理,但是通过现有资料我们可以构建起对于这类功能性API的大致轮廓认知。 ###
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霁之鸢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值