SylixOS PCIe控制器驱动开发(六)

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2021年3月28日14:23:25 评论 1,175

SylixOS读写PCIe设备配置空间

在上一节中,我们知道注册控制器驱动后,SylixOS会遍历所有总线上的设备信息,这是通过读取设备的配置空间信息实现的。SylixOS中配置空间的读写都是通过调用PCI_DRV_FUNCS0 或者PCI_DRV_FUNCS12 数据结构中的回调函数实现的。PCI_DRV_FUNCS12 这个是x86平台使用的,所以我们这里只关注 PCI_DRV_FUNCS0 这个数据结构。

typedef struct pci_drv_funcs0 {
    INT     (*cfgRead)(INT iBus, INT iSlot, INT iFunc, INT iOft, INT iLen, PVOID pvRet);
    INT     (*cfgWrite)(INT iBus, INT iSlot, INT iFunc, INT iOft, INT iLen, UINT32 uiData);
    INT     (*vpdRead)(INT iBus, INT iSlot, INT iFunc, INT iPos, UINT8 *pucBuf, INT iLen);
    INT     (*irqGet)(INT iBus, INT iSlot, INT iFunc, INT iMsiEn, INT iLine, INT iPin, PVOID pvIrq);
    INT     (*cfgSpcl)(INT iBus, UINT32 uiMsg);
} PCI_DRV_FUNCS0;

我们简单回顾下PCIe知识,按照PCIe标准,一个控制器下最多可以有256个总线,每个总线下最多有32个设备,每个设备最多有8个功能,每个功能都有一个配置空间,普通功能配置空间大小为256字节,复杂的可能需要4KB大小。配置空间可以进行单字节、双字节、4字节访问。

有了以上信息后我们以读函数接口为例看看读写接口如何实现。

static int pci_cfg_read (int bus, int dev, int func,
                         int offset, int len, void *data)
{
    return 0;
}
  • bus:总线号。
  • dev:设备号。
  • func:功能号。
  • offset:寄存器偏移。
  • len:读取的字节数,可以为1、2、4。
  • data:数据缓冲区。

每个入参的意义很好理解,不同平台需要根据这几个入参转换成平台相关的配置空间访问方法。比如对于飞腾2000/4平台来说,配置空间是通过普通的MMIO访问来实现的,配置空间MMIO起始地址为0x40000000,控制器驱动需要根据上述入参计算出配置空间寄存器对应的MMIO访问地址,然后通过普通的内存访问方法读写数据。

SylixOS PCIe控制器驱动开发(六)

配置空间写接口和读接口类似,只是最后一个参数是上层传下来的具体要写的数值。

static int pci_cfg_write (int bus, int dev, int func,
                          int offset, int len, unsigned int data)
{
    return 0;
}

驱动同样需要根据入参转换成平台相关的配置空间写方法。

在实际的驱动中,一般定义一个全局变量,并使用上述的读写接口来初始化。

static PCI_DRV_FUNCS0  pci_driver_funcs = {
    .cfgRead  = pci_cfg_read,
    .cfgWrite = pci_cfg_write,
};

附源码

pci_host_driver_demo2.c源码:

#define __SYLIXOS_KERNEL
#define __SYLIXOS_PCI_DRV
#include <SylixOS.h>
#include <module.h>
#include <system/device/pci/pciBus.h>
#include <system/device/pci/pciMsi.h>
#include <system/device/pci/pciLib.h>

static PCI_CTRL_CB pci_host;

static int pci_cfg_read (int bus, int dev, int func,
                         int offset, int len, void *data)
{
    return 0;
}

static int pci_cfg_write (int bus, int dev, int func,
                          int offset, int len, unsigned int data)
{
    return 0;
}

static PCI_DRV_FUNCS0  pci_driver_funcs = {
    .cfgRead  = pci_cfg_read,
    .cfgWrite = pci_cfg_write,
};

int pci_host_probe (void)
{
    API_PciCtrlCreate(&pci_host);

    return 0;
}

int module_init (void)
{
    pci_host_probe();

    return 0;
}

void module_exit (void)
{
}
gewenbin
  • 本文由 发表于 2021年3月28日14:23:25
  • 转载请务必保留本文链接:http://www.databusworld.cn/10026.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: