Provided by: freebsd-manpages_12.2-1_all bug

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 desciptor.  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.