searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

linux虚拟机MSI中断实现分析

2023-10-18 08:41:21
258
0

1、MSI-X中断实现

目前PCIE设备主要通过MSI-X机制向CPU发送中断,实现步骤如下:

a) CPU初始化的时候会给PCIE设备分配中断号,并且根据分配好的中断号生成MSI的address和data信息;

b)然后把address和data信息写入PCIE设备 ;

c) 后期如果PCIE设备想发送中断,则把data的值写入address就可以了

 

2、查找virtio虚拟网卡的中断信息

a、在PCIE的配置空间找到MSI-X CAP的配置

b、根据配置找出MSI-X table的地址(BAR3 + OFFSET)

c、访问MSI-X table中的内容可以知道中断信息(  data and address )
 
 
示例:

[root@localhost ~]# lspci -s 0000:0d.0 -vvv
00:0d.0 Ethernet controller: Virtio: Virtio network device
  Region 0: I/O ports at 6120 [size=32]
  Region 1: Memory at fea5a000 (32-bit, non-prefetchable) [size=4K] # 2、MSI-X 使用该地址空间
  Region 4: Memory at fca10000 (64-bit, prefetchable) [size=16K]
  Expansion ROM at fea20000 [disabled] [size=128K]
  Capabilities: [98] MSI-X: Enable+ Count=3 Masked-   #1、 Enable+ 表示MSIX为Enable状态 Count=3 表示支持3个中断
    Vector table: BAR=1 offset=00000000    # 3、 MSI-X配置的寄存器在BAR1
    PBA: BAR=1 offset=00000800
```
 
d、MSIX Table 中每一条Entry 代表一个中断向量,Msg Data 中包括了中断向量号,Msg Addr 中通常包含了多核CPU用于处理 中断的 Local APIC 编号;
 
address:  决定中断发送给哪个CPU

data:  决定中断发送给CPU的哪个vector
 
详细信息可以参考 irq_msi_compose_msg() 函数实现
 
下图是一个操作实例:
 
 

3、代码实现

 

3.1、 irq domian代码实现

 

- 子domain调用alloc申请中断的时候会递归调用父domain的alloc
  msi_domain_alloc_irqs -> __irq_domain_alloc_irqs -> irq_domain_alloc_irqs_recursive // 递归调用alloc函数

  msi_domain_alloc

  ​      |-> irq_find_mapping 检查是否已经分配了

  ​       |-> irq_domain_alloc_irqs_parent // 递归调用父domain的alloc函数

  ​                     |->  x86_vector_alloc_irqs

  ​                                |-> per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq) 把irq_desc 挂到cpu的中断向量上
 
- 子domain调用active使能中断的时候会递归调用父domain的active
    msi_domain_alloc_irqs --> irq_domain_activate_irq // 递归调用父domain的active函数
   
    msi_domain_activate
   
    ​      |->  irq_chip_compose_msi_msg // 组装Msi消息(包含address和data)
   
    ​                 |-> irq_msi_compose_msg 中断目的CPU写入到msg->address中 中断向量写入msg->data中
   
    ​      |-> irq_chip_write_msi_msg // msi消息写入msix的table中
   
    ​                 |-> pci_msi_domain_write_msg
   
    ​                           |-> __pci_write_msi_msg 写入msix-table中

 

3.2、中断初始化:msi_domain_alloc_irqs

 

msi_domain_alloc_irqs

​     |-> ops->msi_check= pci_msi_domain_check_cap  // 检查是否支持msix等功能

​     |-> ops->msi_prepare =  pci_msi_prepare // 初始化 msi_alloc_info_t

​      |-> ops->set_desc = pci_msi_set_desc // 计算 msi_hwirq 存入 msi_alloc_info_t中

​      |-> __irq_domain_alloc_irqs

​             |-> irq_domain_alloc_descs // 1、 申请irq_desc 并且插入到irq_desc_tree中

​             |-> irq_domain_alloc_irq_data // 2 、申请irq_data、并且申请父domain的irq_data

​             |-> irq_domain_alloc_irqs_recursive // 3、递归调用domain的alloc函数,挂irq_desc到cpu中断向量

​             |-> irq_domain_insert_irq // 4、 建立virq和hwirq的映射关系

​       |-> irq_set_msi_desc_off // msi desc 信息写入到irq_desc

​       |-> irq_domain_activate_irq // 5、 递归调用domain的active函数、激活中断

​               |-> irq_chip_compose_msi_msg  // 组装Msi消息(包含address和data)

​               |-> irq_chip_write_msi_msg //  msi消息写入msix的table中

 

0条评论
0 / 1000
湛****涛
2文章数
0粉丝数
湛****涛
2 文章 | 0 粉丝
湛****涛
2文章数
0粉丝数
湛****涛
2 文章 | 0 粉丝
原创

linux虚拟机MSI中断实现分析

2023-10-18 08:41:21
258
0

1、MSI-X中断实现

目前PCIE设备主要通过MSI-X机制向CPU发送中断,实现步骤如下:

a) CPU初始化的时候会给PCIE设备分配中断号,并且根据分配好的中断号生成MSI的address和data信息;

b)然后把address和data信息写入PCIE设备 ;

c) 后期如果PCIE设备想发送中断,则把data的值写入address就可以了

 

2、查找virtio虚拟网卡的中断信息

a、在PCIE的配置空间找到MSI-X CAP的配置

b、根据配置找出MSI-X table的地址(BAR3 + OFFSET)

c、访问MSI-X table中的内容可以知道中断信息(  data and address )
 
 
示例:

[root@localhost ~]# lspci -s 0000:0d.0 -vvv
00:0d.0 Ethernet controller: Virtio: Virtio network device
  Region 0: I/O ports at 6120 [size=32]
  Region 1: Memory at fea5a000 (32-bit, non-prefetchable) [size=4K] # 2、MSI-X 使用该地址空间
  Region 4: Memory at fca10000 (64-bit, prefetchable) [size=16K]
  Expansion ROM at fea20000 [disabled] [size=128K]
  Capabilities: [98] MSI-X: Enable+ Count=3 Masked-   #1、 Enable+ 表示MSIX为Enable状态 Count=3 表示支持3个中断
    Vector table: BAR=1 offset=00000000    # 3、 MSI-X配置的寄存器在BAR1
    PBA: BAR=1 offset=00000800
```
 
d、MSIX Table 中每一条Entry 代表一个中断向量,Msg Data 中包括了中断向量号,Msg Addr 中通常包含了多核CPU用于处理 中断的 Local APIC 编号;
 
address:  决定中断发送给哪个CPU

data:  决定中断发送给CPU的哪个vector
 
详细信息可以参考 irq_msi_compose_msg() 函数实现
 
下图是一个操作实例:
 
 

3、代码实现

 

3.1、 irq domian代码实现

 

- 子domain调用alloc申请中断的时候会递归调用父domain的alloc
  msi_domain_alloc_irqs -> __irq_domain_alloc_irqs -> irq_domain_alloc_irqs_recursive // 递归调用alloc函数

  msi_domain_alloc

  ​      |-> irq_find_mapping 检查是否已经分配了

  ​       |-> irq_domain_alloc_irqs_parent // 递归调用父domain的alloc函数

  ​                     |->  x86_vector_alloc_irqs

  ​                                |-> per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq) 把irq_desc 挂到cpu的中断向量上
 
- 子domain调用active使能中断的时候会递归调用父domain的active
    msi_domain_alloc_irqs --> irq_domain_activate_irq // 递归调用父domain的active函数
   
    msi_domain_activate
   
    ​      |->  irq_chip_compose_msi_msg // 组装Msi消息(包含address和data)
   
    ​                 |-> irq_msi_compose_msg 中断目的CPU写入到msg->address中 中断向量写入msg->data中
   
    ​      |-> irq_chip_write_msi_msg // msi消息写入msix的table中
   
    ​                 |-> pci_msi_domain_write_msg
   
    ​                           |-> __pci_write_msi_msg 写入msix-table中

 

3.2、中断初始化:msi_domain_alloc_irqs

 

msi_domain_alloc_irqs

​     |-> ops->msi_check= pci_msi_domain_check_cap  // 检查是否支持msix等功能

​     |-> ops->msi_prepare =  pci_msi_prepare // 初始化 msi_alloc_info_t

​      |-> ops->set_desc = pci_msi_set_desc // 计算 msi_hwirq 存入 msi_alloc_info_t中

​      |-> __irq_domain_alloc_irqs

​             |-> irq_domain_alloc_descs // 1、 申请irq_desc 并且插入到irq_desc_tree中

​             |-> irq_domain_alloc_irq_data // 2 、申请irq_data、并且申请父domain的irq_data

​             |-> irq_domain_alloc_irqs_recursive // 3、递归调用domain的alloc函数,挂irq_desc到cpu中断向量

​             |-> irq_domain_insert_irq // 4、 建立virq和hwirq的映射关系

​       |-> irq_set_msi_desc_off // msi desc 信息写入到irq_desc

​       |-> irq_domain_activate_irq // 5、 递归调用domain的active函数、激活中断

​               |-> irq_chip_compose_msi_msg  // 组装Msi消息(包含address和data)

​               |-> irq_chip_write_msi_msg //  msi消息写入msix的table中

 

文章来自个人专栏
湛松涛
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0