我正在Qemu和来宾OS中的驱动程序(LKM)上编写PCI设备。虽然Qemu提供了一个示例PCI设备, edu (edu.txt和edu.c)及其发行版本,但我在编写内核模块以进行DMA传输时遇到了麻烦。 here已介绍了基本驱动程序,但它不支持DMA。
我正在跟踪链接和this的实现。我试图从IRQ处理程序将缓冲区传输到PCI设备。设备可以读取数据( pci_dma_read ),但是我没有得到应该接收的正确数据。这是执行DMA传输的代码段:
static int write_to_HyPerf(void *dev, void* addr, uint32_t size)
{
/* ----------------------------------------------------------------------------
* PCI address 'addr':
* addr -> DMA source address
* 0x40000 -> DMA destination address
* 100 -> DMA transfer count
* 1 -> DMA command register
* while (DMA command register & 1)
*--------------------------------------------------------------------------------
*/
iowrite32((u32 *)dma_handle_to_device, mmio + IO_DMA_SRC);
iowrite32(DMA_START, mmio + IO_DMA_DST);
iowrite32((u32 *)size, mmio + IO_DMA_XCNT);
iowrite32(DMA_CMD | DMA_IRQ, mmio + IO_DMA_CMD);
}
我还使用 dma_alloc_coherent 进行了设置一致性映射。
vaddr_to_device = dma_alloc_coherent(&(dev->dev), DMA_SIZE, &dma_handle_to_device, GFP_ATOMIC);
完整的代码可用here。我在做什么错了?
答案 0 :(得分:0)
可能是您的驱动程序有问题。
在这种情况下,您可以使用以下命令: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/qemu_edu.c
,您可以像在此脚本中一样使用dd命令来从您的设备进行写入和读取: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/qemu_edu.sh
然后,您所需要做的就是将所需的dma值写入正确的地址 就像在edu.c代码中一样:
case 0x80:
dma_rw(edu, false, &val, &edu->dma.src, false);
break;
case 0x88:
dma_rw(edu, false, &val, &edu->dma.dst, false);
break;
case 0x90:
dma_rw(edu, false, &val, &edu->dma.cnt, false);
break;
case 0x98:
dma_rw(edu, false, &val, &edu->dma.cmd, false);
break;