# FPCIE 驱动程序 ## 1. 概述 - PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为是数据发送端和数据接收端。PCIe总线除了总线链路外,还具有多个层次,发送端发送数据时将通过这些层次,而接收端接收数据时也使用这些层次。似 - FPCIE 模块内置两个 PCIE 单元(PCI-E Unit,PEU),分别为 PEU0 和 PEU1。每个 PEU 包含 3 个控制器:C0、C1 和 C2。当 PEU 拆分模式为 X16 时,C1 不可见。 - 本模块特点如下 1. 支持 Root Complex 和 End Point 两种模式; 2. 共 34 lane,两路 X16(可拆分为 2 个 X8)和两路 X1; 3. 内部集成 DMA 引擎,一读一写两个通道。 ## 2. 功能 - 驱动相关的源文件如下, - drivers/pcie/fpcie ``` . ├── fpcie.c ├── fpcie.h ├── fpcie.md ├── fpcie_common.h ├── fpcie_config.c ├── fpcie_dma.c ├── fpcie_dma.h ├── fpcie_ep.c ├── fpcie_g.c ├── fpcie_hw.c ├── fpcie_hw.h ├── fpcie_misc.c ├── fpcie_sinit.c ├── fpcir_intx.c └── fspim.md ``` ## 3. 配置方法 以下部分将指导您完成 PCIE 驱动的软件配置: - 初始化PCIE控制器 - 通过API 获取特定设备的 bar 空间地址 - 使用INTX 中断响应设备中断响应函数 - 使用DMA模式完成数据通信 ## 4. 应用示例 "/baremetal/example/peripheral/fpcie_probe " ## 5. API参考 ### 5.1 用户数据结构 - 中断注册回调函数 ```c typedef struct { void (*IntxCallBack)(void *args) ; void *args ; s32 bdf ; } FPcieIntxFun; ``` - 初始化配置空间地址 ```c struct FPcieRegion { FPcieAddr bus_start; /* Start on the bus */ FPciePhysAddr phys_start; /* Start in physical address space */ FPcieSize size; /* Size */ unsigned long flags; /* Resource flags */ FPcieAddr bus_lower; u32 exist_flg; /* exist flg */ }; ``` - 驱动配置数据 ```c typedef struct { u32 instance_id; /* Id of device */ u32 irq_num; /* Irq number */ uintptr_t ecam; /* The Memory way */ uintptr_t peu0_config_address; uintptr_t peu1_config_address; uintptr_t control_c0_address; uintptr_t control_c1_address; uintptr_t control_c2_address; uintptr_t control_c3_address; uintptr_t control_c4_address; uintptr_t control_c5_address; u32 io_base_addr; u32 io_size ; u32 npmem_base_addr; u32 npmem_size; u64 pmem_base_addr; /* Prefetchable memory */ u64 pmem_size; u8 inta_irq_num ; u8 intb_irq_num ; u8 intc_irq_num ; u8 intd_irq_num ; u8 need_skip ; } FPcieConfig; ``` - 驱动控制数据 ```c typedef struct { u32 is_ready; /* Device is ininitialized and ready*/ FPcieConfig config; struct FPcieRegion mem; struct FPcieRegion mem_prefetch; struct FPcieRegion mem_io; s32 bus_max; /* 当前最大bus num */ FPcieIrqCallBack fpcie_dma_rx_cb; void *dma_rx_args; FPcieIrqCallBack fpcie_dma_tx_cb; void *dma_tx_args; FPcieIrqCallBack fpcie_dma_rx_error_cb; void *dma_rx_error_args; FPcieIrqCallBack fpcie_dma_tx_error_cb; void *dma_tx_error_args; FPcieIntxFun inta_fun; FPcieIntxFun intb_fun; FPcieIntxFun intc_fun; FPcieIntxFun intd_fun; } FPcie; ``` - 配置空间标记参数 ``` #define FPCIE_REGION_MEM 0x00000000 /* PCI memory space */ #define FPCIE_REGION_IO 0x00000001 /* PCI IO space */ #define PCI_REGION_PREFETCH 0x00000008 /* prefetchable PCI memory */ ``` - 配置空间中对应的bar 标号 ``` #define FPCIE_BAR_0 0 #define FPCIE_BAR_1 1 #define FPCIE_BAR_2 2 #define FPCIE_BAR_3 3 #define FPCIE_BAR_4 4 #define FPCIE_BAR_5 5 ``` ### 5.2 错误码定义 - 模块错误码编号:0x1090000 - [0x0] FT_SUCCESS - [0x1090001] FPCIE_ERR_INVALID_PARAM - [0x1090002] FPCIE_ERR_OUTOF_BUS - [0x1090003] FPCIE_ERR_CONFIG_WRITE - [0x1090004] FPCIE_ERR_TYPE0 - [0x1090005] FPCIE_ERR_TIMEOUT - [0x1090006] FPCIE_NEED_SKIP - [0x1090007] FPCIE_NOT_FOUND ### 5.3 用户API接口 #### FPcieLookupConfig - 获取FPCIE驱动的默认配置参数 ```c const FPcieConfig *FPcieLookupConfig(u32 instance_id) ``` Note: - 用户可以通过此接口获取驱动默认配置的副本,进行修改后,作为`FPcieCfgInitialize`函数的入参使用 Input: - u32 instance_id, 选择的FPcie控制器实例号 Return: - const FPcieConfig *, 返回的默认驱动配置,返回NULL表示失败 #### FPcieCfgInitialize - 初始化配置空间和FPCIE 实例 ```c FError FPcieCfgInitialize(FPcie *instance_p, FPcieConfig *config_p) ``` Note: - 用户可以使用'FPcieLookupConfig'所产生的配置参数进行初始化,也可以自己组织配置参数进行初始化 Input: - FPcie *instance_p 指向FPcie实例的指针。 - FPcieConfig *config_p 指向FPcieConfig的指针。 Return : - 成功返回 FT_SUCCESS #### FPcieDmaDescSet - PCIE DMA描述符分组包 ```c FError FPcieDmaDescSet(uintptr axi_addr, uintptr bar_addr, u32 length, struct FPcieDmaDescriptor *desc, struct FPcieDmaDescriptor *next_desc) ``` Note: - 用户使用dma 方式进行PCIE 数据传输时,用此函数将源地址与目标地址进行组合打包 Input: - uintptr axi_addr 内存地址,可以为接收地址也可为发送地址 - uintptr bar_addr 需要通信function中对应的bar寄存器中分配的地址空间,可以为接收地址也可为发送地址 - u32 length 需要传输的字节长度 - struct FPcieDmaDescriptor *next_desc 是下一个需要发送的描述符 Output: - struct FPcieDmaDescriptor *desc 需要要配置的描述符 #### FPcieDmaRead Note: - 通过dma的方式读取Pcie function ```c void FPcieDmaRead(uintptr bar_address, struct FPcieDmaDescriptor *desc) ``` Input: - uintptr bar_address 基地地址寄存器的值 - struct FPcieDmaDescriptor *desc 接收描述符的起始地址 #### FPcieDmaWrite - 通过dma的方式写入Pcie function ```c void FPcieDmaWrite(uintptr bar_address, struct FPcieDmaDescriptor *desc) ``` Input: - uintptr bar_address 基地地址寄存器的值 - struct FPcieDmaDescriptor *desc 发送描述符的起始地址 #### FPcieDmaPollDone - 轮询等待DMA完成 ```c FError FPcieDmaPollDone(struct FPcieDmaDescriptor *desc, u32 wait_cnt) ``` Input: - struct FPcieDmaDescriptor *desc Desc是需要等待完成的dma 描述符 - u32 wait_cnt 是需要等待结束的计数 #### FPcieFetchDeviceInBus - 该功能用于扫描整个总线上的树形结构,并且对其中的节点进行初始化与配置空间的设置 ```c FError FPcieFetchDeviceInBus(FPcie *instance_p, u32 bus_num) ``` Input: - FPcie *instance_p 指向FPcie实例的指针。 - u32 bus_num 扫描对应总线上已经连接的网桥/端点。 Output: - FError FT_SUCCESS 为成功 #### FPcieFindDeviceNum - 根据输入的Vendor ID 与 Device ID ,获取当前PCIE 总线上一共存在多少此类设备 ```c u32 FPcieFindDeviceNum(FPcie *instance_p, u32 bus_num,u32 vendor_id,u32 device_id) ``` Input: - FPcie *instance_p 指向FPcie实例的指针。 - u32 bus_num 需要查找的bus号 - u32 vendor_id 目标 Vendor ID - u32 device_id 目标 Device ID Output: - u32 return 所需查找设备的数量 #### FPcieGetBusDeviceBarInfo - 通过Vendor ID和device ID获取对应的function id、device id 和 bar 空间 ```c FError FPcieGetBusDeviceBarInfo(FPcie *instance_p,u32 bus,u32 vendor_id,u32 device_id,u32 bar_num ,u32 *device_p,u32 *function_p,uintptr *bar_addr_p) ``` Input: - FPcie *instance_p 指向FPcie实例的指针。 - u32 bus 需要查找的bus号 - u32 vendor_id 目标 Vendor ID - u32 device_id 目标 Device ID - u32 bar_num 需要查找对应bar空间的编号 Output: - u32 * device_p 需要获取对应设备号的指针 - u32 * function_p 需要获取对应功能号的指针 - uintptr * bar_addr_p 需要获取对应bar地址空间的指针 - FError return FT_SUCCESS 为成功 #### FPcieSearchFunByClass - 使用 class code 获取设备的信息 ```c u32 FPcieSearchFunByClass(FPcie *instance_p,u32 class_code,FPcieSearchFunNode *node_p ,u32 node_num) ``` Input: - FPcie *instance_p 指向FPcie实例的指针。 - u32 class_code 对应的类号 - FPcieSearchFunNode * node_p 是一个存放特定函数信息缓冲区的指针 - u32 node_num 缓冲器的数量 Output: - u32 return 输出中的实际节点的个数 #### FPcieIntxIrqHandler - fpcie的Intx中断服务函数 ```c void FPcieIntxIrqHandler(s32 vector, void *args) ``` Input: - s32 vector 中断向量号 - void * args 需要传入的参数 #### FPcieIntxRegiterIrqHandler - 使用bus id、device id 和function id在INTX上注册中断响应函数 ```c FError FPcieIntxRegiterIrqHandler(FPcie *instance_p, u32 bus, u32 device, u32 function, FPcieIntxFun *intx_fun_p) ``` Input: - FPcie *instance_p 指向FPcie实例的指针。 - u32 bus 需要配置的bus id - u32 device 需要配置的device id - u32 function 需要配置的function id - FPcieIntxFun * intx_fun_p 是用户用来注册回调函数信息的指针