室内设计资料网站,统一管理网站系统,安装wordpress数据库500,网页游戏源码怎么用PCIe 的 MSI 中断
前言
什么是 MSI 中断 (Message Signaled Interrupts) 概念与内容介绍待补充
正文
对 EP 的初始化
需要对 EP 的配置空间 MSI 相关功能的寄存器进行初始化#xff0c;主要有两个寄存器 Message Address 和 Message Data。它们分别的含义是 EP 产生 MSI …PCIe 的 MSI 中断
前言
什么是 MSI 中断 (Message Signaled Interrupts) 概念与内容介绍待补充
正文
对 EP 的初始化
需要对 EP 的配置空间 MSI 相关功能的寄存器进行初始化主要有两个寄存器 Message Address 和 Message Data。它们分别的含义是 EP 产生 MSI 中断的操作是往 Message Address 寄存器的地址写入 Message Data 指定的数据从而来产生 MSI 中断。Message Address 在不同的 CPU 有不同的配置例如 rk3568 写入的地址为 GICD 中断控制器的某个地址其他有些 CPU 配置任意地址都可。还需要对 EP MSI 中断能力进行使能。即下图中的 Message Control Configuration MSI Control Status Register Field Descriptions 寄存器进行配置。 截图来自 F-Tile Avalon® Streaming Intel® FPGA IP for PCI Express* User Guide
对 RC 的寄存器初始化 本文以 designware IP 核的某型 CPU 为例。其他的 CPU 会存在写 GICD 的地址和下面的配置会有区别。
写入 PCIE_MSI_ADDR_LO , 即需要和 EP 配置的 Message Address 相匹配。RC 会捕获 EP 写入这个地址的操作并触发中断。写入 PCIE_MSI_INTR0_ENABLE即使能所有的 MSI 中断
#define PCIE_MSI_ADDR_LO 0x820
#define PCIE_MSI_ADDR_HI 0x824
void dw_pcie_msi_init(struct pcie_port *pp)
{struct dw_pcie *pci to_dw_pcie_from_pp(pp);u64 msi_target (u64)pp-msi_data;if (!IS_ENABLED(CONFIG_PCI_MSI))return;/* Program the msi_data */dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
}
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);#define PCIE_MSI_INTR0_ENABLE 0x828
#define PCIE_MSI_INTR0_MASK 0x82C
#define PCIE_MSI_INTR0_STATUS 0x830
void dw_pcie_setup_rc(struct pcie_port *pp)
{u32 val, ctrl, num_ctrls;struct dw_pcie *pci to_dw_pcie_from_pp(pp);/** Enable DBI read-only registers for writing/updating configuration.* Write permission gets disabled towards the end of this function.*/dw_pcie_dbi_ro_wr_en(pci);dw_pcie_setup(pci);if (pci_msi_enabled() !pp-ops-msi_host_init) {num_ctrls pp-num_vectors / MAX_MSI_IRQS_PER_CTRL;/* Initialize IRQ Status array */for (ctrl 0; ctrl num_ctrls; ctrl) {pp-irq_mask[ctrl] ~0;dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK (ctrl * MSI_REG_CTRL_BLOCK_SIZE),pp-irq_mask[ctrl]);dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE (ctrl * MSI_REG_CTRL_BLOCK_SIZE),~0);}}// 省略了其他操作
}中断执行 在中断服务函数中需要读 PCIE_MSI_INTR0_STATUS 寄存器来判断是几号MSI中断这个是由配置的 Message Data 来决定的。 中断状态清除 需要写 PCIE_MSI_INTR0_STATUS 寄存器来清除对应的中断否则中断会持续触发。同时也需要写 GIC 本身的寄存器来清除 PCIe 的中断。
#define PCIE_MSI_INTR0_STATUS 0x830/* MSI int handler */
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{int i, pos, irq;unsigned long val;u32 status, num_ctrls;irqreturn_t ret IRQ_NONE;struct dw_pcie *pci to_dw_pcie_from_pp(pp);num_ctrls pp-num_vectors / MAX_MSI_IRQS_PER_CTRL;for (i 0; i num_ctrls; i) {status dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS (i * MSI_REG_CTRL_BLOCK_SIZE));if (!status)continue;ret IRQ_HANDLED;val status;pos 0;while ((pos find_next_bit(val, MAX_MSI_IRQS_PER_CTRL,pos)) ! MAX_MSI_IRQS_PER_CTRL) {irq irq_find_mapping(pp-irq_domain,(i * MAX_MSI_IRQS_PER_CTRL) pos);generic_handle_irq(irq);pos;}}return ret;
}
EXPORT_SYMBOL_GPL(dw_handle_msi_irq);总结
至此EP 可以正确触发 MSI 中断并被 RC 捕获后往 GIC 投递 PCIe 中断。本例的 MSI 中断并不是直接写 GIC 的 ITS ((Interrupt Translation Service)在GICv3中是可选的。ITS负责接收来自外设的中断并将它们转化为LPI INTID发送到相应的Redistributor) 产生的而是由 RC 中转了然后投递到 GIC 的。
其他
EP 生成 MSI 中断的消息填充图中的含义是生成一个 MSI Mwr 的 TLP 消息其组包的数据来源包括 Message Address 和 Message Data。