Bootstrap

Linux PCIe Endpoint 调试笔记

本来以为把 PCIe RC 模式做出来, 手搓的PCIe function driver 能读能写能接收MSI, 就可以过了。 结果架构师不知从哪里翻出一个与金主爸爸的会议记录,上面白纸黑字地写着, 分给linux 那个PCIe 是用来做EP的。(😩大哥, 你早点说啊!)

😑,喷不过也得罪不起架构,只能回炉再造我的PCIe驱动。

在RC模式下, 测试用的PCIe function 驱动搓起来不难, iomap两个BAR Addr, 再设置下MSI 就完成了. linux 源码下一堆function driver的例子,总有一款能和你口味。但是PCIe Endpoint的栗子🌰就少了很多。 对我这种眼神清澈的初学者来说,想写 PCIe endpoint,却不知如何下手。

摸索了几天,总算小有收获。为了纪念掉落的头发, 写篇总结笔记吧。 

以下是干货

PCIe Controller 

之前的PCIe RC笔记有提过, 给Linux写PCIe driver, 主要写个中间层。 应用层Linux替你写了, 底层驱动也是synopsis 或 cadence 的大厂提供的。我们写的中间层也linkup自家的phy,然后调用下底层驱动的API进行初始化就好。 实在没思路,看看友商怎么写的吧。

一般来说, 我们只要写一个PCIe Controller 驱动就好,根据DTS中property将PCIe设置成RC或EP模式。也就一两个寄存器的事。

PCIe Endpoint

其实Linux自带 Endpoint Test Function (全文完)

以下内均为凑字数,大神就略过吧。

在Linux源码搜一下 pci-epf-test,你就能找到惊喜啦! 但是如果你的眼神跟我一样清澈的话,接着看吧

1. 记得在menuconfig 中启用 PCIe endpoint support 和 pci-epf-test 

2. 编译

3. 在console 下 按照以下步骤输入 

51000000.pcie_ep 是你的EP 名字, 根据你dts定义给PCIe label,可能会变。俺们就随机应变吧

Endpoint Controller Devices

To find the list of endpoint controller devices in the system:

# ls /sys/class/pci_epc/
  51000000.pcie_ep

If PCI_ENDPOINT_CONFIGFS is enabled:

# ls /sys/kernel/config/pci_ep/controllers
  51000000.pcie_ep

Endpoint Function Drivers

To find the list of endpoint function drivers in the system:

# ls /sys/bus/pci-epf/drivers
  pci_epf_test

If PCI_ENDPOINT_CONFIGFS is enabled:

# ls /sys/kernel/config/pci_ep/functions
  pci_epf_test

Creating pci-epf-test Device

PCI endpoint function device can be created using the configfs. To create pci-epf-test device, the following commands can be used:

# mount -t configfs none /sys/kernel/config
# cd /sys/kernel/config/pci_ep/
# mkdir functions/pci_epf_test/func1

The “mkdir func1” above creates the pci-epf-test function device that will be probed by pci_epf_test driver.

The PCI endpoint framework populates the directory with the following configurable fields:

# ls functions/pci_epf_test/func1
  baseclass_code        interrupt_pin   progif_code     subsys_id
  cache_line_size       msi_interrupts  revid           subsys_vendorid
  deviceid              msix_interrupts subclass_code   vendorid

The PCI endpoint function driver populates these entries with default values when the device is bound to the driver. The pci-epf-test driver populates vendorid with 0xffff and interrupt_pin with 0x0001:

# cat functions/pci_epf_test/func1/vendorid
  0xffff
# cat functions/pci_epf_test/func1/interrupt_pin
  0x0001

Configuring pci-epf-test Device

The user can configure the pci-epf-test device using configfs entry. In order to change the vendorid and the number of MSI interrupts used by the function device, the following commands can be used:

# echo 0x104c > functions/pci_epf_test/func1/vendorid
# echo 0xb500 > functions/pci_epf_test/func1/deviceid
# echo 16 > functions/pci_epf_test/func1/msi_interrupts
# echo 8 > functions/pci_epf_test/func1/msix_interrupts

Binding pci-epf-test Device to EP Controller

In order for the endpoint function device to be useful, it has to be bound to a PCI endpoint controller driver. Use the configfs to bind the function device to one of the controller driver present in the system:

# ln -s functions/pci_epf_test/func1 controllers/51000000.pcie_ep/

Once the above step is completed, the PCI endpoint is ready to establish a link with the host.

Start the Link

In order for the endpoint device to establish a link with the host, the _start_ field should be populated with ‘1’:

# echo 1 > controllers/51000000.pcie_ep/start

以上内容来自 https://docs.kernel.org/PCI/endpoint/pci-test-howto.html

4.  如果你希望这个用于测试的endpoint function 在linux kernel init 之后就被启用。你可以把以上给出的命令写成一个*.sh 脚本, 然后丢/etc/init.d/文件夹下就好。 不会的话,就去问你们家的integrator吧。

5.  要测试endpoint 功能的话, 可以使用pcitest.sh(具体看链接,懒得翻译了)。 但是这个脚本是给linux RC端用的。 如果你的RC端不是LINUX, 而是MCU的话......那只能自己手搓endpoint device function。🤔 (不会的话可以看看我之前的PCIe笔记哦,它虽然不能帮你搓代码,也教不会你写PCIe驱动,但是它能给你一点点写代码的勇气...🫶)

 

 

 

 

 

 

;