PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为是数据发送端和数据接收端。PCIe总线除了总线链路外,还具有多个层次,发送端发送数据时将通过这些层次,而接收端接收数据时也使用这些层次。似
FPCIE 模块内置两个 PCIE 单元(PCI-E Unit,PEU),分别为 PEU0 和 PEU1。每个 PEU 包含 3 个控制器:C0、C1 和 C2。当 PEU 拆分模式为 X16 时,C1 不可见。
本模块特点如下
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
以下部分将指导您完成 PCIE 驱动的软件配置:
"/baremetal/example/peripheral/fpcie_probe "
中断注册回调函数
typedef struct
{
void (*IntxCallBack)(void *args) ;
void *args ;
s32 bdf ;
} FPcieIntxFun;
初始化配置空间地址
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 */
};
驱动配置数据
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;
驱动控制数据
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
获取FPCIE驱动的默认配置参数
const FPcieConfig *FPcieLookupConfig(u32 instance_id)
Note:
FPcieCfgInitialize函数的入参使用Input:
Return:
初始化配置空间和FPCIE 实例
FError FPcieCfgInitialize(FPcie *instance_p, FPcieConfig *config_p)
Note:
Input:
FPcie *instance_p 指向FPcie实例的指针。
FPcieConfig *config_p 指向FPcieConfig的指针。
Return :
PCIE DMA描述符分组包
FError FPcieDmaDescSet(uintptr axi_addr,
uintptr bar_addr,
u32 length,
struct FPcieDmaDescriptor *desc,
struct FPcieDmaDescriptor *next_desc)
Note:
Input:
uintptr axi_addr 内存地址,可以为接收地址也可为发送地址
uintptr bar_addr 需要通信function中对应的bar寄存器中分配的地址空间,可以为接收地址也可为发送地址
u32 length 需要传输的字节长度
struct FPcieDmaDescriptor *next_desc 是下一个需要发送的描述符
Output:
Note:
通过dma的方式读取Pcie function
void FPcieDmaRead(uintptr bar_address, struct FPcieDmaDescriptor *desc)
Input:
uintptr bar_address 基地地址寄存器的值
struct FPcieDmaDescriptor *desc 接收描述符的起始地址
通过dma的方式写入Pcie function
void FPcieDmaWrite(uintptr bar_address, struct FPcieDmaDescriptor *desc)
Input:
uintptr bar_address 基地地址寄存器的值
struct FPcieDmaDescriptor *desc 发送描述符的起始地址
轮询等待DMA完成
FError FPcieDmaPollDone(struct FPcieDmaDescriptor *desc, u32 wait_cnt)
Input:
struct FPcieDmaDescriptor *desc Desc是需要等待完成的dma 描述符
u32 wait_cnt 是需要等待结束的计数
该功能用于扫描整个总线上的树形结构,并且对其中的节点进行初始化与配置空间的设置
FError FPcieFetchDeviceInBus(FPcie *instance_p, u32 bus_num)
Input:
FPcie *instance_p 指向FPcie实例的指针。
u32 bus_num 扫描对应总线上已经连接的网桥/端点。
Output:
根据输入的Vendor ID 与 Device ID ,获取当前PCIE 总线上一共存在多少此类设备
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:
通过Vendor ID和device ID获取对应的function id、device id 和 bar 空间
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 为成功
使用 class code 获取设备的信息
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:
fpcie的Intx中断服务函数
void FPcieIntxIrqHandler(s32 vector, void *args)
Input:
s32 vector 中断向量号
void * args 需要传入的参数
使用bus id、device id 和function id在INTX上注册中断响应函数
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 是用户用来注册回调函数信息的指针