news 2026/4/16 16:25:46

[Linux]学习笔记系列 -- [drivers][bus]simple-pm-bus

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Linux]学习笔记系列 -- [drivers][bus]simple-pm-bus

title: simple-pm-bus
categories:

  • linux
  • drivers
  • bus
    tags:
  • linux
  • drivers
  • bus
    abbrlink: b441a160
    date: 2025-10-16 15:36:50

https://github.com/wdfk-prog/linux-study

文章目录

  • drivers/bus/simple-pm-bus.c 简单电源管理总线(Simple PM Bus) 通用的、轻量级的设备电源管理协调器
      • 历史与背景
        • 这项技术是为了解决什么特定问题而诞生的?
        • 它的发展经历了哪些重要的里程碑或版本迭代?
        • 目前该技术的社区活跃度和主流应用情况如何?
      • 核心原理与设计
        • 它的核心工作原理是什么?
        • 它的主要优势体现在哪些方面?
        • 它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
      • 使用场景
        • 在哪些具体的业务或技术场景下,它是首选解决方案?
        • 是否有不推荐使用该技术的场景?为什么?
      • 对比分析
        • 请将其 与 其他相似技术 进行详细对比。
    • Simple Power-Managed Bus Driver
      • 实现原理分析
      • 代码分析

drivers/bus/simple-pm-bus.c 简单电源管理总线(Simple PM Bus) 通用的、轻量级的设备电源管理协调器

历史与背景

这项技术是为了解决什么特定问题而诞生的?

simple-pm-bus的诞生是为了解决在复杂的片上系统(SoC)中一个常见的、但缺乏标准化解决方案的问题:如何以一种通用、有序的方式管理一组相互关联的、但又不属于任何标准总线(如I2C, SPI)的设备的电源状态(主要是休眠与唤醒)

在许多SoC设计中,存在大量简单的、直接挂在内存映射I/O(MMIO)上的设备。这些设备可能在逻辑上属于一个功能单元(例如,一个视频处理流水线上的多个IP核),它们需要按照特定的顺序进入休眠(suspend)或从中恢复(resume)。

simple-pm-bus出现之前,处理这种情况通常依赖于:

  • 平台代码中的硬编码:在板级支持文件(board file)中硬编码休眠/唤醒的调用顺序,这使得代码难以移植和维护。
  • 驱动间的隐式依赖:驱动程序之间通过msleep等脆弱的方式来猜测和等待其他设备的状态。

simple-pm-bus提供了一个轻量级的、基于设备树的虚拟总线,专门用于解决这个问题。它允许开发者将一组设备“聚合”在一起,并保证在系统级的休眠/唤醒流程中,这些设备会按照它们在设备树中声明的顺序被同步地有序地休眠和唤醒。

它的发展经历了哪些重要的里程碑或版本迭代?

simple-pm-bus是由内核开发者 Linus Walleij 引入的,作为对内核电源管理(PM)框架的一个补充。它的发展是增量式的:

  1. 核心概念实现:最初的版本实现了其核心功能——创建一个虚拟总线,并在总线的回调函数中,按照设备注册的顺序来调用每个子设备的PM回调。
  2. genpd的集成:一个重要的演进是它与通用电源域(Generic Power Domains,genpd)框架的集成。这使得simple-pm-bus不仅能协调设备的软件休眠状态,还能协同管理它们所依赖的硬件电源域的开关。
  3. 异步支持的考量与放弃:社区曾讨论过是否为simple-pm-bus添加异步的休眠/唤醒能力。但最终的结论是,这个总线的核心价值就在于其简单性和保证的顺序性,而异步处理会破坏这一点,且对于真正需要异步的复杂场景,已有其他更好的解决方案(如设备链接device_link)。
目前该技术的社区活跃度和主流应用情况如何?

simple-pm-bus是一个相对“小众”但非常实用的内核组件。它不像I2C或USB总线那样被普遍知晓,但在嵌入式和SoC领域,它是一个解决特定问题的标准工具。

  • 应用情况:在ARM、ARM64等平台的设备树(DTS)文件中,经常可以看到simple-pm-bus的身影,用于组织那些没有标准总线接口的MMIO设备。
  • 社区状态:该代码非常稳定和成熟,改动很少。

核心原理与设计

它的核心工作原理是什么?

simple-pm-bus的核心是一个**“代理”或“直通(passthrough)”总线**。它自身不实现任何复杂的硬件协议,而是利用VFS和设备模型的框架来协调和转发电源管理事件。

  1. 设备树声明:一切始于设备树。开发者会创建一个节点,其compatible属性为"simple-pm-bus"。所有需要被该总线管理的设备,都作为这个节点的子节点来声明。子节点在DTS文件中的物理顺序,就决定了它们被处理的顺序
  2. 总线驱动注册simple-pm-bus.c中实现了一个平台驱动程序。当内核解析设备树并找到一个simple-pm-bus节点时,这个驱动的probe函数会被调用。
  3. 虚拟总线创建probe函数的主要任务是创建一个struct bus_type的实例,这是一个代表simple-pm-bus的虚拟总线。
  4. PM回调的实现:这个虚拟总线的关键在于它自己定义了suspendresume回调函数。
  5. 有序的事件转发
    • 当系统休眠时:内核电源管理核心会调用simple-pm-bussuspend回调。这个回调函数会按照与设备注册时相反的顺序(后注册的先休眠),遍历所有挂在该总线上的子设备,并依次调用它们各自驱动程序的suspend回调。
    • 当系统唤醒时:过程相反。simple-pm-busresume回调会按照设备注册时的顺序(先注册的先唤醒),依次调用子设备的resume回调。

通过这种方式,simple-pm-bus利用设备模型固有的父子关系和注册顺序,以极低的成本实现了一个有序的PM事件协调器。

它的主要优势体现在哪些方面?
  • 保证执行顺序:这是其核心价值。它为一组设备的休眠/唤醒提供了严格的、可预测的顺序保证。
  • 简单性:实现非常简单,代码量小,易于理解。它不引入任何新的复杂概念。
  • 基于设备树:将设备间的PM依赖关系以一种声明式的方式固化在设备树中,使得硬件描述与驱动代码解耦,提高了可移植性。
  • 同步执行:其同步执行模型对于那些必须等待前一个设备完全休眠/唤醒后才能进行下一步操作的场景,是非常简单和可靠的。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
  • 严格的同步模型:其最大的优势也是其最大的局限性。它不支持并行/异步的休眠和唤醒,因此可能会拖慢整个系统的休眠/唤醒速度。
  • 功能单一:它只处理电源管理。它不是一个通用的总线,不提供设备间的通信、中断处理或DMA等功能。
  • 不处理运行时PMsimple-pm-bus主要关注系统级的休眠/唤醒(suspend/resume)。虽然它可以与运行时PM(Runtime PM)共存,但它本身不提供复杂的运行时PM协调逻辑。

使用场景

在哪些具体的业务或技术场景下,它是首选解决方案?

当满足以下所有条件时,simple-pm-bus是首选解决方案:

  • 你有一组没有标准硬件总线的设备(通常是MMIO设备)。
  • 这些设备在系统进入或退出全局休眠状态时,必须按照一个严格的顺序进行休眠或唤醒。
  • 这个顺序是静态的,可以在设备树中预先定义。
  • 不需要并行处理来加速休眠/唤醒过程。

示例
一个视频编码SoC包含三个IP核:一个图像缩放器(Scaler),一个颜色空间转换器(CSC),和一个H.264编码器(Encoder)。它们形成一个流水线。在系统休眠时,必须先关闭Encoder,再关闭CSC,最后关闭Scaler。唤醒时顺序相反。
在设备树中,可以这样描述:

video_pipeline: video-pipeline { compatible = "simple-pm-bus"; #address-cells = <1>; #size-cells = <1>; ranges; scaler@1000 { compatible = "vendor,scaler"; reg = <0x1000 0x100>; }; csc@2000 { compatible = "vendor,csc"; reg = <0x2000 0x100>; }; encoder@3000 { compatible = "vendor,encoder"; reg = <0x3000 0x100>; }; };

在这种配置下,simple-pm-bus会确保唤醒时scaler->csc->encoderresume顺序,休眠时encoder->csc->scalersuspend顺序。

是否有不推荐使用该技术的场景?为什么?
  • 需要高性能并行处理:如果一组设备的休眠/唤醒可以并行进行以加速系统状态转换,那么simple-pm-bus的强制串行模型会成为瓶颈。在这种情况下,应该让这些设备独立存在,并依赖内核的通用异步机制。
  • 设备间有复杂的运行时依赖:如果设备A的运行时PM状态依赖于设备B的状态(例如,A只有在B处于Active状态时才能被唤醒),那么应该使用更强大的**设备链接(Device Links)**机制,它专门用于管理设备间的运行时依赖。
  • 设备属于标准总线:如果设备挂在I2C, SPI, USB等标准总线之上,那么应该使用这些总线自身的电源管理规范,而不是simple-pm-bus

对比分析

请将其 与 其他相似技术 进行详细对比。

simple-pm-busvs. 设备链接 (Device Links)

特性simple-pm-bus设备链接 (Device Links)
功能概述一个虚拟总线,用于在系统休眠/唤醒期间,保证一组设备按顺序被回调。一个点对点的依赖关系描述。它声明一个设备(consumer)依赖于另一个设备(supplier)。
主要解决的问题静态的、有序的系统级PM回调。动态的、运行时的PM依赖。确保supplier在consumer需要它之前被唤醒,在consumer不再需要它之后才休眠。
工作时机系统休眠/唤醒(suspend/resume)。运行时PM(runtime_suspend/runtime_resume) 和系统休眠/唤醒
依赖模型多对一(总线)。多个设备属于同一个总线,共享一个顺序。一对一(链接)。可以构建复杂的依赖图(DAG)。
配置方式在设备树中通过父子节点关系隐式定义顺序通过设备树中的power-domainsclocks等属性自动创建,或通过device_link_add()API显式创建
适用场景硬件流水线等需要在系统休眠时严格按顺序开关的场景。驱动A需要确保驱动B的设备(如时钟、电源)已经开启后才能继续工作的场景。

Simple Power-Managed Bus Driver

本代码片段展示了一个名为simple-pm-bus平台设备驱动(platform driver)。其核心功能是为那些本身没有复杂硬件、主要作为其他设备“容器”的简单总线设备(如simple-bus),提供一个通用的、基于时钟管理的运行时电源管理(Runtime PM)框架。当总线下的所有子设备都进入空闲状态时,此驱动会自动禁用(gate)总线的所有时钟以节省功耗;当任何一个子设备需要被访问时,它又会自动重新使能这些时钟。

实现原理分析

此驱动是 Linux 内核中一个典型的“胶水层”和“基础设施”驱动,它为一类设备提供了通用的行为,其原理基于设备树、平台驱动模型和运行时电源管理框架。

  1. 设备匹配与驱动绑定:

    • simple_pm_bus_of_match数组定义了此驱动会尝试绑定的设备。它通过compatible字符串来匹配设备树中的节点。
    • 核心目标:.compatible = "simple-pm-bus"。任何在设备树中明确标记为simple-pm-bus的节点,都是此驱动的主要服务对象。
    • 透明总线处理: 它也匹配simple-bus,simple-mfd等。但对于这些设备,它设置了.data = ONLY_BUS。在probe函数中,有一个复杂的逻辑if (match && match->data),其效果是:如果一个设备匹配的是这些“透明总线”,并且这个驱动是其最精确的匹配项(of_property_match_string(...) == 0),那么probe函数就什么也不做,直接返回成功。这是一种“占位”行为,确保了这些总线设备有一个驱动与之绑定(满足设备模型的完整性),但将实际的电源管理等任务留给它们自己的驱动(如果存在的话)。
  2. probe函数的核心逻辑:

    • 当一个真正的simple-pm-bus设备被探测到时:
      a.获取时钟:devm_clk_bulk_get_all是一个关键函数。它会自动解析设备树中与该总线节点关联的所有clocks属性,并获取这些时钟的句柄。
      b.使能 Runtime PM:pm_runtime_enable(&pdev->dev)激活了内核的运行时电源管理框架。此后,内核会开始自动跟踪该总线设备及其所有子设备的“使用计数”(usage count)。
      c.填充子设备:of_platform_populate(np, NULL, lookup, &pdev->dev)是另一个核心步骤。它会解析当前总线节点的所有子节点,并为每个子节点动态地创建和注册一个新的平台设备。这使得这些子设备能够被它们自己的驱动程序所探测和绑定。
  3. 运行时电源管理 (simple_pm_bus_pm_ops):

    • 此驱动通过.pm字段,将其电源管理操作集simple_pm_bus_pm_ops注册到内核。
    • runtime_suspend: 当内核的 Runtime PM 框架检测到该总线及其所有子设备都已空闲(使用计数降为 0),并且过了自动挂起的延迟时间后,它会自动调用simple_pm_bus_runtime_suspend。此函数的核心是clk_bulk_disable_unprepare,它会关闭之前获取的所有时钟。
    • runtime_resume: 当任何一个子设备(或总线自身)需要被访问(例如,用户空间open一个子设备文件,导致其驱动的probe被调用),内核会首先自动调用父总线的simple_pm_bus_runtime_resume。此函数的核心是clk_bulk_prepare_enable,它会重新使能所有时钟,确保总线和子设备能够正常工作。

代码分析

// ... (包含的头文件) ...// 驱动的私有数据结构,用于存储获取到的时钟信息。structsimple_pm_bus{structclk_bulk_data*clks;intnum_clks;};/** * @brief simple_pm_bus_probe - 驱动的 probe 函数,当匹配的设备被发现时调用。 * @param pdev: 指向平台设备的指针。 * @return int: 成功返回0,失败返回错误码。 */staticintsimple_pm_bus_probe(structplatform_device*pdev){// ... (变量定义) ...// 特殊情况处理:如果使用了 driver_override,则不执行任何操作,直接返回。if(pdev->driver_override)return0;match=of_match_device(dev->driver->of_match_table,dev);// 特殊情况处理:如果匹配的是 "simple-bus" 等透明总线,并且是最佳匹配,则不执行任何操作。if(match&&match->data){if(of_property_match_string(np,"compatible",match->compatible)==0)return0;elsereturn-ENODEV;}// 为驱动的私有数据分配内存 (使用 devm_kzalloc,可自动释放)。bus=devm_kzalloc(&pdev->dev,sizeof(*bus),GFP_KERNEL);if(!bus)return-ENOMEM;// 获取设备树中定义的所有时钟。bus->num_clks=devm_clk_bulk_get_all(&pdev->dev,&bus->clks);if(bus->num_clks<0)returndev_err_probe(&pdev->dev,bus->num_clks,"failed to get clocks\n");// 将私有数据与设备关联起来。dev_set_drvdata(&pdev->dev,bus);dev_dbg(&pdev->dev,"%s\n",__func__);// 启用此设备的运行时电源管理。pm_runtime_enable(&pdev->dev);// 如果设备来自设备树,则解析其子节点并为它们创建平台设备。if(np)of_platform_populate(np,NULL,lookup,&pdev->dev);return0;}/** * @brief simple_pm_bus_remove - 驱动的 remove 函数,当设备被移除时调用。 * @param pdev: 指向平台设备的指针。 */staticvoidsimple_pm_bus_remove(structplatform_device*pdev){// 对于透明总线或 driver_override 的情况,不执行任何操作。if(pdev->driver_override||data)return;dev_dbg(&pdev->dev,"%s\n",__func__);// 禁用此设备的运行时电源管理。pm_runtime_disable(&pdev->dev);}/** * @brief simple_pm_bus_runtime_suspend - 运行时挂起回调。 * @param dev: 指向设备的指针。 * @return int: 始终返回0。 */staticintsimple_pm_bus_runtime_suspend(structdevice*dev){structsimple_pm_bus*bus=dev_get_drvdata(dev);// 关闭(unprepare & disable)所有关联的时钟。clk_bulk_disable_unprepare(bus->num_clks,bus->clks);return0;}/** * @brief simple_pm_bus_runtime_resume - 运行时恢复回调。 * @param dev: 指向设备的指针。 * @return int: 成功返回0,失败返回错误码。 */staticintsimple_pm_bus_runtime_resume(structdevice*dev){structsimple_pm_bus*bus=dev_get_drvdata(dev);intret;// 使能(prepare & enable)所有关联的时钟。ret=clk_bulk_prepare_enable(bus->num_clks,bus->clks);if(ret){dev_err(dev,"failed to enable clocks: %d\n",ret);returnret;}return0;}// ... (系统级 suspend/resume 的包装函数) ...// 定义驱动的电源管理操作集。staticconststructdev_pm_opssimple_pm_bus_pm_ops={RUNTIME_PM_OPS(simple_pm_bus_runtime_suspend,simple_pm_bus_runtime_resume,NULL)NOIRQ_SYSTEM_SLEEP_PM_OPS(simple_pm_bus_suspend,simple_pm_bus_resume)};// 定义一个标记,用于标识仅作为总线的匹配项。#defineONLY_BUS((void*)1)// 定义驱动的 OF (设备树) 匹配表。staticconststructof_device_idsimple_pm_bus_of_match[]={{.compatible="simple-pm-bus",},{.compatible="simple-bus",.data=ONLY_BUS},{.compatible="simple-mfd",.data=ONLY_BUS},{.compatible="isa",.data=ONLY_BUS},{.compatible="arm,amba-bus",.data=ONLY_BUS},{/* sentinel */}};MODULE_DEVICE_TABLE(of,simple_pm_bus_of_match);// 定义平台驱动结构体。staticstructplatform_driversimple_pm_bus_driver={.probe=simple_pm_bus_probe,.remove=simple_pm_bus_remove,.driver={.name="simple-pm-bus",.of_match_table=simple_pm_bus_of_match,.pm=pm_ptr(&simple_pm_bus_pm_ops),// 关联电源管理操作},};// 使用模块宏来注册平台驱动。module_platform_driver(simple_pm_bus_driver);// 模块元数据MODULE_DESCRIPTION("Simple Power-Managed Bus Driver");MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 16:07:47

动手实测YOLOv13:三行代码实现高精度目标识别

动手实测YOLOv13&#xff1a;三行代码实现高精度目标识别 在智慧物流分拣中心的高速传送带上&#xff0c;每分钟经过200件包裹&#xff0c;传统检测系统面对叠放、反光、遮挡等复杂工况频频漏检&#xff1b;而在城市交通监控大屏前&#xff0c;暴雨夜中模糊的车牌与低光照下的…

作者头像 李华
网站建设 2026/4/15 17:41:44

智能家居中i2s音频接口设计:完整指南

以下是对您提供的博文《智能家居中I2S音频接口设计&#xff1a;完整技术分析指南》的 深度润色与专业重构版本 。本次优化严格遵循您的全部要求&#xff1a; ✅ 彻底去除AI痕迹&#xff0c;语言自然、有“人味”——像一位十年嵌入式音频系统工程师在技术分享会上娓娓道来&a…

作者头像 李华
网站建设 2026/4/16 15:55:13

电商推荐系统实战:用PyTorch-2.x-Universal-Dev-v1.0快速实现模型训练

电商推荐系统实战&#xff1a;用PyTorch-2.x-Universal-Dev-v1.0快速实现模型训练 1. 为什么电商推荐系统值得你花10分钟上手 你有没有想过&#xff0c;当用户在电商平台上浏览商品时&#xff0c;那些精准出现在首页的“猜你喜欢”、购物车页面的“买了又买”、结算页的“搭配…

作者头像 李华
网站建设 2026/4/16 9:05:04

如何优化YOLOE推理速度?几个实用技巧分享

如何优化YOLOE推理速度&#xff1f;几个实用技巧分享 YOLOE&#xff08;Real-Time Seeing Anything&#xff09;作为新一代开放词汇目标检测与分割模型&#xff0c;以“零样本迁移实时推理”双优势迅速在工业场景中崭露头角。但很多工程师在实际部署时发现&#xff1a;明明文档…

作者头像 李华
网站建设 2026/4/16 15:54:59

轻量嵌入模型怎么选?Qwen3-Embedding-0.6B给出答案

轻量嵌入模型怎么选&#xff1f;Qwen3-Embedding-0.6B给出答案 1. 为什么轻量嵌入模型正在成为新刚需&#xff1f; 你有没有遇到过这样的情况&#xff1a; 想给一个中小规模知识库快速配上语义搜索&#xff0c;但发现8B模型在4卡A10上跑得吃力&#xff0c;显存占用超95%&…

作者头像 李华
网站建设 2026/4/16 14:28:20

零基础也能用!BSHM人像抠图镜像一键部署,实测效果惊艳

零基础也能用&#xff01;BSHM人像抠图镜像一键部署&#xff0c;实测效果惊艳 你是不是也遇到过这些情况&#xff1a; 想给产品图换背景&#xff0c;但PS抠图太费时间&#xff1b; 做短视频需要透明人像&#xff0c;可专业软件学不会&#xff1b; 设计师朋友说“这个边缘要精细…

作者头像 李华