当前位置: 首页 > news >正文

SMMUv3中断处理过程分析(十三)

1.概述

SMMUv3驱动初始化的时候,会注册事件队列中断处理函数、错误中断处理函数和PRIQ中断处理函数。下面分析这些中断处理函数。

2.事件中断

事件中断的处理函数为arm_smmu_evtq_thread。当事件中断发生后,中断处理函数会遍历事件队列,处理每一个事件。处理过程如下:

  1. 从事件队列中取出事件
  2. 从事件中解析Event number,只处理EVT_ID_TRANSLATION_FAULTEVT_ID_ADDR_SIZE_FAULTEVT_ID_ACCESS_FAULTEVT_ID_PERMISSION_FAULT四种类型的事件,其他事件返回 -EOPNOTSUPP
  3. 判断事件中的Stall位是否设置,没有设置直接返回-EOPNOTSUPP,若设置,则继续处理。SMMUv3触发上述四种事件后,必须处于Stall状态,才能让CPU处理IO Page Fault。
  4. 根据触发事件的事务读写属性、特权以及访问类型(指令访问还是数据访问),构造IO Page Fault请求。
  5. 调用iommu_report_device_fault函数上报IO Page Fault事件。
[drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c]
static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
{......do {while (!queue_remove_raw(q, evt)) {  // 循环读取事件u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);ret = arm_smmu_handle_evt(smmu, evt);  // 处理事件if (!ret || !__ratelimit(&rs))continue;......// 不能一直占用CPU处理事件,处理一段事件需要产看是否有调度请求cond_resched();}......} while (!queue_empty(llq));/* Sync our overflow flag, as we believe we're up to speed */queue_sync_cons_ovf(q);return IRQ_HANDLED;
}static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
{......// 解析Event numberswitch (FIELD_GET(EVTQ_0_ID, evt[0])) {case EVT_ID_TRANSLATION_FAULT:case EVT_ID_ADDR_SIZE_FAULT:case EVT_ID_ACCESS_FAULT:case EVT_ID_PERMISSION_FAULT:break;default:return -EOPNOTSUPP;}// SMMU是否处于stall状态if (!(evt[1] & EVTQ_1_STALL))return -EOPNOTSUPP;// 设置导致FAULT的事务是读还是写if (evt[1] & EVTQ_1_RnW)perm |= IOMMU_FAULT_PERM_READ;elseperm |= IOMMU_FAULT_PERM_WRITE;// 判断导致FAULT的事务是指令还是数据if (evt[1] & EVTQ_1_InD)perm |= IOMMU_FAULT_PERM_EXEC;  // 指令// 判断导致FAULT的事务是否有特权模式if (evt[1] & EVTQ_1_PnU)perm |= IOMMU_FAULT_PERM_PRIV;  // 具有特权模式// iommu_fault_type为page request faultflt->type = IOMMU_FAULT_PAGE_REQ;flt->prm = (struct iommu_fault_page_request) {/* 当前页请求是一组相关页请求中的最后一个请求,这个标志在批量* 页请求处理中非常重要。*/.flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,// 设置Page Request Group Index.grpid = FIELD_GET(EVTQ_1_STAG, evt[1]),.perm = perm,  // 权限.addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),  // 导致FAULT的访问地址};if (ssid_valid) {/* 如果是SubstreamID有效,还需要设置PASID有效标志。SMMUv3将PCIe* 设备的PASID设置为SubstreamID*/flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);  // 设置PASID}......// 上报异常ret = iommu_report_device_fault(master->dev, &fault_evt);......
}

3.错误中断

事件中断的处理函数为arm_smmu_gerror_handler。当错误中断发生后,中断处理函数先读取SMMU_()GERROR和SMMU_GERRORN寄存器。SMMU(_)GERROR寄存器保存了错误类型,SMMU_GERRORN寄存器用于响应这些错误。

[drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c]
static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
{......gerror = readl_relaxed(smmu->base + ARM_SMMU_GERROR);gerrorn = readl_relaxed(smmu->base + ARM_SMMU_GERRORN);active = gerror ^ gerrorn;  // 获取当前pending的错误if (!(active & GERROR_ERR_MASK))return IRQ_NONE; /* No errors pending */....../* 表示SMMU进入了Service failure mode,此时SMMU停止地址转换,* 停止执行命令,停止上报事件,响应错误并不会退出Service failure mode,* 如果退出,和具体的实现相关*/if (active & GERROR_SFM_ERR) {dev_err(smmu->dev, "device has entered Service Failure Mode!\n");arm_smmu_device_disable(smmu);}// 报告全局错误的MSI中断写入出现错误,写入错误了中断如何报上来?if (active & GERROR_MSI_GERROR_ABT_ERR)dev_warn(smmu->dev, "GERROR MSI write aborted\n");// PRIQ队列MSI中断写入错误if (active & GERROR_MSI_PRIQ_ABT_ERR)dev_warn(smmu->dev, "PRIQ MSI write aborted\n");// 事件队列MSI中断写入错误if (active & GERROR_MSI_EVTQ_ABT_ERR)dev_warn(smmu->dev, "EVTQ MSI write aborted\n");// 命令队列MSI中断写入错误if (active & GERROR_MSI_CMDQ_ABT_ERR)dev_warn(smmu->dev, "CMDQ MSI write aborted\n");// PRIQ队列写入错误if (active & GERROR_PRIQ_ABT_ERR)dev_err(smmu->dev, "PRIQ write aborted -- events may have been lost\n");// 事件队列写入错误if (active & GERROR_EVTQ_ABT_ERR)dev_err(smmu->dev, "EVTQ write aborted -- events may have been lost\n");// 如果是命令错误,则移动队列的读指针,跳过错误命令if (active & GERROR_CMDQ_ERR)arm_smmu_cmdq_skip_err(smmu);writel(gerror, smmu->base + ARM_SMMU_GERRORN);  // 响应错误return IRQ_HANDLED;
}

4.PRIQ中断

PRI(Page Request Interface)是PCIe规范中定义的一种机制,允许IOMMU(或SMMU)与设备之间进行页请求和页响应的交互。PRIQ(Page Request Interface Queue)是SMMUv3中用于处理PRI消息的队列。PRI机制的主要目的是支持提前为设备分配物理内存,而不是等到IOMMU上报IO Page Fault时分配物理内存,这对高速的PCIe设备提高性能有很大的帮助。

SMMUv3的PRIQ中断处理函数为arm_smmu_priq_thread,可以看出,SMMUv3驱动还没有实现处理PRI的功能,只是简单的回复Page Response。

[drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c]
static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
{......do {while (!queue_remove_raw(q, evt))arm_smmu_handle_ppr(smmu, evt);......} while (!queue_empty(llq));/* Sync our overflow flag, as we believe we're up to speed */queue_sync_cons_ovf(q);return IRQ_HANDLED;
}static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
{......sid = FIELD_GET(PRIQ_0_SID, evt[0]);ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]);ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : IOMMU_NO_PASID;last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]);grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]);......if (last) {struct arm_smmu_cmdq_ent cmd = {.opcode			= CMDQ_OP_PRI_RESP,.substream_valid	= ssv,.pri			= {.sid	= sid,.ssid	= ssid,.grpid	= grpid,.resp	= PRI_RESP_DENY,},};arm_smmu_cmdq_issue_cmd(smmu, &cmd);}
}

参考资料

  1. linux6.12 source code.
  2. Arm ® System Memory Management Unit Architecture Specification version 3.
http://www.dtcms.com/a/436388.html

相关文章:

  • 江西省住房和城乡建设厅官方网站外贸网店
  • wordpress展示页面模板下载信息流广告优化
  • 网站开发 q3687474网站建设需求分析模板
  • 个人网站推广手段有哪些公司网站建设调研背景
  • 公司设计网站定制大庆市建设网站
  • 定制家具网站源代码网页工具大全
  • 北京网站建设签约阜阳市城乡建设局网站
  • 东台建设企业网站cmmi软件开发流程
  • 做百度网站网站排名赚钱吗太原网络项目
  • 在电脑上怎么创建微网站吗手机网页及网站设计 pdf
  • 编写个人网站宜昌市水利建设工程协会网站
  • 程序员参与洗钱网站建设网站源码修复
  • 上海联通 网站备案松江做微网站
  • 做网站公司宣传语公司网络运营团队方案
  • 沭阳各乡镇做网站旅游网站建设目的
  • 个人博客系统测手动试报告
  • 石狮网站上海市做网站
  • 手机网站 wordpresswordpress acg站
  • 如何建企业仢网站网站建设属于哪类工作
  • 城乡建设局网站首页wordpress怎么创建目录页面
  • 怎么用ftp修改网站html5网站代理
  • 河南网站备案地址个人网站名称备案
  • 备案时网站名称可以重复吗嘉兴官网
  • 东莞快速建站平台中国海洋大学做英语作业的网站
  • 河南省建设厅网站上海到北京飞机几个小时
  • 贵阳seo网站管理乐清市规划图高清
  • 河南省建设科技网站广州天河 网站建设
  • 基于 SpringBoot 的在线学习过程管理系统软件的设计与实现(代码+数据库+LW)
  • 98. 可达路径
  • 外卖网站 模板wordpress获取分类名称