mirror of https://gitee.com/openkylin/linux.git
docs: driver-api: device-io: Document I/O access functions
This adds more detailed descriptions of the various read/write primitives available for use with I/O memory/ports. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
7c566bb5e4
commit
eeba4b0168
|
@ -146,6 +146,144 @@ There are also equivalents to memcpy. The ins() and
|
|||
outs() functions copy bytes, words or longs to the given
|
||||
port.
|
||||
|
||||
__iomem pointer tokens
|
||||
======================
|
||||
|
||||
The data type for an MMIO address is an ``__iomem`` qualified pointer, such as
|
||||
``void __iomem *reg``. On most architectures it is a regular pointer that
|
||||
points to a virtual memory address and can be offset or dereferenced, but in
|
||||
portable code, it must only be passed from and to functions that explicitly
|
||||
operated on an ``__iomem`` token, in particular the ioremap() and
|
||||
readl()/writel() functions. The 'sparse' semantic code checker can be used to
|
||||
verify that this is done correctly.
|
||||
|
||||
While on most architectures, ioremap() creates a page table entry for an
|
||||
uncached virtual address pointing to the physical MMIO address, some
|
||||
architectures require special instructions for MMIO, and the ``__iomem`` pointer
|
||||
just encodes the physical address or an offsettable cookie that is interpreted
|
||||
by readl()/writel().
|
||||
|
||||
Differences between I/O access functions
|
||||
========================================
|
||||
|
||||
readq(), readl(), readw(), readb(), writeq(), writel(), writew(), writeb()
|
||||
|
||||
These are the most generic accessors, providing serialization against other
|
||||
MMIO accesses and DMA accesses as well as fixed endianness for accessing
|
||||
little-endian PCI devices and on-chip peripherals. Portable device drivers
|
||||
should generally use these for any access to ``__iomem`` pointers.
|
||||
|
||||
Note that posted writes are not strictly ordered against a spinlock, see
|
||||
Documentation/driver-api/io_ordering.rst.
|
||||
|
||||
readq_relaxed(), readl_relaxed(), readw_relaxed(), readb_relaxed(),
|
||||
writeq_relaxed(), writel_relaxed(), writew_relaxed(), writeb_relaxed()
|
||||
|
||||
On architectures that require an expensive barrier for serializing against
|
||||
DMA, these "relaxed" versions of the MMIO accessors only serialize against
|
||||
each other, but contain a less expensive barrier operation. A device driver
|
||||
might use these in a particularly performance sensitive fast path, with a
|
||||
comment that explains why the usage in a specific location is safe without
|
||||
the extra barriers.
|
||||
|
||||
See memory-barriers.txt for a more detailed discussion on the precise ordering
|
||||
guarantees of the non-relaxed and relaxed versions.
|
||||
|
||||
ioread64(), ioread32(), ioread16(), ioread8(),
|
||||
iowrite64(), iowrite32(), iowrite16(), iowrite8()
|
||||
|
||||
These are an alternative to the normal readl()/writel() functions, with almost
|
||||
identical behavior, but they can also operate on ``__iomem`` tokens returned
|
||||
for mapping PCI I/O space with pci_iomap() or ioport_map(). On architectures
|
||||
that require special instructions for I/O port access, this adds a small
|
||||
overhead for an indirect function call implemented in lib/iomap.c, while on
|
||||
other architectures, these are simply aliases.
|
||||
|
||||
ioread64be(), ioread32be(), ioread16be()
|
||||
iowrite64be(), iowrite32be(), iowrite16be()
|
||||
|
||||
These behave in the same way as the ioread32()/iowrite32() family, but with
|
||||
reversed byte order, for accessing devices with big-endian MMIO registers.
|
||||
Device drivers that can operate on either big-endian or little-endian
|
||||
registers may have to implement a custom wrapper function that picks one or
|
||||
the other depending on which device was found.
|
||||
|
||||
Note: On some architectures, the normal readl()/writel() functions
|
||||
traditionally assume that devices are the same endianness as the CPU, while
|
||||
using a hardware byte-reverse on the PCI bus when running a big-endian kernel.
|
||||
Drivers that use readl()/writel() this way are generally not portable, but
|
||||
tend to be limited to a particular SoC.
|
||||
|
||||
hi_lo_readq(), lo_hi_readq(), hi_lo_readq_relaxed(), lo_hi_readq_relaxed(),
|
||||
ioread64_lo_hi(), ioread64_hi_lo(), ioread64be_lo_hi(), ioread64be_hi_lo(),
|
||||
hi_lo_writeq(), lo_hi_writeq(), hi_lo_writeq_relaxed(), lo_hi_writeq_relaxed(),
|
||||
iowrite64_lo_hi(), iowrite64_hi_lo(), iowrite64be_lo_hi(), iowrite64be_hi_lo()
|
||||
|
||||
Some device drivers have 64-bit registers that cannot be accessed atomically
|
||||
on 32-bit architectures but allow two consecutive 32-bit accesses instead.
|
||||
Since it depends on the particular device which of the two halves has to be
|
||||
accessed first, a helper is provided for each combination of 64-bit accessors
|
||||
with either low/high or high/low word ordering. A device driver must include
|
||||
either <linux/io-64-nonatomic-lo-hi.h> or <linux/io-64-nonatomic-hi-lo.h> to
|
||||
get the function definitions along with helpers that redirect the normal
|
||||
readq()/writeq() to them on architectures that do not provide 64-bit access
|
||||
natively.
|
||||
|
||||
__raw_readq(), __raw_readl(), __raw_readw(), __raw_readb(),
|
||||
__raw_writeq(), __raw_writel(), __raw_writew(), __raw_writeb()
|
||||
|
||||
These are low-level MMIO accessors without barriers or byteorder changes and
|
||||
architecture specific behavior. Accesses are usually atomic in the sense that
|
||||
a four-byte __raw_readl() does not get split into individual byte loads, but
|
||||
multiple consecutive accesses can be combined on the bus. In portable code, it
|
||||
is only safe to use these to access memory behind a device bus but not MMIO
|
||||
registers, as there are no ordering guarantees with regard to other MMIO
|
||||
accesses or even spinlocks. The byte order is generally the same as for normal
|
||||
memory, so unlike the other functions, these can be used to copy data between
|
||||
kernel memory and device memory.
|
||||
|
||||
inl(), inw(), inb(), outl(), outw(), outb()
|
||||
|
||||
PCI I/O port resources traditionally require separate helpers as they are
|
||||
implemented using special instructions on the x86 architecture. On most other
|
||||
architectures, these are mapped to readl()/writel() style accessors
|
||||
internally, usually pointing to a fixed area in virtual memory. Instead of an
|
||||
``__iomem`` pointer, the address is a 32-bit integer token to identify a port
|
||||
number. PCI requires I/O port access to be non-posted, meaning that an outb()
|
||||
must complete before the following code executes, while a normal writeb() may
|
||||
still be in progress. On architectures that correctly implement this, I/O port
|
||||
access is therefore ordered against spinlocks. Many non-x86 PCI host bridge
|
||||
implementations and CPU architectures however fail to implement non-posted I/O
|
||||
space on PCI, so they can end up being posted on such hardware.
|
||||
|
||||
In some architectures, the I/O port number space has a 1:1 mapping to
|
||||
``__iomem`` pointers, but this is not recommended and device drivers should
|
||||
not rely on that for portability. Similarly, an I/O port number as described
|
||||
in a PCI base address register may not correspond to the port number as seen
|
||||
by a device driver. Portable drivers need to read the port number for the
|
||||
resource provided by the kernel.
|
||||
|
||||
There are no direct 64-bit I/O port accessors, but pci_iomap() in combination
|
||||
with ioread64/iowrite64 can be used instead.
|
||||
|
||||
inl_p(), inw_p(), inb_p(), outl_p(), outw_p(), outb_p()
|
||||
|
||||
On ISA devices that require specific timing, the _p versions of the I/O
|
||||
accessors add a small delay. On architectures that do not have ISA buses,
|
||||
these are aliases to the normal inb/outb helpers.
|
||||
|
||||
readsq, readsl, readsw, readsb
|
||||
writesq, writesl, writesw, writesb
|
||||
ioread64_rep, ioread32_rep, ioread16_rep, ioread8_rep
|
||||
iowrite64_rep, iowrite32_rep, iowrite16_rep, iowrite8_rep
|
||||
insl, insw, insb, outsl, outsw, outsb
|
||||
|
||||
These are helpers that access the same address multiple times, usually to copy
|
||||
data between kernel memory byte stream and a FIFO buffer. Unlike the normal
|
||||
MMIO accessors, these do not perform a byteswap on big-endian kernels, so the
|
||||
first byte in the FIFO register corresponds to the first byte in the memory
|
||||
buffer regardless of the architecture.
|
||||
|
||||
Public Functions Provided
|
||||
=========================
|
||||
|
||||
|
|
Loading…
Reference in New Issue