7

I am writing a PCIe driver for Linux, currently without DMA, and need to know how to read and write to the PCIe device once it is enabled from user space.

In the driver I do the basics in probe():

pci_enable_device();
pci_request_regions();
pci_iomap();

But then how do I access this memory from user space to read and write? Do I add file operations to my PCIe driver? Does the memory from pci_iomap show up some place where the user space code can call:

open('mapped memory location');
mmap(...);

If so then what is the location?

Note: the PCIe device will not plugging into any Linux subsystems such as audio, Ethernet, etc.

Adam B
  • 3,775
  • 3
  • 32
  • 42
user2205930
  • 1,046
  • 12
  • 26
  • 1
    Not sure if it's the recommended way of doing things, but other kernel drivers expose virtual devices like `/dev/vboxnetctl`, which I assume you can issue commands to. I'm not certain that the Linux kernel would allow any userspace program to read/write to a PCIe device willy-nilly, that sounds like it might be dangerous. – Naftuli Kay Feb 08 '16 at 18:41
  • 1
    I was looking at that as well. Is there anything I need to do in order for my device to show up there? For example, what API calls do I make in my driver? – user2205930 Feb 08 '16 at 19:16
  • 1
    Perhaps take a look at the VirtualBox driver source code for ideas. – Naftuli Kay Feb 08 '16 at 19:28
  • 1
    Btw, better to use `pcim_*()` API. – 0andriy Feb 15 '16 at 18:11
  • 1
    What is `pcim_*()` exactly and why should I be using it? Sometimes documentation for Linux can be painful to gather so could you please provide a sentence or two on it? – user2205930 Feb 16 '16 at 22:09

2 Answers2

4

If you just want to export memory from the kernel space to the user space and get interrupts, think about the UIO driver.

With it, all the accesses will be done through /dev/uioX file. You can do mmap() on it to export memory and you can read (with a blocking read) to "catch" the interrupt.

UIO is perfectly suited for PCIe, there already is a driver in kernel for it.

FabienM
  • 3,421
  • 23
  • 45
1

You can register devices using functions like register_chrdev and device_create. Consider the kernel source for /dev/null and /dev/mem:

static int __init chr_dev_init(void)
{
    int minor;

    if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
        printk("unable to get major %d for memory devs\n", MEM_MAJOR);

    mem_class = class_create(THIS_MODULE, "mem");
    if (IS_ERR(mem_class))
        return PTR_ERR(mem_class);

    mem_class->devnode = mem_devnode;
    for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
        if (!devlist[minor].name)
            continue;

        /*
         * Create /dev/port?
         */
        if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
            continue;

        device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
                  NULL, devlist[minor].name);
    }

    return tty_init();
}

fs_initcall(chr_dev_init);
antiduh
  • 11,853
  • 4
  • 43
  • 66
  • 1
    Yes, I eventually created a character device driver for my PCIe device. I would recommend others to read the Linux Device Drivers book, chapter 3, to learn more. It's outdated but you can pick out some basics to get you going. – user2205930 Feb 12 '16 at 00:11