PROTO(4) FreeBSD Kernel Interfaces Manual PROTO(4)
NAME
proto - Generic prototyping and diagnostics driver
SYNOPSIS
To compile this driver into the kernel, place the following line in your
kernel configuration file:
device proto
Alternatively, to load the driver as a module at boot time, place the
following line in loader.conf(5):
proto_load="YES"
To have the driver attach to a device instead of its regular driver,
mention it in the list of devices assigned to the following loader
variable:
hw.proto.attach="desc[,desc]"
DESCRIPTION
The proto device driver attaches to PCI or ISA devices when no other
device drivers are present for those devices and it creates device
special files for all resources associated with the device. The driver
itself has no knowledge of the device it attaches to. Programs can open
these device special files and perform register-level reads and writes.
As such, the proto device driver is nothing but a conduit or gateway
between user space programs and the hardware device.
Examples for why this is useful include hardware diagnostics and
prototyping. In both these use cases, it is far more convenient to
develop and run the logic in user space. Especially hardware diagnostics
requires a somewhat user-friendly interface and adequate reporting.
Neither is done easily as kernel code.
I/O port resources
Device special files created for I/O port resources allow lseek(2),
read(2), write(2) and ioctl(2) operations to be performed on them. The
read(2) and write(2) system calls are used to perform input and output
(resp.) on the port. The amount of data that can be read or written at
any single time is either 1, 2 or 4 bytes. While the proto driver does
not prevent reading or writing 8 bytes at a time for some architectures,
it should not be assumed that such actually produces correct results.
The lseek(2) system call is used to select the port number, relative to
the I/O port region being represented by the device special file. If,
for example, the device special file corresponds to an I/O port region
from 0x3f8 to 0x3ff inclusive, then an offset of 4 given to lseek with a
whence value of SEEK_SET will target port 0x3fc on the next read or write
operation. The ioctl(2) system call can be used for the PROTO_IOC_REGION
request. This ioctl request returns the extend of the resource covered
by this device special file. The extend is returned in the following
structure:
struct proto_ioc_region {
unsigned long address;
unsigned long size;
};
Memory mapped I/O resources
The device special files created for memory mapped I/O resources behave
in the same way as those created for I/O port resources. Additionally,
device special files for memory mapped I/O resources allow the memory to
be mapped into the process' address space using mmap(2). Reads and
writes to the memory address returned by mmap(2) go directly to the
hardware. As such the use of read(2) and write(2) can be avoided,
reducing the access overhead significantly. Alignment and access width
constraints put forth by the underlying device apply. Also, make sure
the compiler does not optimize memory accesses away or has them coalesced
into bigger accesses.
DMA pseudo resource
A device special file named busdma is created for the purpose of doing
DMA. It only supports ioctl(2) and only for the PROTO_IOC_BUSDMA
request. This device special file does not support read(2) nor write(2).
The PROTO_IOC_BUSDMA request has an argument that is both in and out and
is defined as follows:
struct proto_ioc_busdma {
unsigned int request;
unsigned long key;
union {
struct {
unsigned long align;
unsigned long bndry;
unsigned long maxaddr;
unsigned long maxsz;
unsigned long maxsegsz;
unsigned int nsegs;
unsigned int datarate;
unsigned int flags;
} tag;
struct {
unsigned long tag;
unsigned int flags;
unsigned long virt_addr;
unsigned long virt_size;
unsigned int phys_nsegs;
unsigned long phys_addr;
unsigned long bus_addr;
unsigned int bus_nsegs;
} md;
struct {
unsigned int op;
unsigned long base;
unsigned long size;
} sync;
} u;
unsigned long result;
};
The request field is used to specify which DMA operation is to be
performed. The key field is used to specify which object the operation
applies to. An object is either a tag or a memory descriptor (md). The
following DMA operations are defined:
PROTO_IOC_BUSDMA_TAG_CREATE
Create a root tag. The result field is set on output with the key
of the DMA tag. The tag is created with the constraints given by
the tag sub-structure. These constraints correspond roughly to
those that can be given to the bus_dma_tag_create(9) function.
PROTO_IOC_BUSDMA_TAG_DERIVE
Create a derived tag. The key field is used to identify the parent
tag from which to derive the new tag. The key of the derived tag
is returned in the result field. The derived tag combines the
constraints of the parent tag with those given by the tag sub-
structure. The combined constraints are written back to the tag
sub-structure on return.
PROTO_IOC_BUSDMA_TAG_DESTROY
Destroy a root or derived tag previously created. The key field
specifies the tag to destroy. A tag can only be destroyed when not
referenced anymore. This means that derived tags that have this
tag as a parent and memory descriptors created from this tag must
be destroyed first.
PROTO_IOC_BUSDMA_MEM_ALLOC
Allocate memory that satisfies the constraints put forth by the tag
given in the tag field of the md sub-structure. The key of the
memory descriptor for this memory is returned in the result field.
The md sub-structure is filled on return with details of the
allocation. The kernel virtual address and the size of the
allocated memory are returned in the virt_addr and virt_size
fields. The number of contigous physical memory segments and the
address of the first segment are returned in the phys_nsegs and
phys_addr fields. Allocated memory is automatically loaded and
thus mapped into bus space. The number of bus segments and the
address of the first segment are returned in the bus_nsegs and
bus_addr fields. The behaviour of this operation banks heavily on
how bus_dmamem_alloc(9) is implemented, which means that memory is
currently always allocated as a single contigous region of physical
memory. In practice this also tends to give a single contigous
region in bus space. This may change over time.
PROTO_IOC_BUSDMA_MEM_FREE
Free previously allocated memory and destroy the memory descriptor.
The proto driver is not in a position to track whether the memory
has been mapped in the process' address space, so the application
is responsible for unmapping the memory before it is freed. The
proto driver also cannot protect against the hardware writing to or
reading from the memory, even after it has been freed. When the
memory is reused for other purposes it can be corrupted or cause
the hardware to behave in unpredictable ways when DMA has not
stopped completely before freeing.
PROTO_IOC_BUSDMA_MD_CREATE
Create an empty memory descriptor with the tag specified in the tag
field of the md sub-structure. The key of the memory descriptor is
returned in the result field.
PROTO_IOC_BUSDMA_MD_DESTROY
Destroy the previously created memory descriptor specified by the
key field. When the memory descriptor is still loaded, it is
unloaded first.
PROTO_IOC_BUSDMA_MD_LOAD
Load a contigous region of memory in the memory descriptor
specified by the key field. The size and address in the process'
virtual address space are specified by the virt_size and virt_addr
fields. On return, the md sub-structure contains the result of the
operation. The number of physical segments and the address of the
first segment is returned in the phys_nsegs and phys_addr fields.
The number of bus space segments and the address of the first
segment in bus space is returned in the bus_nsegs and bus_addr
fields.
PROTO_IOC_BUSDMA_MD_UNLOAD
Unload the memory descriptor specified by the key field.
PROTO_IOC_BUSDMA_SYNC
Guarantee that all hardware components have a coherent view of the
memory tracked by the memory descriptor, specified by the key
field. A sub-section of the memory can be targeted by specifying
the relative offset and size of the memory to make coherent. The
offset and size are given by the base and size fields of the sync
sub-structure. The op field holds the sync operation to be
performed. This is similar to the bus_dmamap_sync(9) function.
PCI configuration space
Access to PCI configuration space is possible through the pcicfg device
special file. The device special file supports lseek(2), read(2) and
write(2). Usage is the asme as for I/O port resources.
FILES
All device special files corresponding to a PCI device are located under
/dev/proto/pci<d>:<b>:<s>:<f> with pci<d>:<b>:<s>:<f> representing the
location of the PCI device in the PCI hierarchy. A PCI location
includes:
<d> The PCI domain number
<b> The PCI bus number
<s> The PCI slot or device number
<f> The PCI function number
Every PCI device has a device special file called pcicfg. This device
special file gives access to the PCI configuration space. A device
special file called busdma is also created. This device special file
provides the interfaces needed for doing DMA. For each valid base
address register (BAR), a device special file is created that contains
the BAR offset and the resource type. A resource type can be either io
or mem representing I/O port or memory mapped I/O space (resp.)
ISA devices do not have a location. Instead, they are identified by the
first I/O port address or first memory mapped I/O address. Consequently,
all device special files corresponding to an ISA device are located under
/dev/proto/isa:<addr> with addr the address in hexadecimal notation. For
each I/O port or memory mapped I/O address, a device special file is
created that contains the resource identification used by the kernel and
the resource type. The resource type can be either io or mem
representing I/O port or memory mapped I/O space (resp.) When the device
has a DMA channel assigned to it, a device special file with the name
busdma is created as well. This device special file provides the
interfaces needed for doing DMA.
If the ISA device is not a Plug-and-Play device nor present in the ACPI
device tree, it must have the appropriate hints so that the kernel can
reserve the resources for it.
EXAMPLES
A single function PCI device in domain 0, on bus 1, in slot 2 and having
a single memory mapped I/O region will have the following device special
files:
/dev/proto/pci0:1:2:0/10.mem
/dev/proto/pci0:1:2:0/pcicfg
A legacy floppy controller will have the following device files:
/dev/proto/isa:0x3f0/00.io
/dev/proto/isa:0x3f0/01.io
/dev/proto/isa:0x3f0/busdma
SEE ALSO
ioctl(2), lseek(2), mmap(2), read(2), write(2), bus_dma_tag_create(9),
bus_dmamap_sync(9), bus_dmamem_alloc(9)
AUTHORS
The proto device driver and this manual page were written by Marcel
Moolenaar <marcel@xcllnt.net>.
SECURITY CONSIDERATIONS
Because programs have direct access to the hardware, the proto driver is
inherently insecure. It is not advisable to use this driver on a
production machine.
MISSING FUNCTIONALITY
The proto driver does not fully support memory descriptors that need
multiple physical memory segments or multiple bus space segments. At the
very least, an operation is needed on the DMA pseudo resource for the
application to obtain all segments.
The proto driver does not yet support interrupts. Since interrupts
cannot be handled by the driver itself, they must be converted into
signals and delivered to the program that has registered for interrupts.
A satisfactory mechanism for keeping the interrupt masked during the
signal handling is still being worked out.
DMA support for devices other than busmaster devices is not present yet.
The details of how a program is to interact with the DMA controller still
need to be fleshed out.
FreeBSD 13.1-RELEASE-p6 August 7, 2015 FreeBSD 13.1-RELEASE-p6
man2web Home...