音频smmu问题之smmu学习

news/2024/4/19 17:15:46/

一、音频smmu 内存访问问题

在工作中,遇到一个smmu问题,主要log信息如下:

arm-smmu 15000000.apps-smmu: Unhandled arm-smmu context fault from soc:spf_core_platform:qcom,msm-audio-ion!
arm-smmu 15000000.apps-smmu: FAR = 0x000000001fff8000
arm-smmu 15000000.apps-smmu: PAR = 0x0000000000000000
arm-smmu 15000000.apps-smmu: FSR = 0x40000408 [PF R SS]
arm-smmu 15000000.apps-smmu: FSYNR0 = 0x320002
arm-smmu 15000000.apps-smmu: FSYNR1 = 0xe00e
arm-smmu 15000000.apps-smmu: context bank# = 0x30
arm-smmu 15000000.apps-smmu: TTBR0 = 0x0000000000000000
arm-smmu 15000000.apps-smmu: TTBR1 = 0x0000000000000000
arm-smmu 15000000.apps-smmu: SCTLR = 0x0a5f00e7 ACTLR = 0x00000003
arm-smmu 15000000.apps-smmu: CBAR = 0x0001f300
arm-smmu 15000000.apps-smmu: MAIR0 = 0xf404ff44 MAIR1 = 0x0000efe4
arm-smmu 15000000.apps-smmu: SID = 0x1001
arm-smmu 15000000.apps-smmu: Client info: BID=0x7, PID=0x0, MId=0xe
arm-smmu 15000000.apps-smmu: soft iova-to-phys=0x00000000bc299000
arm-smmu 15000000.apps-smmu: hard iova-to-phys(ATOS)=0x00000000bc299000

1、从堆栈来看大致可以了解到, 这是由于SMMU监测到某个模块非法的访问DMA地址后, 引起了内核崩溃. 那么, 为何有这个错误SMMU访问错误? 这个错误又是哪个模块导致的? 是在什么情况下引起的SMMU内存错误了? 这不得不从SMMU本身说起.

继续来看下问题的日志. 堆栈的前面一部分是有关SMMU的状态寄存器:
FAR(Fault Address Register): 表示发生错误的IO虚拟地址
PAR(Physical Address Register): 发生错误时查找到的物理地址, 这里是全0, 说明相应的IOVA地址没有映射
FSR(Fault Status Register): 表示SMMU错误的类型(转换/权限等), 这里的值0x40000408 [PF R SS], 说明是一个读操作时引起的页表访问错误
TTBRm(Translation Table Base Address):
TTBR0: 保存Translation Table0的基地址
TTBR1: 保存Translation Table1的基地址
SID(Stream ID): SID是对应设备使用SMMU映射内存时的标识

重点看下如下两行日志, 我们可以知道发生内存映射异常的IOVA地址是0x1fff8000, 对应的SID是0x1001

arm-smmu 15000000.apps-smmu: FAR = 0x000000001fff8000
arm-smmu 15000000.apps-smmu: SID = 0x1001

SID一般在设备树DTS的配置中指定的或者可以在modem代码中查看

路径:/trustzone_images/core/settings/kernel/iortlib/config/xxx/xxx.c

2、理清楚这些SMMU的日志只是第一步, 但是对于为何会发生SMMU访问异常还是毫无头绪. 这个只能通过阅读驱动源代码弄清楚代码流程才能一步步揭开迷雾了.

网卡需要传数据时, 获取到当前的缓冲区对应的DMA内存地址(IOVA)后, 通过SMMU向对应的RAM地址传输数据
发送完成后, 通过中断告知驱动有数据需要接收
CPU接收到中断后, 驱动会把DMA的映射解除, 数据交由CPU处理; 接着驱动把对应的数据发送到协议栈继续处理

那么, 问题来了, SMMU是何时收到DMA访问异常错误的了? 是在第三个步骤, 驱动解除DMA地址映射后, 有地方再次尝试使用该DMA地址导致的吗? 从驱动的逻辑来看, 每次传送完成, DMA地址与RAM地址解除映射后, 没有地方会再次尝试获取该DMA地址了(对应buffer的DMA地址已经置空). 退一步说, 如果是驱动使用的时候发生的问题, 那么异常的堆栈应该会打印出来, 但是现在只有SMMU相关的日志.

所以, 问题的源头只能是在网卡通过SMMU往对应的DMA地址发送数据的时候, 就是说如果网卡给DMA传输数据的大小超过了预分配的buffer的大小的话, SMMU会发现对应的DMA地址没有映射到物理地址, 从而报错. 解决问题的办法也很简单, 只需要把buffer大小由原来的1538修改为2048(2kb)就可以了:

从高通给的一些问题案例来说, 一般SMMU都是由于需要传输的数据大小与实际的buf大小不一致导致的. 总的说来, SMMU的问题看起来十分棘手, 但只要把基本的概念与原理弄清楚, 把代码流程梳理完整, 解决这类问题并不是件十分困难的事情.

二、smmu 相关知识学习

1、概述

简单来说, SMMU(System Memory Management Unit)是ARM为外设访问系统RAM提供了一种类似于MMU的虚拟内存访问机制, 外设可以通过DMA直接访问RAM, 而无需CPU的干预. 如此, 外设可以通过一个虚拟的地址即可访问物理地址(可以不连续), 做到了不同外设之间IO地址空间的彼此独立与隔离. 因此, SMMU也通常被称为IOMMU(Input/Output MMU).

下图是从ARM SMMU Spec手册里的一张SMMU简图: SMMU为设备与RAM之间构建了一个设备虚拟地址(IOVA)与物理地址之间的映射关系, 每次执行DMA数据传输的时候, 都要通过SMMU将IOVA地址翻译成对应的物理地址.
在这里插入图片描述
那么对于设备驱动来说, 如何使用SMMU了? 不妨来看下SMMU相关的API.

arm_iommu_create_mapping: 配置设备所要使用的VA(Virtual Address, 虚拟地址)的范围
arm_iommu_attach_device: 将分配好的VA地址范围与设备绑定, 并开启SMMU地址转换
dma_map_single/dma_unmap_single: 分配/去除某个DMA地址, 这种方式是异步的, 常用于一次性传输的场景(传输完成后DMA的映射即解除了)
dma_alloc_coherent/dma_free_coherent: 一致性(consistent), 同步(synchronous)的DMA内存分配方法, 确保CPU与设备的数据始终是同步的, 一般用于需要常驻内存的一些数据
这里不对IOMMU的代码做深入分析了. 有关IOMMU相关的流程可以参考内核代码:

kernel/drivers/iommu: SMMU驱动, 用于配置SMMU, 为设备驱动提供接口
kernel/arch/arm64/mm: 与平台相关的SMMU的页表分配的实现

2、smmu寄存器

FAR(Fault Address Register): 表示发生错误的IO虚拟地址
PAR(Physical Address Register): 发生错误时查找到的物理地址, 这里是全0, 说明相应的IOVA地址没有映射
FSR(Fault Status Register): 表示SMMU错误的类型(转换/权限等), 这里的值0x40000408 [PF R SS], 说明是一个读操作时引起的页表访问错误
TTBRm(Translation Table Base Address):
TTBR0: 保存Translation Table0的基地址
TTBR1: 保存Translation Table1的基地址
SID(Stream ID): SID是对应设备使用SMMU映射内存时的标识

参考
https://mp.weixin.qq.com/s/IsNUsalsE2sZOd2AJlXtjQ?poc_token=HLeZ2WWjwsFSMFprJ21xG6cSnuJWTNdnE0gRy9h5
https://zhuanlan.zhihu.com/p/662140784
https://zhuanlan.zhihu.com/p/650483261


http://www.ppmy.cn/news/1365098.html

相关文章

devc++跑酷小游戏3.5.0

本来想搞存档的&#xff0c;失败了&#xff0c;要再学学文件操作的函数。还有一个打印地图的函数&#xff0c;更失败&#xff0c;彻底放弃。最近开学了&#xff0c;游戏不会经常更新&#xff0c;要写作业。昨天写到10点T_T #include<bits/stdc.h> #include<windows.h…

vue-router4 (二) 引入并配置路由

1.在项目src/router/index.ts 文件夹下配置路由&#xff1a; import { createRouter ,createWebHistory,RouteRecordRaw} from "vue-router"; //1.引入路由//3.routes配置项 const routes:Array<RouteRecordRaw> [{path:"/", //路径name:"…

【GameFramework框架内置模块】4、内置模块之调试器(Debugger)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群&#xff1a;398291828 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录&#xff1a;…

Groovy(第八节) Groovy 之类

目录 Song 类 Groovy 类就是 Java 类 类的关系 类初始化 核心的灵活性

如何使用Fastapi上传文件?先从请求体数据讲起

文章目录 1、请求体数据2、form表单数据3、小文件上传1.单文件上传2.多文件上传 4、大文件上传1.单文件上传2.多文件上传 1、请求体数据 前面我们讲到&#xff0c;get请求中&#xff0c;我们将请求数据放在url中&#xff0c;其实是非常不安全的&#xff0c;我们更愿意将请求数…

【MySQL】MySQL复合查询--多表查询自连接子查询 - 副本

文章目录 1.基本查询回顾2.多表查询3.自连接4.子查询 4.1单行子查询4.2多行子查询4.3多列子查询4.4在from子句中使用子查询4.5合并查询 4.5.1 union4.5.2 union all 1.基本查询回顾 表的内容如下&#xff1a; mysql> select * from emp; ----------------------------…

MySQL:单表查询SQL语句

提醒&#xff1a;设定下面的语句是在数据库名为 db_student里执行的。 创建t_student表 CREATE TABLE t_student(id INT NOT NULL AUTO_INCREMENT,stuName VARCHAR(30) DEFAULT NULL,age INT,sex VARCHAR(4) DEFAULT NULL,gradeName VARCHAR(30) DEFAULT NULL,PRIMARY KEY(id)…

修改Qt生成iOS应用的原生底层,编译QtBase下的ios子模块

1.下载Qt源码 2.找到ios.pro子工程 3.使用QtCreaor12打开ios.pro工程 4.出现工程下只有一个.pro文件解决 复制修改好的toolchain.prf文件进行替换. 修改方法:

HTML知识点

HTML 【一】HTML简介 【1】什么是HTML HTML是一种用于创建网页结构和内容的超文本标记语言&#xff0c;它是构建网页的基础。为了让浏览器正确渲染页面&#xff0c;我们必须遵循HTML的语法规则。浏览器在解析网页时会将HTML代码转换为可视化的页面&#xff0c;所以我们在浏览…

Netty入门指南:从零开始的异步网络通信

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Netty入门指南&#xff1a;从零开始的异步网络通信 前言Netty简介由来&#xff1a;发展历程&#xff1a;异步、事件驱动的编程模型&#xff1a; 核心组件解析通信协议高性能特性异步编程范式性能优化与…

鸿蒙应用程序包安装和卸载流程

开发者 开发者可以通过调试命令进行应用的安装和卸载&#xff0c;可参考多HAP的调试流程。 图1 应用程序包安装和卸载流程&#xff08;开发者&#xff09; 多HAP的开发调试与发布部署流程 多HAP的开发调试与发布部署流程如下图所示。 图1 多HAP的开发调试与发布部署流程 …

leetcode 3.反转链表;

1.题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 2.用例&#xff1a; 3.题目解析&#xff1a; &#xff08;1&#xff09;函数头&#xff1a; 要求返回结点&#xff0c;就 ListNode* reverseList(ListNode* head)&…

代码随想录算法训练营day60 || 647.回文子串,516. 最长回文子序列

动态规划&#xff0c;字符串性质决定了DP数组的定义 | LeetCode&#xff1a;647.回文子串_哔哩哔哩_bilibili 动态规划再显神通&#xff0c;LeetCode&#xff1a;516.最长回文子序列_哔哩哔哩_bilibili 647.回文子串 // 时间复杂度O(n^2) // 空间复杂度O(n^2) class Solution …

R语言空间分析、模拟预测与可视化

随着地理信息系统&#xff08;GIS&#xff09;和大尺度研究的发展&#xff0c;空间数据的管理、统计与制图变得越来越重要。R语言在数据分析、挖掘和可视化中发挥着重要的作用&#xff0c;其中在空间分析方面扮演着重要角色&#xff0c;与空间相关的包的数量也达到130多个。在本…

Redis的发布订阅功能教程,实现实时消息和key过期事件通知功能

Redis的发布订阅 Redis的发布/订阅(Pub/Sub)功能是一种消息传递模式,用于实现消息发布者(publisher)和订阅者(subscriber)之间的消息通信。在这种模式下,消息的发送者(发布者)将消息发送到特定的频道(channel),而订阅了该频道的接收者(订阅者)将会接收到这些消息…

gprMax3.0随机介质建模

此处利用gprMax建立随机介质模型,采用matlab生成随机数组,保存为HDF5文件,此处为全代码,无需修改即可运行。在gprMax输入文件中使用#geometry_objects_read:读入自定义的随机模型 此文参考其他博主的自定义几何形状模块gprMax3.0建模时如何自定义目标的几何形状_#geomet…

Baby_enc-攻防世界-MISC

题目描述&#xff1a; 下载得到enc.py和out.txt&#xff0c;分别是加密算法和结果。先看enc.py&#xff1a; import codecs def enc(s, t):if t:l list(map(ord, s))return enc(.join(list(map(chr, [l[i]^l[i1] for i in range(len(l)-1)]))), t-1)else:return swith open(i…

trie树(前缀树)

前缀树 1. 前缀树的的介绍2.前缀树的实现2.1插入功能2.2删除功能2.3查找前缀和查找单词功能2.4 哈希表版本 1. 前缀树的的介绍 在计算机科学中&#xff0c;trie&#xff0c;又称前缀树或字典树&#xff0c;是一种有序树&#xff0c;用于保存关联数组&#xff0c;其中的键通常是…

Stable Diffusion 模型分享:【Checkpoint】YesMix(动漫、2.5D)

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四下载地址模型介绍 条目内容类型大模型基础模型SD 1.5来源

C语言第三十二弹---自定义类型:联合和枚举

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 目录 1、联合体 1.1、联合体类型的声明 1.2、联合体的特点 1.3、相同成员的结构体和联合体对比 1.4、联合体大小的计算 1.5、联合的⼀个练习 2、枚举类型 …