在我还没有台式电脑的时候,我一直都很好奇PCIe协议能承载什么设备。
常见的无非是硬盘、网卡、USB控制器之类。
不过类比一下,USB接口能实现很多功能,但是像免驱的外置显卡/DMA等却很少见。
我听说的DMA游戏外挂都是基于“高贵的PCIe”的。
于是我把目光投向了FPGA,用于自定义PCIe设备。
市面上原生自带PCIe通道的FPGA开发板价格基本千元起步。
经过一番寻找,我最终在选择了浪潮 FPGA XC7K480T。
这应该是一张矿卡加速卡,但是价格非常美丽(某鱼300r),还板载了DDR颗粒(LPDDR3 4G)。
它的主控属于Kintex系列,官网资料显示拥有478K个Logic Cells和32个GTX Transceivers。
这个资源别说原生PCIe DMA,剩下的资源搭建几个riscv核都绰绰有余了。
接下来就是找一台支持PCIe设备的电脑了。
PCIe接口有一个优点:x1到x16通道、1.0到5.0是向下兼容的。
而且只要是开放式卡槽,能插进去就能用,最坏的情况也就是协商到PCIe1.0 x1通道降速运行。
当时我的主力机是一台笔记本,主要用于开发编译,如果用M.2转PCIe需要拆后盖,操作起来也很危险。
偏偏我手里又没有树莓派5这种带PCIe的开发板。
于是,我翻出了一个吃灰已久的OPS电脑模块。
这是我高中学校更换投影仪时,我从垃圾堆里捡回来的。
为了点亮它,我最大的投入是花了几十买了个魔改电源。
(其实,以我现在画PCB的能力,用快充诱骗+DC5525接头,完全可以自己做一个的)
这台OPS采用AMD处理器,板载两个mini-PCIe插槽,分别插着无线网卡和128G固态硬盘。
PCB上其实还有一个SATA接口,只是没有焊接插座。
为了连接FPGA,我在某宝买了一个mini-PCIe转PCIe转接卡。
(实际上只有PCIe x1通道可用,所以买x1开放式槽或者x16槽都一样,能插进去就行)
不过我接下来依次遇到两个问题:
- Linux找不到设备(设备无法初始化,似乎卡在重置前状态)
- 供电不足,设备指示灯闪烁
我用Vivado编译并用JTAG刷入了XDMA例程,也在Linux下编译安装了驱动,这里不再赘述。
但进入Linux后,lspci没有自定义设备,dmesg也没有任何相关日记。
起初我怀疑是Linux的问题,但更像是物理层面上就没有连上FPGA。
接下来我怀疑是开发板坏了,但是商家发货时提供了眼图,板子硬件损坏的概率不大。
然后我怀疑是供电不足,对着PCIe金手指的定义量了一圈,3.3V、12V电压基本没问题。
但在测量的最后,我发现PERST#(PCIe复位信号)始终为低——正常情况下,开机后不久这个信号是会被拉高的。
测量对地阻值只有1k。测量与3.3V的电阻时,先是高阻态、随后立刻变成1k,电压也被拉高,此时再测对地电阻又接近高阻态了。
我猜内部是用触发器实现的,但是修改了很多属性也没能成功,我的电脑编译一次要20分钟实在等不了就放弃了
为了对比验证,我又买了一个PCIe网卡插上去,发现网卡能正常使用,且对VCC和GND的电阻均为高阻态。
那我只能来硬的了,我在开机之前手动将VCC和PERST#短接,重复多次终于有一次能识别并使用设备了。
不过紧接着遇到了第二个问题:设备会经常反复重启。万用表一量,12V供电掉到了10V。
我估计这里的12V是转接卡从mini-pcie的3.3V升压得来的。
毕竟mini-pcie能提供的功率有限,市面上大部分这种转接卡都需要外接辅助供电,一般是从主机的SATA电源取电。
SATA接口本可以提供12V、5V和3.3V电源,但遗憾的是我的OPS主板上12V是浮空的(能看出来没有过孔也没有走线,万用表测量确实没有12V输出)
我把FPGA XDMA的功能裁剪,去除了DRAM控制器,用SRAM矩阵代替内存,功率降到了几W终于不重启了。不过没有DRAM还是不行。
我购买了一个12V DC充电器,剪断电源线飞线连接到了SATA的6pin供电线上,终于稳定了。
(我担心会有电源倒灌的问题,不过好在没有发生,但是不知道哪里漏电了,金属外壳带电了摸上去麻麻的)
我手动短接了几次找到了技巧,但是每次都短接终究不是长久之计。
我在转换器上,飞线了一个1k电阻上拉到3.3V(一开始用了10k,但是只能拉到1.5v)。
这样虽然是非标准的,但是我的情况可以稳定使用了。
再次进入linux系统,官方的实例传输和读取小文件都没问题,这段经历就告一段落了。
(这也让我意识到,DMA的能访问的内存是内核分配的,IOMMU也会阻止非授权的内存访问,所以DMA外挂也需要主机驱动配合啊)
现在有了台式机,主板上自带很多PCIe插槽,还有我梦寐以求的原生x16通道。再也不用这么麻烦的方式了。
这是我回忆半年前的经历写下的文字,细节可能有所出入