PCIe Leagcy,MSI/MSI-X中断详解

PCIe Leagcy,MSI/MSI-X中断详解

  • 前言
  • 7 Series FPGA Support
  • Leagcy Interupt
    • FPGA Code
    • WinDriver :
  • 待完

前言

PCIe有三种中断,分别为Leagcy InteruptMSI InteruptMSI-X Interupt,无论是什么应用,基本都需要中断,因此很有必要了解这几种中断的处理方式,这里会结合Windriver代码来说明,PCIE参考资料为Mindshare PCIe ,这本资料真心不错。

7 Series FPGA Support

7 Seriers FPGA PCIe IP核的Interupt 配置。PCIe Leagcy,MSI/MSI-X中断详解_第1张图片可以看到3种中断方式都支持,但是Leagcy Interupt 只支持发送INTA Meassge 类型。

Leagcy Interupt

这是一种共享且为了兼容之前的PCI的中断方式。

  • 共享
    PCIe Leagcy,MSI/MSI-X中断详解_第2张图片
    共享:意味着有多个设备都用同样的中断线,当这个中断线被Assert ,意味着这条中断线上至少有一个设备请求了中断信号,这时CPU必须有一种机制来判断到底是哪个设备请求了中断信号,在图中可以看到 Input 0 # 连线了3个INTA#。

  • 兼容:
    PCIe Leagcy,MSI/MSI-X中断详解_第3张图片
    PCIe Leagcy,MSI/MSI-X中断详解_第4张图片
    之前的PCI设备。
    中断请求:Assert 中断信号线。
    中断处理结束完: Dssert 中断信号线。

现在PCIe总线取消了这种AssertDssert的方式(电平),采用Message TLP消息包的方式来传递中断,但是又要向前兼容,故利用某些Message 类型,可以看到也就是这些Message Code不同从而代表不同的Leagcy Interupt类型,当这种包传递到PCIe to PCI Bridge ,Bridge 会自动转化成Assert Dssert的方式。反方向亦是如此。

FPGA Code

7 series PCIe IP核 简化了发送Leagcy Interupt 的方式,不需要用户按照Message TLP方式来发送这种信号,只需要与一些信号线交互就可以了。

实际上只需要3个信号就能发送Leagcy Interupt。
PCIe Leagcy,MSI/MSI-X中断详解_第5张图片

发送Assert:

    if(cfg_interrupt_rdy)
        begin
            cfg_interrupt_assert    <=#TCQ 1'b0;
            cfg_interrupt           <=#TCQ 1'b0; 
            //可能是状态跳转的代码
        end
    else
        begin
            cfg_interrupt_assert    <=#TCQ 1'b1;
            cfg_interrupt           <=#TCQ 1'b1; 
        end

cfg_interrupt 必须拉到 cfg_interrupt_rdy这个信号为

发送Dssert:

    if(cfg_interrupt_rdy)
        begin
            cfg_interrupt_assert    <=#TCQ 1'b0;
            cfg_interrupt           <=#TCQ 1'b0; 
            //可能是状态跳转的代码
        end
    else
        begin
            cfg_interrupt_assert    <=#TCQ 1'b0;
            cfg_interrupt           <=#TCQ 1'b1; 
        end

当然如果想知道IP核当前被软件启用了哪种中断方式,需要两个信号的组合。
PCIe Leagcy,MSI/MSI-X中断详解_第6张图片PCIe Leagcy,MSI/MSI-X中断详解_第7张图片

WinDriver :

前面已经说明了Leagcy Interupt 是共享的,因此需要一种手段来判断是否是自己特定设备的中断。

WinDriver处理这种中断的手段就是它认为当设备产生Leagcy Interupt 应该在设备的某些地址位置定义了一串数字,而当设备不产生Leagcy Interupt的时候,这串数字是清0的或者等于其他值,这串数字也就是Mask

            trans[0].cmdTrans = RM_DWORD;
            trans[0].dwPort = pDev->pAddrDesc->kptAddr + index;
     //trans[0] 也就是为了读取index位置的一串数字  
            trans[1].Data.Dword = Mask;//比对值
            trans[1].cmdTrans = CMD_MASK;
 	//trans[1] 的Mask是你自己先定义的或者手册给的,
 	//WinDriver 比对的方式就是 trans[1].Data.Dword& trans[0].Data.Dword做个与运算,
 	//等于1  这个中断是你的设备的。
 	//等于0 不是你的设备产生的中断,那也就不会返回到用户空间的中断处理 。

            trans[2].cmdTrans = WM_DWORD;//写一个DW
            trans[2].Data.Dword = Dword;//写的值
            trans[2].dwPort = pDev->pAddrDesc->kptAddr + offset;
  //trans[2] 就是写一个值(可能是需要回应的值)到一个offset偏移位置,需要或者不需要,看实际,比如offset=index,那也就是把会值写到Mask的位置了
            dwStatus = WDC_IntEnable(hDev, trans,3, 0, UserIntHandler,
                (PVOID)pDev, WDC_IS_KP(hDev));

待完

你可能感兴趣的:(Xilinx,PCIe,fpga,pci-e)