5

I am writing a PCI device on Qemu and driver(LKM) in the guest OS. While Qemu provides an example PCI device, edu(edu.txt and edu.c) with it's distribution, I am having trouble writing the kernel module to do DMA transfer. A basic driver has been covered here but it does not support DMA.

I am following the implementation of the link and this. I tried to transmit buffer to the PCI device from the IRQ handler. The device can read the data (pci_dma_read) but the I am not getting the correct data that I am supposed to receive. Here is the code segment that is doing DMA transfer:

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);
}

I also have setup coherent mapping using dma_alloc_coherent.

vaddr_to_device = dma_alloc_coherent(&(dev->dev), DMA_SIZE, &dma_handle_to_device, GFP_ATOMIC);

The complete code is available here. What am I doing wrong?

Proy
  • 336
  • 2
  • 13

1 Answers1

0

Could be that you having problem in your driver.

In this case you can use this: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/qemu_edu.c

and you can use dd command as in this script to write and read from your device: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/qemu_edu.sh

Then all you need is to write the wanted dma values to the correct address like in the edu.c code:

    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;
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Dor marcus
  • 41
  • 5
  • When I tried to write to ```edu->dma.src``` at address 0x80 and then read such value. The value I got was not expected. According to the source code of edu device, it seems that reading from/writing to address 0x80 should be the same as that of address 0x08, which is the factorial field. However, for address 0x08 (fact), it works well; but for address 0x80, it did not work as expected. May I know if you have any ideas? Thanks in advance. – Ethan L. Dec 26 '21 at 09:14
  • not sure ... did you checked your endian is correct? (could be causing 0x80->0x08) – Dor marcus Dec 27 '21 at 11:47
  • Thanks for your reply. I made a "silly" mistake by writing to address 80 instead of 0x80. That is why for address 0x08 it works since 0x08 is equal to 8 in decimal, while for address 0x80 it does not work. – Ethan L. Dec 28 '21 at 08:33