linux 6.10.0 CXL/reg.c 详解

文章目录

    • 前言
    • Ref
    • 正文
      • 1. cxl_setup_regs
      • 2. cxl_probe_regs()
      • 3. cxl_probe_component_regs()
      • 4. cxl_probe_device_regs()
      • 5. cxl_map_device_regs()
      • 6. cxl_count_regblock() / cxl_find_regblock_instance()

前言

CXL 是一个比较新的技术,内核版本迭代太快,跟不上节奏,固定一个版本是不行了。

在阅读之前,希望读者能有一定的 PCIe/CXL 基础知识,精力有限,不能把所有知识点都能说的很详细,需要一定的基础才能理解,同时,希望在学习的过程中,手边能有 PCIe Spec 以及 CXL 2.0 /3.1 Spec,以便随时查看,当然,我也会尽量把重点的部分截图在博文中。

最后,如果有问题请留言讨论。

Ref

《PCI_Express_Base_5.0r1.0》
《CXL Specification_rev2p0_ver1p0_2020Oct26》
《CXL-3.1-Specification》

正文

1. cxl_setup_regs

int cxl_setup_regs(struct cxl_register_map *map)
{int rc;// 对 map 所代表的寄存器块进行物理地址到虚拟地址的映射,大小到 bar 空间尾部rc = cxl_map_regblock(map);if (rc)return rc;// 获取寄存器块的信息, 位置,大小等rc = cxl_probe_regs(map);// 解除映射cxl_unmap_regblock(map);return rc;
}

2. cxl_probe_regs()

static int cxl_probe_regs(struct cxl_register_map *map)
{struct cxl_component_reg_map *comp_map;struct cxl_device_reg_map *dev_map;struct device *host = map->host;void __iomem *base = map->base;// 根据寄存器块的类型进行处理switch (map->reg_type) {case CXL_REGLOC_RBI_COMPONENT:// 处理 component Registercomp_map = &map->component_map;// 下文分析,主要获取寄存器id, 位置和大小信息保存在 comp_map 中cxl_probe_component_regs(host, base, comp_map);dev_dbg(host, "Set up component registers\n");break;case CXL_REGLOC_RBI_MEMDEV:// 处理 CXL Memory Device Register// 找到的寄存器组地址和大小信息保存在 dev_map 中dev_map = &map->device_map;cxl_probe_device_regs(host, base, dev_map);if (!dev_map->status.valid || !dev_map->mbox.valid ||!dev_map->memdev.valid) {dev_err(host, "registers not found: %s%s%s\n",!dev_map->status.valid ? "status " : "",!dev_map->mbox.valid ? "mbox " : "",!dev_map->memdev.valid ? "memdev " : "");return -ENXIO;}dev_dbg(host, "Probing device registers...\n");break;default:break;}return 0;
}

3. cxl_probe_component_regs()

// 探测 CXL 组件寄存器块, 找到设备中的 HDM Decoder 寄存器并记录位置和大小
// dev : CXL 设备文件
// base : 包含 HDM 解码能力头的映射基地址,就是寄存器块所在位置的基地址,已映射后的虚拟地址
// map : 描述发现的寄存器块信息的对象
// Ref CXL 2.0r     8.1.9 Register Locator DVSEC
//                  8.2.5 CXL.cache and CXL.mem Registers
void cxl_probe_component_regs(struct device *dev, void __iomem *base,struct cxl_component_reg_map *map)
{int cap, cap_count;u32 cap_array;*map = (struct cxl_component_reg_map) { 0 };/** CXL.cache and CXL.mem registers are at offset 0x1000 as defined in* CXL 2.0 8.2.4 Table 141. 如上图*/// CXL_CM_OFFSET 0x1000// CXL_CM_OFFSET 偏移处为 .cache 和 .mem 的寄存器位置base += CXL_CM_OFFSET;cap_array = readl(base + CXL_CM_CAP_HDR_OFFSET);// 见下图 CXL.cache and CXL.mem Architectural Register Header// 或Ref CXL 2.0 8.2.5.1 CXL Capability Header Register// CXL Capability Header Register 的 CXL_Capability_ID (0:15) 必须为 1,不为 1 报错// #define   CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0)// #define     CM_CAP_HDR_CAP_ID 1if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) {dev_err(dev,"Couldn't locate the CXL.cache and CXL.mem capability array header.\n");return;}/* It's assumed that future versions will be backward compatible */// 见下图 CXL.cache and CXL.mem Architectural Register Header// 或Ref CXL 2.0 8.2.5.1 CXL Capability Header Register// 31:24 Array_Size 定义了存在的元素数目// #define   CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)cap_count = FIELD_GET(CXL_CM_CAP_HDR_ARRAY_SIZE_MASK, cap_array);// 遍历,每个元素 4 个字节,首个DWORD 为头,略过for (cap = 1; cap <= cap_count; cap++) {void __iomem *register_block;u32 hdr;int decoder_cnt;u16 cap_id, offset;u32 length;hdr = readl(base + cap * 0x4);// 读 Capability Header id 与偏移cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr);offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr);register_block = base + offset;// Ref CXL 2.0 8.2.5.5 CXL HDM Decoder Capability Header// 或上图 CXL HDM Decoder Capability Header// CXL_CM_CAP_CAP_ID_HDM == 0x5// 只处理 HDM Decoder Registersswitch (cap_id) {case CXL_CM_CAP_CAP_ID_HDM:// #define   CXL_CM_CAP_CAP_ID_HDM 0x5// 8.2.5.5 CXL HDM Decoder Capability Header, 如下图// CXL_Capability_ID 为 5 dev_dbg(dev, "found HDM decoder capability (0x%x)\n",offset);// 先读 4 字节// 8.2.5.12.1 CXL HDM Decoder Capability Register (Offset 00h)hdr = readl(register_block);// Ref 下图 CXL HDM Decoder Capability Structure// or CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure// 根据 bit 3:0 获取 number of memory address decodersdecoder_cnt = cxl_hdm_decoder_count(hdr);// 8.2.5.12 CXL HDM Decoder Capability Structure// 长度计算公式,设备的是 0x20 * decoder_cnt + 0x10length = 0x20 * decoder_cnt + 0x10;rmap = &map->hdm_decoder;break;// ID 为 2case CXL_CM_CAP_CAP_ID_RAS:// #define   CXL_CM_CAP_CAP_ID_RAS 0x2// 8.2.5.2 CXL RAS Capability Headerdev_dbg(dev, "found RAS capability (0x%x)\n",offset);// 长度包括0x18 的寄存器,最后一个寄存器是日志寄存器,包括 0x40 个字节的日志,共 0x58(CXL_RAS_CAPABILITY_LENGTH)length = CXL_RAS_CAPABILITY_LENGTH;rmap = &map->ras;break;default:dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id,offset);break;}if (!rmap)continue;// 保存内容rmap->valid = true;rmap->id = cap_id;rmap->offset = CXL_CM_OFFSET + offset;rmap->size = length;}
}
EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL);

CXL.cache and CXL.mem Architectural Register Header
请添加图片描述

CXL HDM Decoder Capability Header
请添加图片描述

CXL HDM Decoder Capability Structure
请添加图片描述

4. cxl_probe_device_regs()


// 探测 CXL 设备寄存器块,记录位置及大小
// dev :  CXL 设备内核对象
// base : 寄存器块 CXL Device Register interface 所在位置的基地址,已映射后的虚拟地址
// map : 描述发现的寄存器块信息的对象
void cxl_probe_device_regs(struct device *dev, void __iomem *base,struct cxl_device_reg_map *map)
{int cap, cap_count;u64 cap_array;*map = (struct cxl_device_reg_map){ 0 };cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET);// 由下图 Figure 138. CXL Memory Device Registers 知// 偏移为 CXLDEV_CAP_ARRAY_OFFSET(0) 是 CXL Device Capabilities Array Register 寄存器// Ref CXL 2.0 8.2.8 CXL Device Register Interfaceif (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) !=CXLDEV_CAP_ARRAY_CAP_ID)// Cap ID 必须为 CXLDEV_CAP_ARRAY_CAP_ID(0)// 如下图 CXL Device Capabilities Array Register// Ref CXL 2.0 CXL Device Capabilities Array Register : Capability IDreturn;cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);// 同样,获得元素 Capabilities 数量, [47:32], 每个元素头 16 字节,并前后连续// cap_count 不包括 CXL Device Capability Header Register,第一个headerfor (cap = 1; cap <= cap_count; cap++) {// 进行遍历,从 1 开始,地址跳过 CXL Device Capabilities Array Register, 占 0x10 字节struct cxl_reg_map *rmap;u32 offset, length;u16 cap_id;cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK,readl(base + cap * 0x10));offset = readl(base + cap * 0x10 + 0x4);length = readl(base + cap * 0x10 + 0x8);// 每个 Capabilities 长度 16字节 // Ref CXL 2.0r 8.2.8.1 CXL Device Capabilities Array Register : Capabilities Count// 获取 cap_id[15:0], offset[63:32], lenth[95:64]// Ref CXL 2.0r 8.2.8.2 CXL Device Capability Header Register// or 如下图 CXL Device Capability Header Registerswitch (cap_id) {// 根据 id 做不同记录处理// 不过都是记录偏移和大小以及生效标志// 如下图 CXL Device Capabilities, 分别取 1, 2, 3// CXL Memeory Device 必须要有 1 和 2// Ref CXL 2.0 8.2.8.2.1 CXL Device Capabilitiescase CXLDEV_CAP_CAP_ID_DEVICE_STATUS:// 1dev_dbg(dev, "found Status capability (0x%x)\n", offset);rmap = &map->status;break;case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:// 2dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);rmap = &map->mbox;break;case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX:// 3dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset);break;case CXLDEV_CAP_CAP_ID_MEMDEV:// 4000h// 8.2.8.5 Memory Device Registers// CXL Memeory Device 必须要有dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset);rmap = &map->memdev;break;default:// 0000h - 3FFFFh 描述通用 CXL 设备能力// 4000h - 7FFFFh 描述与PCI头(offset 09h)中 class code register 相关的特定能力// 8000h - FFFFh 描述 vedndor specific capabilitiesif (cap_id >= 0x8000)dev_dbg(dev, "Vendor cap ID: %#x offset: %#x\n", cap_id, offset);elsedev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset);break;}if (!rmap)continue;// 保存 id, offset, length 到 map 相应字段rmap->valid = true;rmap->id = cap_id;rmap->offset = offset;rmap->size = length;}
}
EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL);

CXL Memory Device Registers
请添加图片描述

CXL Device Capabilities Array Register
请添加图片描述

CXL Device Capability Header Register
请添加图片描述

CXL Device Capabilities
请添加图片描述

5. cxl_map_device_regs()

// 映射设备寄存器,.io 寄存器块
int cxl_map_device_regs(struct pci_dev *pdev,struct cxl_device_regs *regs,struct cxl_register_map *map)
{struct device *host = map->host;resource_size_t phys_addr = map->resource;// phys_addr 是 CXL memory device 寄存器组的物理首地址struct mapinfo {const struct cxl_reg_map *rmap;void __iomem **addr;} mapinfo[] = {{ &map->device_map.status, &regs->status, },{ &map->device_map.mbox, &regs->mbox, },{ &map->device_map.memdev, &regs->memdev, },};// 组成一个数组,方便管理int i;for (i = 0; i < ARRAY_SIZE(mapinfo); i++) {struct mapinfo *mi = &mapinfo[i];resource_size_t length;resource_size_t addr;if (!mi->rmap->valid)continue;// 对于有效的 CXL device capability registeraddr = phys_addr + mi->rmap->offset;length = mi->rmap->size;// 获取偏移位置和大小*(mi->addr) = devm_cxl_iomap_block(host, addr, length);// devm_cxl_iomap_block 申请空间 [addr, length] 并进行映射,返回虚拟地址保存if (!*(mi->addr))return -ENOMEM;}return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL);

6. cxl_count_regblock() / cxl_find_regblock_instance()


int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type)
{struct cxl_register_map map;int rc, count = 0;while (1) {// 主要函数rc = cxl_find_regblock_instance(pdev, type, &map, count);if (rc)return count;count++;}
}
EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL);/*** cxl_find_regblock_instance() - Locate a register block by type / index* @pdev: The CXL PCI device to enumerate.* @type: Register Block Indicator id* @map: Enumeration output, clobbered on error* @index: Index into which particular instance of a regblock wanted in the*	   order found in register locator DVSEC.** Return: 0 if register block enumerated, negative error code otherwise** A CXL DVSEC may point to one or more register blocks, search for them* by @type and @index.*/
int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,struct cxl_register_map *map, int index)
{u32 regloc_size, regblocks;int instance = 0;int regloc, i;*map = (struct cxl_register_map) {.host = &pdev->dev,.resource = CXL_RESOURCE_NONE,};// 寻找 DVSEC REG LOCATOR// 通过 Table 124 CXL DVSEC ID Assignment DVSEC ID 表可知 Register Locator DVSEC 为 8// Register Locator DVSEC 指示寄存器块的类型和位置// CXL_REGLOC_RBI_PMU 表示 CPMU Registers,在 CXL 2.0r 8.1.9.1 Register Offset Low 15:8 定义// #define CXL_DVSEC_REG_LOCATOR					8regloc = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,CXL_DVSEC_REG_LOCATOR);if (!regloc)return -ENXIO;pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, &regloc_size);regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);regloc += CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET;regblocks = (regloc_size - CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET) / 8;// #define   CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET			0xC// Register Locator DVSEC 布局是 0xc 字节的头 + (n * 8) n是寄存器块的个数// 遍历寄存器块并根据第二个参数 type 去匹配// 同时,对map进行赋值,可获取寄存器块的类型、在哪个BAR空间以及偏移位置、寄存器块最大值// 对于 CXL1.1设备,componenet 寄存器不在bar空间中,需要在RCRB中寻找for (i = 0; i < regblocks; i++, regloc += 8) {u32 reg_lo, reg_hi;pci_read_config_dword(pdev, regloc, &reg_lo);pci_read_config_dword(pdev, regloc + 4, &reg_hi);if (!cxl_decode_regblock(pdev, reg_lo, reg_hi, map))continue;if (map->reg_type == type) {if (index == instance)return 0;instance++;}}map->resource = CXL_RESOURCE_NONE;return -ENODEV;
}
EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, CXL);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/393779.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python爬虫预备知识三-多进程

python实现多进程的方法&#xff1a;fork、multiprocessing模块创建多进程。 os.fork方法 os.fork方法只适合于unix/linux系统&#xff0c;不支持windows系统。 fork方法调用一次会返回两次&#xff0c;原因在于操作系统将当前进程&#xff08;父进程&#xff09;复制出一份…

在Linux中,什么叫做线程

在Linux中&#xff0c;什么叫做线程&#xff1f; CPU调度的基本单位。 在Linux中&#xff0c;什么叫做进程&#xff1f; 内核视角&#xff1a; 承担分配系统资源的基本实体。 一个进程内部可以有多个执行流。 task_struct可以理解为轻量级进程。 线程是进程内部的一个分支…

【python】Python中位运算算法详细解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

数据库扩展新篇章:主流分库分表中间件全解析

摘要&#xff1a; 随着企业数据量的激增&#xff0c;传统的单体数据库架构已经无法满足日益增长的性能需求和数据管理复杂性。分库分表技术作为解决这一问题的有效手段&#xff0c;通过将数据水平或垂直地分散到多个数据库中&#xff0c;提高了系统的扩展性和处理能力。本文将详…

LISA: Reasoning Segmentation via Large Language Model

发表时间&#xff1a;CVPR 2024 论文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2024/papers/Lai_LISA_Reasoning_Segmentation_via_Large_Language_Model_CVPR_2024_paper.pdf 作者单位&#xff1a;CUHK Motivation&#xff1a;尽管感知系统近年来取得了显…

鸡舍环控系统

在现代养殖业中&#xff0c;科技的进步正悄然改变着传统模式&#xff0c;其中&#xff0c;基于物联网和自动控制技术的鸡舍环控系统正逐渐成为行业内的新宠。这套系统不仅能够集成温湿度、光照度等参数的监测与控制&#xff0c;还能通过智能化手段减轻日常养殖工作量&#xff0…

探索 Python 异步通信的奥秘:WebSockets 库的神奇之旅

文章目录 探索 Python 异步通信的奥秘&#xff1a;WebSockets 库的神奇之旅背景&#xff1a;为何选择 WebSockets&#xff1f;什么是 websockets 库&#xff1f;安装 websockets 库5个简单的库函数使用方法场景应用示例常见问题与解决方案总结 探索 Python 异步通信的奥秘&…

sqli-labs-php7-master\Less-1

1&#xff0c;进入mysql数据库 mysql -u root -p 接着&#xff1a; show databases; use security; select * from where id1 LIMIT 0,1; 函数的基本用法 system_user() #当前系统用户 user() #当前登录用户 current_user() #当前登录用…

electron-updater实现electron全量更新和增量更新——主进程部分

同学们可以私信我加入学习群&#xff01; 正文开始 前言更新功能所有文章汇总一、更新插件选择二、在main.js中引入我们的更新模块三、更新模块UpdateController.js暴露的方法checkUpdate四、更新模块UpdateController.js中的监听4.1监听是否有新版本需要更新&#xff1f;4.2 监…

怎样配置虚拟机IP

目录&#xff08;三步走&#xff09; 配置本机IP 配置虚拟机外部IP 配置虚拟机内部IP 参考链接&#xff1a; 配置本机IP 打开“网络和共享中心”——>更改“适配器设置” 找到“VMnet8”&#xff0c;然后右键“属性”&#xff0c;弹出下列窗口 输入本机IP&#xff08;你…

浅谈操作系统

我们前面谈到了一个可执行程序首先会到内存进行预先加载~而在我们的计算机中第一个被加载的软件就是操作系统~ 操作系统的主要工作就是对软硬件资源进行管理~ 这里我们先从操作系统下层开始讲起~ 我们把操作系统类比为校长&#xff0c;驱动程序类比为辅导员&#xff0c;底层硬件…

【学术会议征稿】第四届电气工程与计算机技术国际学术会议(ICEECT2024)

第四届电气工程与计算机技术国际学术会议&#xff08;ICEECT2024&#xff09; 2024 4th International Conference on Electrical Engineering and Computer Technology 第四届电气工程与计算机技术国际学术会议&#xff08;ICEECT2024&#xff09;将于9月27日-29日在哈尔滨举…

吴恩达机器学习COURSE1 WEEK2

COURSE1 WEEK2 多维特征 在线性回归中&#xff0c;往往特征不止一个&#xff0c;而是具有多维特征 例如&#xff0c;在预测房价的例子中&#xff0c;我们知道更多的信息&#xff1a; x 1 x_1 x1​&#xff1a;房屋的面积 x 2 x_2 x2​&#xff1a;卧室的数目 x 3 x_3 x3​&a…

微信小程序 - 自定义计数器 - 优化(键盘输入校验)

微信小程序通过自定义组件&#xff0c;实现计数器值的增加、减少、清零、最大最小值限定、禁用等操作。通过按钮事件触发方式&#xff0c;更新计数器的值&#xff0c;并修改相关联的其它变量。通过提升用户体验&#xff0c;对计数器进行优化设计&#xff0c;使用户操作更加便捷…

蜂窝网络架构

2G/3G 4G eNB RF-RRU eCPRI RRU-BBU 光纤 5G From 38.300 AMF处理信令等&#xff0c;UPF 用户面&#xff0c;后面还有SMF

医院不良事件监测预警上报系统,PHP不良事件管理系统源码

不良事件上报系统&#xff0c;支持医院进行10大类医疗安全&#xff08;不良&#xff09;事件的上报管理&#xff1b;帮助医院管理部门更好把控不良事件的发生趋势&#xff0c;分析医院内部潜在的问题和风险&#xff0c;采取适当的管理措施&#xff0c;有效加强质量控制&#xf…

MySQL总体功能

基于Innodb存储引擎的讨论 MySQL 核心功能 功能解决的问题ACID模型数据并发访问&#xff0c;和奔溃恢复安全问题,一致性&奔溃恢复索引数据查询效率问题备份容错设计,解决硬件错误带来的问题复制数据迁移监控执行数据库操作的异常记录

JavaEE: wait(等待) / notify (通知)

文章目录 wait(等待) / notify (通知)总结 wait(等待) / notify (通知) 线程在操作系统上的调度是随机的~ 那么我们想要控制线程之间执行某个逻辑的先后顺序,那该咋办呢? 可以让后执行的逻辑,使用wait, 先执行的线程,在完成某些逻辑之后,通过notify来唤醒对应的wait. 另外,通…

C++-类与对象基础

一&#xff0c;类的定义 1.1类定义格式 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省略。类体中内容称为mian类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者…

【nginx】centos7安装并配置开机自启

【nginx】配置开机自启 1.nginx配置开机自启 安装完成nginx之后 vim /lib/systemd/system/nginx.service[Unit] Descriptionnginx Afternetwork.target[Service] Typeforking ExecStart/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf ExecReload/usr/loc…