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

pci msi-x中断学习

2024-09-26 09:25:23
20
0

1、MSI-X Capability

1.1、下图是MSI-X Capability的结构体,各字段含义如下:

Capability ID

RO

表示MSI-X Cap功能ID号,其值为0x11

Next Pointer

RO

指向下一个Capability地址

Message Control

RO

当前PCIe设备使用MSI-X机制进行中断请求的状态与控制信息,详情见下文。

Table BIR

RO

表示MSI-X Table所在的BAR空间。该字段由三位组成,其中0b000~0b101BAR0~5空间一一对应

Table Offset

RO

表示MSI-X Table在相应BAR空间中的偏移。

PBA BIR

RO

表示Pending TablePCIe设备的哪个BAR空间中。在通常情况下,Pending TableMSI-X Table存放在PCIe设备的同一个BAR空间中。

PBA Offset

RO

表示Pending Table在相应BAR空间中的偏移

下图是Message Control的结构体和字段解释

Table Size

RO

用来存放MSI-X Table的大小

Function Mask

RW

中断请求的全局Mask位,默认值为0。如果为1,该设备所有的中断请求都将被屏蔽;如果为0,则由Per Vector Mask位,决定是否屏蔽相应的中断请求

MSI-X Enable

RW

MSI-X中断机制的使能位,复位值为0,表示不使能MSI-X中断机制。该位为1MSI Enable位为0时,当前PCIe设备使用MSI-X中断机制,此时INTxMSI中断机制被禁止。当PCIe设备的MSI EnbleMSI-X Enable位为0时,将使用INTx中断消息报文发出/结束中断请求。

1.2、从QEMU出发

qemu支持pci msi-x的模拟,接口如下:

/*
 * Make PCI device @dev MSI-X capable
 * @nentries is the max number of MSI-X vectors that the device support.
 * @table_bar is the MemoryRegion that MSI-X table structure resides.
 * @table_bar_nr is number of base address register corresponding to @table_bar.
 * @table_offset indicates the offset that the MSI-X table structure starts with
 * in @table_bar.
 * @pba_bar is the MemoryRegion that the Pending Bit Array structure resides.
 * @pba_bar_nr is number of base address register corresponding to @pba_bar.
 * @pba_offset indicates the offset that the Pending Bit Array structure
 * starts with in @pba_bar.
 * Non-zero @cap_pos puts capability MSI-X at that offset in PCI config space.
 * @errp is for returning errors.
 *
 * Return 0 on success; set @errp and return -errno on error:
 * -ENOTSUP means lacking msi support for a msi-capable platform.
 * -EINVAL means capability overlap, happens when @cap_pos is non-zero,
 * also means a programming error, except device assignment, which can check
 * if a real HW is broken.
 */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              MemoryRegion *table_bar, uint8_t table_bar_nr,
              unsigned table_offset, MemoryRegion *pba_bar,
              uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
              Error **errp);

2、pci_alloc_irq_vectors()

接口如下:

int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, unsigned int max_vecs, unsigned int flags)

 

参数和return:

dev

pci 设备

min_vecs

设备对中断向量数目的最小要求,如果小于该值,会返回错误

max_vecs

期望分配的中断向量最大个数

flags

用于区分设备和驱动能够使用的中断类型,一般有4

#define PCI_IRQ_LEGACY (1 << 0) /* Allow legacy interrupts */

#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */

#define PCI_IRQ_MSIX (1 << 2) /* Allow MSI-X interrupts */

#define PCI_IRQ_ALL_TYPES   (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)

return

返回分配到的向量数量

 

主要分析当flag 为__pci_enable_msix_range时的流程
pci_alloc_irq_vectors()
    ->pci_alloc_irq_vectors_affinity()

pci_alloc_irq_vectors_affinity()
    ->__pci_enable_msix_range()
        ->min_vecs > max_vecs ? max小于min 则直接返回
        ->dev->msix_enabled ? 如果已经enable,则直接返回(lspci 能看到MSI-X的使能状态)加载KO后就是使能状态,卸载KO后应该是非使能状态
        ->__pci_enable_msix()

__pci_enable_msix()
    -> pci_msi_supported() 判断是否支持msi,即是否支持中断
    -> pci_msix_vec_count()获取设备支持的MSI-X的entry的个数,从msix的message_control字段中获取支持个数(lspci看到的数量+ 1)
    ->msix_capability_init()

msix_capability_init()
    ->pci_msix_clear_and_set_ctrl()写message_control enable字段为1
    ->pci_read_config_word() 获取mis-x的数量
    ->msix_map_region()根据支持的entry个数,bar number,在bar中的偏移,进行ioremap,大小是entry 个数 * 16(sizeof(msix entry))
    ->msix_setup_entries()init msi table entry,设置entry的向量号,base地址等信息。链表形式放在dev管理dev->msi_list
    ->pci_msi_setup_msi_irqs() 使能mis 中断
        ->msi_domain_alloc_irqs() 以domain进行申请中断
            ->遍历dev->msi_list,__irq_domain_alloc_irqs()申请irq的描述符,一些资源
            ->遍历dev->msi_list,irq_domain_activate_irq()激活irq,这块是递归调用,使用domain->ops->activate;激活irp
            ->irq_chip_write_msi_msg() 调用data->chip->irq_write_msi_msg()
                ->pci_msi_domain_write_msg()完成msix tab的内容。
    ->msi_verify_entries()校验entry填充的是否符合规则(是否使用64bit和高32位地址是否使用)
    ->msix_program_entries() 上一步屏蔽中断,防止新中断进来,遍历entry,查看mask等信息
    ->populate_msi_sysfs() 写sysfs的msi_irqs信息
    ->pci_intx_for_msi()关闭INTx中断
    ->解除mis-x屏蔽

 

0条评论
0 / 1000
z****n
8文章数
0粉丝数
z****n
8 文章 | 0 粉丝
原创

pci msi-x中断学习

2024-09-26 09:25:23
20
0

1、MSI-X Capability

1.1、下图是MSI-X Capability的结构体,各字段含义如下:

Capability ID

RO

表示MSI-X Cap功能ID号,其值为0x11

Next Pointer

RO

指向下一个Capability地址

Message Control

RO

当前PCIe设备使用MSI-X机制进行中断请求的状态与控制信息,详情见下文。

Table BIR

RO

表示MSI-X Table所在的BAR空间。该字段由三位组成,其中0b000~0b101BAR0~5空间一一对应

Table Offset

RO

表示MSI-X Table在相应BAR空间中的偏移。

PBA BIR

RO

表示Pending TablePCIe设备的哪个BAR空间中。在通常情况下,Pending TableMSI-X Table存放在PCIe设备的同一个BAR空间中。

PBA Offset

RO

表示Pending Table在相应BAR空间中的偏移

下图是Message Control的结构体和字段解释

Table Size

RO

用来存放MSI-X Table的大小

Function Mask

RW

中断请求的全局Mask位,默认值为0。如果为1,该设备所有的中断请求都将被屏蔽;如果为0,则由Per Vector Mask位,决定是否屏蔽相应的中断请求

MSI-X Enable

RW

MSI-X中断机制的使能位,复位值为0,表示不使能MSI-X中断机制。该位为1MSI Enable位为0时,当前PCIe设备使用MSI-X中断机制,此时INTxMSI中断机制被禁止。当PCIe设备的MSI EnbleMSI-X Enable位为0时,将使用INTx中断消息报文发出/结束中断请求。

1.2、从QEMU出发

qemu支持pci msi-x的模拟,接口如下:

/*
 * Make PCI device @dev MSI-X capable
 * @nentries is the max number of MSI-X vectors that the device support.
 * @table_bar is the MemoryRegion that MSI-X table structure resides.
 * @table_bar_nr is number of base address register corresponding to @table_bar.
 * @table_offset indicates the offset that the MSI-X table structure starts with
 * in @table_bar.
 * @pba_bar is the MemoryRegion that the Pending Bit Array structure resides.
 * @pba_bar_nr is number of base address register corresponding to @pba_bar.
 * @pba_offset indicates the offset that the Pending Bit Array structure
 * starts with in @pba_bar.
 * Non-zero @cap_pos puts capability MSI-X at that offset in PCI config space.
 * @errp is for returning errors.
 *
 * Return 0 on success; set @errp and return -errno on error:
 * -ENOTSUP means lacking msi support for a msi-capable platform.
 * -EINVAL means capability overlap, happens when @cap_pos is non-zero,
 * also means a programming error, except device assignment, which can check
 * if a real HW is broken.
 */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              MemoryRegion *table_bar, uint8_t table_bar_nr,
              unsigned table_offset, MemoryRegion *pba_bar,
              uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
              Error **errp);

2、pci_alloc_irq_vectors()

接口如下:

int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, unsigned int max_vecs, unsigned int flags)

 

参数和return:

dev

pci 设备

min_vecs

设备对中断向量数目的最小要求,如果小于该值,会返回错误

max_vecs

期望分配的中断向量最大个数

flags

用于区分设备和驱动能够使用的中断类型,一般有4

#define PCI_IRQ_LEGACY (1 << 0) /* Allow legacy interrupts */

#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */

#define PCI_IRQ_MSIX (1 << 2) /* Allow MSI-X interrupts */

#define PCI_IRQ_ALL_TYPES   (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)

return

返回分配到的向量数量

 

主要分析当flag 为__pci_enable_msix_range时的流程
pci_alloc_irq_vectors()
    ->pci_alloc_irq_vectors_affinity()

pci_alloc_irq_vectors_affinity()
    ->__pci_enable_msix_range()
        ->min_vecs > max_vecs ? max小于min 则直接返回
        ->dev->msix_enabled ? 如果已经enable,则直接返回(lspci 能看到MSI-X的使能状态)加载KO后就是使能状态,卸载KO后应该是非使能状态
        ->__pci_enable_msix()

__pci_enable_msix()
    -> pci_msi_supported() 判断是否支持msi,即是否支持中断
    -> pci_msix_vec_count()获取设备支持的MSI-X的entry的个数,从msix的message_control字段中获取支持个数(lspci看到的数量+ 1)
    ->msix_capability_init()

msix_capability_init()
    ->pci_msix_clear_and_set_ctrl()写message_control enable字段为1
    ->pci_read_config_word() 获取mis-x的数量
    ->msix_map_region()根据支持的entry个数,bar number,在bar中的偏移,进行ioremap,大小是entry 个数 * 16(sizeof(msix entry))
    ->msix_setup_entries()init msi table entry,设置entry的向量号,base地址等信息。链表形式放在dev管理dev->msi_list
    ->pci_msi_setup_msi_irqs() 使能mis 中断
        ->msi_domain_alloc_irqs() 以domain进行申请中断
            ->遍历dev->msi_list,__irq_domain_alloc_irqs()申请irq的描述符,一些资源
            ->遍历dev->msi_list,irq_domain_activate_irq()激活irq,这块是递归调用,使用domain->ops->activate;激活irp
            ->irq_chip_write_msi_msg() 调用data->chip->irq_write_msi_msg()
                ->pci_msi_domain_write_msg()完成msix tab的内容。
    ->msi_verify_entries()校验entry填充的是否符合规则(是否使用64bit和高32位地址是否使用)
    ->msix_program_entries() 上一步屏蔽中断,防止新中断进来,遍历entry,查看mask等信息
    ->populate_msi_sysfs() 写sysfs的msi_irqs信息
    ->pci_intx_for_msi()关闭INTx中断
    ->解除mis-x屏蔽

 

文章来自个人专栏
RDMA杂谈
8 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0