本来以为把 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驱动,但是它能给你一点点写代码的勇气...🫶)