紧接着上篇文字提到的中断,我们继续往下走走看。这篇文字主要设计的是内存和地址的处理。
/* Clear pending interrupts */
xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS);
/* Enable interrupts */
xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG) | 0xfff);
// Mark that we don't have preallocated buffers
xtrxdev->buf_rx_size = 0;
xtrxdev->buf_tx_size = 0;
memset(xtrxdev->buf_rx, 0, sizeof(xtrxdev->buf_rx));//存的是地址所有要在使用前清0
memset(xtrxdev->buf_tx, 0, sizeof(xtrxdev->buf_tx));
err = xtrx_allocdma_rx(xtrxdev, BUF_SIZE); //申请一组
///#define BUF_SIZE 32768
if (err) {
dev_err(&pdev->dev, "Failed to register RX DMA buffers.\n");
err = -ENODEV;
goto err_irq_3;
}
err = xtrx_allocdma_tx(xtrxdev, BUF_SIZE);
if (err) {
dev_err(&pdev->dev, "Failed to register TX DMA buffers.\n");
err = -ENODEV;
goto err_rx_bufs;
}
这里的 xtrx_readl和xtrx_writel是读写FPGA内部的寄存器的。
32个结构,每个结构里面有一对地址,分别是虚拟地址virt 和物理地址phys. 这样就应该要形成32个环队列。
我们继续看看xtrx_allocdma_rx和xtrx_allocdma_tx.
我们看到xtrx_allocdma这个函数就是实现了用户虚拟地址和PCI物理地址的对应关系。rx在申请缓冲区时候还调用了xtrx_update_rxdma_len这个函数,我们看到实际就是写入了长度给FPGA的寄存器。
if ((GET_HWID_COMPAT(d->hwid) >= 1))
#define GET_HWID_COMPAT(x) ((x >> 8) & 0xff)
u32 hwid;
xtrxdev->hwid = xtrx_readl(xtrxdev, GP_PORT_RD_HWCFG);
这里看到根据硬件GP_PORT_RD_HWCFG寄存器确定版本号并确定是进行单独一个长度寄存器的设置还是甚至全部的长度寄存器。
这里我们实际运行一下看。因此我们看到实际是在这里更新长度实际是只写了一个寄存器。这应该是后续代码有升级,只需要修改一个长度就可以,因为都是一样长度。
static void xtrx_set_dma_bufs(struct xtrx_dev *d, struct xtrx_dmabuf_nfo *pbufs, unsigned config_off, unsigned len)
这个函数实际是给FPGA写了物理地址和长度。
这里实际可以考虑长度不变,就可少绕很多函数。
// DMA functions
static void xtrx_set_dma_bufs(struct xtrx_dev *d, struct xtrx_dmabuf_nfo *pbufs, unsigned config_off, unsigned len)
{
int i;
unsigned len_qw = len / 16;
printk(KERN_INFO PFX "liwei: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> xtrx_set_dma_bufs [%d] \n", __LINE__ );
//Initialize DMA buffers
for (i = 0; i < BUFS; i++) {
uintptr_t addr = ((uintptr_t)d->bar0_addr) + config_off + 4 * i;
uint32_t reg = ((len_qw - 1) & 0xFFF) | (0xFFFFF000 & pbufs[i].phys);
printk(KERN_NOTICE PFX "buf[%d]=%lx [virt %p] => %08x\n", i, (unsigned long)pbufs[i].phys, pbufs[i].virt, reg);
iowrite32(cpu_to_be32(reg), (void __iomem *)(addr));
memset(pbufs[i].virt, i+1, len);
}
}
我们看到了分配内存时候低12位都是0,这12位被利用起来保存长度。这里我们看到len到是怎样保存到12位里面的:1,首先左移4位(也就是除以16)。2,再减去1。其实这样就实现了12+4=16位的地址空间。所以我推测最大的长度是64K。
把BUFF_SIZE改大,超过64K,显示如下
显然超过64K出错了。
设置为65536实验过了是可以的。
我们要在FPGA里面实现FPGA自主的收发,就要告诉它一组收发的地址和长度。这篇文字的上述操作就做了这个事情。
上述分析似乎能看到驱动和FPGA之间的交互,但是没有看到用户的应用程序是如何跟驱动交互的。这在之后的分析要着重分析一下。