User mode drivers

来源:互联网 发布:sql在表中添加字段 编辑:程序博客网 时间:2024/06/05 14:07

As many of you will be aware, we've been working on infrastructure for
user-mode PCI and other drivers. The first step is to be able to
handle interrupts from user space. Subsequent patches add
infrastructure for setting up DMA for PCI devices.

The user-level interrupt code doesn't depend on the other patches, and
is probably the most mature of this patchset.


This patch adds a new file to /proc/irq/<nnn>/ called irq. Suitably
privileged processes can open this file. Reading the file returns the
number of interrupts (if any) that have occurred since the last read.
If the file is opened in blocking mode, reading it blocks until
an interrupt occurs. poll(2) and select(2) work as one would expect, to
allow interrupts to be one of many events to wait for.
(If you didn't like the file, one could have a special system call to
return the file descriptor).

Interrupts are usually masked; while a thread is in poll(2) or read(2) on the
file they are unmasked.

All architectures that use CONFIG_GENERIC_HARDIRQ are supported by
this patch.

A low latency user level interrupt handler would do something like
this, on a CONFIG_PREEMPT kernel:

int irqfd;
int n_ints;
struct sched_param sched_param;

irqfd = open("/proc/irq/513/irq", O_RDONLY);
mlockall()
sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 10;
sched_setscheduler(0, SCHED_FIFO, &sched_param);

while(read(irqfd, n_ints, sizeof n_ints) == sizeof nints) {
... talk to device to handle interrupt
}

If you don't care about latency, then forget about the mlockall() and
setting the priority, and you don't need CONFIG_PREEMPT.


USER LEVEL DRIVERS: enable PCI device drivers at user space.

This patch adds the capability for suitably privileged user-level processes to
enable a PCI device, and set up DMA for it. A subsequent patch hooks up
the actual system calls.

There are three new system calls:

long usr_pci_open(int bus, int slot, int function, __u64 dma_mask);
Returns a filedescriptor for the PCI device described
by bus,slot,function. It also enables the device, and sets it
up as a bus-mastering DMA device, with the specified dma mask.

Error codes are:
ENOMEM: insufficient kernel memory to fulfil your request
ENOENT: the specified device doesn't exist, or is otherwise
invisible to Linux.
EBUSY: Another driver has claimed the device
EIO: The specified dma mask is invalid for this device.
ENFILE: too many open files

long usr_pci_get_consistent(int fd, size_t size, void **vaddrp, unsigned long *dmaaddrp)

Call pci_alloc_consistent() to get size worth of pci
consistent memory (currently an error if size != PAGESIZE);
map the allocated memory into the user's address space;
return the virtual user address in *vaddrp, and the bus
address in *dmaaddrp

ERRORS:
EINVAL: the filedescriptor was not one obtained from usr_pci_open(), or
size != PAGESIZE
ENOMEM: insufficient appropriate memory or insufficient free
virtual address space in the user program.
EFAULT: vaddrp or dmaaddrp didn't point to writeable memory.

The mapping obtained can be cleaned up with munmap().

long usr_pci_mmap(int fd, struct mapping_info *mp) --
map some memory for DMA to/from the device represented by fd,
which was obtained from usr_pci_open().

struct mapping_info contains:
void *virtaddr -- the virtual address to dma to
int size -- how many bytes to set up
struct usr_pci_sglist *sglist -- a pointer to a scatterlist
int nents -- how many entries in the scatterlist
enum dma_data_direction direction --- which way the
dma is going to happen.

The scatterlist should be sized at least size/PAGESIZE + 2.

usr_pci_mmap() will call pci_map_sg() on the virtual region,
then copy the resulting scatterlist into *sglist. The nents field
will be updated with the actual number of scatterlist entries filled in.

Failure codes are:
EINVAL: the fd wasn't obtained from usr_pci_open, or
direction wasn't one of DMA_TO_DEVICE, DMA_FROM_DEVICE
or DMA_BIDIRECTIONAL, or the size of the
scatterlist is insufficient to map the region.
EFAULT: mp was a bad pointer, or the region of memory spanned
by (virtaddr, virtaddr + size) was not all mapped.
ENOMEM: insufficient appropriate memory

long usr_pci_munmap(int fd, struct mapping_info *mp)
Unmap a dma region mapped by usr_pci_map().
Struct mapping info is the same one used in usr_pci_mmap().

Error codes are:
EINVAL: : the fd wasn't obtained from usr_pci_open, or the
struct mapping_info was never mapped for this device

Ref:

http://www.gossamer-threads.com/lists/linux/kernel/1140388

0 0
原创粉丝点击