PCIe学习笔记(1)Hot-Plug机制

文章目录

  • Hot-Plug Init
  • Hot Add Flow
  • Surprise Remove Flow
  • NPEM Flow

Hot-Plug Init

PCIe hot-plug是一种支持在不关机情况下从支持的插槽添加或删除设备的功能,PCIe架构定义了一些寄存器以支持原生热插拔。相关寄存器主要分布在Device Capabilities, Slot Capabilities, Slot Control, Slot Status和Slot Capabilities 2。Hot-Plug相关支持寄存器位置如下。
在这里插入图片描述
一个Downstream Port支持以下热插拔事件。

  • Slot Events:
    • Attention Button Pressed
    • Power Fault Detected
    • MRL Sensor Changed
    • Presence Detect Changed
  • Command Completed Events
  • Data Link Layer State Changed Events

主要事件都可以通过寄存器控制使能,需要在初始化时配置启用。如果要启用INTx message,需配置如下:

  • Command register内的Interrupt Disable位需要设为0
  • Slot Control register内的Hot-Plug Interrupt Enable位需要设为1
  • 至少使能一个hot-plug event控制寄存器
    如果要启用MSI/MSI-X,则需取消屏蔽关联向量。PME和Hot-Plug事件中断共享同一向量,由PCIE Capabilities的Interrupt Message Number域段控制。
    在这里插入图片描述

Hot-Plug事件产生需要启用PME_En位。
在这里插入图片描述

Hot Add Flow

主要处理Presence Detect Changed, Command Completed events(需要在No Command Completed Support为0时,否则硬件支持无通知式自动完成)。
pciehp_handle_presence_or_link_change函数为Presence Detect Changed事件中断服务函数。

void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
{int present, link_active;/** If the slot is on and presence or link has changed, turn it off.* Even if it's occupied again, we cannot assume the card is the same.*/mutex_lock(&ctrl->state_lock);switch (ctrl->state) {case BLINKINGOFF_STATE:cancel_delayed_work(&ctrl->button_work);fallthrough;case ON_STATE:ctrl->state = POWEROFF_STATE;mutex_unlock(&ctrl->state_lock);if (events & PCI_EXP_SLTSTA_DLLSC)ctrl_info(ctrl, "Slot(%s): Link Down\n",slot_name(ctrl));if (events & PCI_EXP_SLTSTA_PDC)ctrl_info(ctrl, "Slot(%s): Card not present\n",slot_name(ctrl));pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);  //call remove_boardbreak;default:mutex_unlock(&ctrl->state_lock);break;}/* Turn the slot on if it's occupied or link is up */mutex_lock(&ctrl->state_lock);present = pciehp_card_present(ctrl);link_active = pciehp_check_link_active(ctrl);if (present <= 0 && link_active <= 0) {if (ctrl->state == BLINKINGON_STATE) {ctrl->state = OFF_STATE;cancel_delayed_work(&ctrl->button_work);pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,INDICATOR_NOOP);ctrl_info(ctrl, "Slot(%s): Card not present\n",slot_name(ctrl));}mutex_unlock(&ctrl->state_lock);return;}switch (ctrl->state) {case BLINKINGON_STATE:cancel_delayed_work(&ctrl->button_work);fallthrough;case OFF_STATE:ctrl->state = POWERON_STATE;mutex_unlock(&ctrl->state_lock);if (present)ctrl_info(ctrl, "Slot(%s): Card present\n",slot_name(ctrl));if (link_active)ctrl_info(ctrl, "Slot(%s): Link Up\n",slot_name(ctrl));ctrl->request_result = pciehp_enable_slot(ctrl);  //call board_added()break;default:mutex_unlock(&ctrl->state_lock);break;}
}
pciehp_enable_slot会调用board_added(通过__pciehp_enable_slot)和pciehp_set_indicators
static int pciehp_enable_slot(struct controller *ctrl)
{int ret;pm_runtime_get_sync(&ctrl->pcie->port->dev);ret = __pciehp_enable_slot(ctrl);if (ret && ATTN_BUTTN(ctrl))/* may be blinking */pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,INDICATOR_NOOP);pm_runtime_put(&ctrl->pcie->port->dev);mutex_lock(&ctrl->state_lock);ctrl->state = ret ? OFF_STATE : ON_STATE;mutex_unlock(&ctrl->state_lock);return ret;
}

board_added完成了pciehp_power_on_slot,pciehp_set_indicators,pciehp_configure_device (Off -> Blink -> On)

static int board_added(struct controller *ctrl)
{int retval = 0;struct pci_bus *parent = ctrl->pcie->port->subordinate;if (POWER_CTRL(ctrl)) {/* Power on slot */retval = pciehp_power_on_slot(ctrl);if (retval)return retval;}pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,INDICATOR_NOOP);/* Check link training status */retval = pciehp_check_link_status(ctrl);if (retval)goto err_exit;/* Check for a power fault */if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));retval = -EIO;goto err_exit;}retval = pciehp_configure_device(ctrl);if (retval) {if (retval != -EEXIST) {ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",pci_domain_nr(parent), parent->number);goto err_exit;}}pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,PCI_EXP_SLTCTL_ATTN_IND_OFF);return 0;err_exit:set_slot_off(ctrl);return retval;
}
int pciehp_power_on_slot(struct controller *ctrl)
{struct pci_dev *pdev = ctrl_dev(ctrl);u16 slot_status;int retval;/* Clear power-fault bit from previous power failures */pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);if (slot_status & PCI_EXP_SLTSTA_PFD)pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,PCI_EXP_SLTSTA_PFD);ctrl->power_fault_detected = 0;pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC);ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,PCI_EXP_SLTCTL_PWR_ON);retval = pciehp_link_enable(ctrl);if (retval)ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__);return retval;
}

Surprise Remove Flow

需要处理AER和DPC events,然后处理hot-plug events。中断触发pciehp_handle_presence_or_link_change,然后pciehp_disable_slot会调用remove_board(通过__pciehp_disable_slot),remove_board主要完成pciehp_power_off_slot和pciehp_set_indicators (On -> Off)。Presense detected需要等待DPC先触发。

static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
{int ret;pm_runtime_get_sync(&ctrl->pcie->port->dev);ret = __pciehp_disable_slot(ctrl, safe_removal);pm_runtime_put(&ctrl->pcie->port->dev);mutex_lock(&ctrl->state_lock);ctrl->state = OFF_STATE;mutex_unlock(&ctrl->state_lock);return ret;
}
static void remove_board(struct controller *ctrl, bool safe_removal)
{pciehp_unconfigure_device(ctrl, safe_removal);if (POWER_CTRL(ctrl)) {pciehp_power_off_slot(ctrl);/** After turning power off, we must wait for at least 1 second* before taking any action that relies on power having been* removed from the slot/adapter.*/msleep(1000);/* Ignore link or presence changes caused by power off */atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),&ctrl->pending_events);}pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,INDICATOR_NOOP);
}
void pciehp_power_off_slot(struct controller *ctrl)
{pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,PCI_EXP_SLTCTL_PWR_OFF);
}

NPEM Flow

NPEM(Native PCIe Enclosure Management) 是PCIe标准为NVMe设备定义的扩展LED控制功能,热插拔的LED控制机制由NPEM完成。可以实现在DP内或UP内,用于控制和更新LED状态。软件通过写入NPEM控制寄存器来发出NPEM指令,NPEM控制器根据指令更新LED状态,并使用completed机制指示软件完成。
在这里插入图片描述
NPEM支持实现OK/Locate/Fail/Rebuild等可选LED状态。
在这里插入图片描述
Linux Reference:
drivers/pci/hotplug /pciehp_hpc.c
driversdrivers/pci/hotplug/pciehp_ctrl.c

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

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

相关文章

Swift Combine 发布者publisher的生命周期 从入门到精通四

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三 1. 发布者和订阅者的生命周期 订阅者和发布者以明确定义的顺序进行通信&#xff0c;因此使得它们具有从开始到结束的生命周期&#xff1a; …

vue 实现一个持续时间定时器组件

vue 实现一个定时器组件 效果图子组件父组件 效果图 子组件 新建一个timer.vue文件 <template><span :class"{red: string > 600}">{{ string | formatDurationS }}</span> </template> <script>export default {name: timer,pro…

AD域国产替代方案,助力某金融企业麒麟信创电脑实现“真替真用”

近期收到不少企业客户反馈采购的信创PC电脑用不起来&#xff0c;影响信创改造的进度。例如&#xff0c;某金融企业积极响应国产化信创替代战略&#xff0c;购置了一批麒麟操作系统电脑。分发使用中发现了如下问题&#xff1a; • 当前麒麟操作系统电脑无法做到统一身份认证&…

推荐一款开源的跨平台划词翻译和OCR翻译软件:Pot

Pot简介 一款开源的跨平台划词翻译和OCR翻译软件 下载安装指南 根据你的机器型号下载对应版本&#xff0c;下载完成后双击安装即可。 使用教程 Pot具体功能如下&#xff1a; 划词翻译输入翻译外部调用鼠标选中需要翻译的文本&#xff0c;按下设置的划词翻译快捷键即可按下输…

格式工厂怎么转换视频格式?轻松转换!只需几个步骤

在当今数字娱乐时代&#xff0c;视频格式的广泛多样性意味着我们可能需要在不同设备和平台之间进行频繁的转换。而在众多视频转换工具中&#xff0c;格 式工厂凭借其强大的功能和简便的操作&#xff0c;成为了许多用户首选的选择之一。如果您正在寻找一种轻松而高效的方法来转换…

力扣精选算法100道——和为 K 的子数组[前缀和专题]

和为K的子数组链接 目录 第一步&#xff1a;了解题意​编辑 第二步&#xff1a;算法原理 第三步&#xff1a;代码 第一步&#xff1a;了解题意 数组中和为k的连续子数组&#xff0c;我们主要关注的是连续的&#xff0c; 比如[1,1,1],和为2的子数组有俩个&#xff0c;比如第…

闲聊电脑(6)装个 Windows(二)

闲聊电脑&#xff08;6&#xff09;装个 Windows&#xff08;二&#xff09; 夜深人静&#xff0c;万籁俱寂&#xff0c;老郭趴在电脑桌上打盹&#xff0c;桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭&#xff1a;冰箱大哥&#xff0c;上次说的镜像文件到底长啥样…

2024 token的实现原理:JWT标准,一文搞懂

先看看&#xff0c;用户和服务器的交互 -- 面上是这样子的&#xff1a; token的样子&#xff1a; 你看上图&#xff0c;三个部分组成&#xff0c;每个部分中&#xff0c;由 " . "&#xff0c;逗号分割&#xff1b; token为什么张这个样子&#xff1f; 因为规定了&am…

如何使用 Bard 中的画图功能

Bard 是 Google AI 推出的大型语言模型&#xff0c;它不仅可以生成文本、翻译语言&#xff0c;还可以根据您的描述生成图像。这篇文章将介绍如何使用 Bard 中的画图功能。 步骤 1&#xff1a;打开 Bard 首先&#xff0c;您需要打开 Bard。您可以访问 bard.google.com: https:…

jvm基础篇之垃圾回收[2](垃圾回收算法)

文章目录 版权声明垃圾回收算法核心思想垃圾回收算法的历史垃圾回收算法的评价标准垃圾分类算法分类标记清除算法核心思想标记清除算法优缺点 复制算法核心思想完整案例复制算法的优缺点 标记整理算法核心思想标记整理算法优缺点 分代垃圾回收算法arthas查看分代内存情况核心思…

【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目

作者推荐 【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 本文涉及知识点 动态规划汇总 LeetCode1987:不同的好子序列数目 给你一个二进制字符串 binary 。 binary 的一个 子序列 如果是 非空 的且没有 前导 0 &#xff08;除非数字是 “0” 本身&…

NodeJs使用selenium

在模拟登陆qq空间实现(3)这里有对 selenium的使用&#xff0c;使用的是C#。本文基于nodejs使用selenium。 const { AuditManager } require(aws-sdk); const {By, Builder, Capabilities} require(selenium-webdriver); function sleep(ms) {return new Promise(resolve >…