|
@@ -1,323 +0,0 @@
|
|
|
-<?xml version="1.0" encoding="UTF-8"?>
|
|
|
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
|
|
- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
|
|
-
|
|
|
-<book id="DoingIO">
|
|
|
- <bookinfo>
|
|
|
- <title>Bus-Independent Device Accesses</title>
|
|
|
-
|
|
|
- <authorgroup>
|
|
|
- <author>
|
|
|
- <firstname>Matthew</firstname>
|
|
|
- <surname>Wilcox</surname>
|
|
|
- <affiliation>
|
|
|
- <address>
|
|
|
- <email>matthew@wil.cx</email>
|
|
|
- </address>
|
|
|
- </affiliation>
|
|
|
- </author>
|
|
|
- </authorgroup>
|
|
|
-
|
|
|
- <authorgroup>
|
|
|
- <author>
|
|
|
- <firstname>Alan</firstname>
|
|
|
- <surname>Cox</surname>
|
|
|
- <affiliation>
|
|
|
- <address>
|
|
|
- <email>alan@lxorguk.ukuu.org.uk</email>
|
|
|
- </address>
|
|
|
- </affiliation>
|
|
|
- </author>
|
|
|
- </authorgroup>
|
|
|
-
|
|
|
- <copyright>
|
|
|
- <year>2001</year>
|
|
|
- <holder>Matthew Wilcox</holder>
|
|
|
- </copyright>
|
|
|
-
|
|
|
- <legalnotice>
|
|
|
- <para>
|
|
|
- This documentation is free software; you can redistribute
|
|
|
- it and/or modify it under the terms of the GNU General Public
|
|
|
- License as published by the Free Software Foundation; either
|
|
|
- version 2 of the License, or (at your option) any later
|
|
|
- version.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- This program is distributed in the hope that it will be
|
|
|
- useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
- See the GNU General Public License for more details.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- You should have received a copy of the GNU General Public
|
|
|
- License along with this program; if not, write to the Free
|
|
|
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
- MA 02111-1307 USA
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- For more details see the file COPYING in the source
|
|
|
- distribution of Linux.
|
|
|
- </para>
|
|
|
- </legalnotice>
|
|
|
- </bookinfo>
|
|
|
-
|
|
|
-<toc></toc>
|
|
|
-
|
|
|
- <chapter id="intro">
|
|
|
- <title>Introduction</title>
|
|
|
- <para>
|
|
|
- Linux provides an API which abstracts performing IO across all busses
|
|
|
- and devices, allowing device drivers to be written independently of
|
|
|
- bus type.
|
|
|
- </para>
|
|
|
- </chapter>
|
|
|
-
|
|
|
- <chapter id="bugs">
|
|
|
- <title>Known Bugs And Assumptions</title>
|
|
|
- <para>
|
|
|
- None.
|
|
|
- </para>
|
|
|
- </chapter>
|
|
|
-
|
|
|
- <chapter id="mmio">
|
|
|
- <title>Memory Mapped IO</title>
|
|
|
- <sect1 id="getting_access_to_the_device">
|
|
|
- <title>Getting Access to the Device</title>
|
|
|
- <para>
|
|
|
- The most widely supported form of IO is memory mapped IO.
|
|
|
- That is, a part of the CPU's address space is interpreted
|
|
|
- not as accesses to memory, but as accesses to a device. Some
|
|
|
- architectures define devices to be at a fixed address, but most
|
|
|
- have some method of discovering devices. The PCI bus walk is a
|
|
|
- good example of such a scheme. This document does not cover how
|
|
|
- to receive such an address, but assumes you are starting with one.
|
|
|
- Physical addresses are of type unsigned long.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- This address should not be used directly. Instead, to get an
|
|
|
- address suitable for passing to the accessor functions described
|
|
|
- below, you should call <function>ioremap</function>.
|
|
|
- An address suitable for accessing the device will be returned to you.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- After you've finished using the device (say, in your module's
|
|
|
- exit routine), call <function>iounmap</function> in order to return
|
|
|
- the address space to the kernel. Most architectures allocate new
|
|
|
- address space each time you call <function>ioremap</function>, and
|
|
|
- they can run out unless you call <function>iounmap</function>.
|
|
|
- </para>
|
|
|
- </sect1>
|
|
|
-
|
|
|
- <sect1 id="accessing_the_device">
|
|
|
- <title>Accessing the device</title>
|
|
|
- <para>
|
|
|
- The part of the interface most used by drivers is reading and
|
|
|
- writing memory-mapped registers on the device. Linux provides
|
|
|
- interfaces to read and write 8-bit, 16-bit, 32-bit and 64-bit
|
|
|
- quantities. Due to a historical accident, these are named byte,
|
|
|
- word, long and quad accesses. Both read and write accesses are
|
|
|
- supported; there is no prefetch support at this time.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The functions are named <function>readb</function>,
|
|
|
- <function>readw</function>, <function>readl</function>,
|
|
|
- <function>readq</function>, <function>readb_relaxed</function>,
|
|
|
- <function>readw_relaxed</function>, <function>readl_relaxed</function>,
|
|
|
- <function>readq_relaxed</function>, <function>writeb</function>,
|
|
|
- <function>writew</function>, <function>writel</function> and
|
|
|
- <function>writeq</function>.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Some devices (such as framebuffers) would like to use larger
|
|
|
- transfers than 8 bytes at a time. For these devices, the
|
|
|
- <function>memcpy_toio</function>, <function>memcpy_fromio</function>
|
|
|
- and <function>memset_io</function> functions are provided.
|
|
|
- Do not use memset or memcpy on IO addresses; they
|
|
|
- are not guaranteed to copy data in order.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The read and write functions are defined to be ordered. That is the
|
|
|
- compiler is not permitted to reorder the I/O sequence. When the
|
|
|
- ordering can be compiler optimised, you can use <function>
|
|
|
- __readb</function> and friends to indicate the relaxed ordering. Use
|
|
|
- this with care.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- While the basic functions are defined to be synchronous with respect
|
|
|
- to each other and ordered with respect to each other the busses the
|
|
|
- devices sit on may themselves have asynchronicity. In particular many
|
|
|
- authors are burned by the fact that PCI bus writes are posted
|
|
|
- asynchronously. A driver author must issue a read from the same
|
|
|
- device to ensure that writes have occurred in the specific cases the
|
|
|
- author cares. This kind of property cannot be hidden from driver
|
|
|
- writers in the API. In some cases, the read used to flush the device
|
|
|
- may be expected to fail (if the card is resetting, for example). In
|
|
|
- that case, the read should be done from config space, which is
|
|
|
- guaranteed to soft-fail if the card doesn't respond.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The following is an example of flushing a write to a device when
|
|
|
- the driver would like to ensure the write's effects are visible prior
|
|
|
- to continuing execution.
|
|
|
- </para>
|
|
|
-
|
|
|
-<programlisting>
|
|
|
-static inline void
|
|
|
-qla1280_disable_intrs(struct scsi_qla_host *ha)
|
|
|
-{
|
|
|
- struct device_reg *reg;
|
|
|
-
|
|
|
- reg = ha->iobase;
|
|
|
- /* disable risc and host interrupts */
|
|
|
- WRT_REG_WORD(&reg->ictrl, 0);
|
|
|
- /*
|
|
|
- * The following read will ensure that the above write
|
|
|
- * has been received by the device before we return from this
|
|
|
- * function.
|
|
|
- */
|
|
|
- RD_REG_WORD(&reg->ictrl);
|
|
|
- ha->flags.ints_enabled = 0;
|
|
|
-}
|
|
|
-</programlisting>
|
|
|
-
|
|
|
- <para>
|
|
|
- In addition to write posting, on some large multiprocessing systems
|
|
|
- (e.g. SGI Challenge, Origin and Altix machines) posted writes won't
|
|
|
- be strongly ordered coming from different CPUs. Thus it's important
|
|
|
- to properly protect parts of your driver that do memory-mapped writes
|
|
|
- with locks and use the <function>mmiowb</function> to make sure they
|
|
|
- arrive in the order intended. Issuing a regular <function>readX
|
|
|
- </function> will also ensure write ordering, but should only be used
|
|
|
- when the driver has to be sure that the write has actually arrived
|
|
|
- at the device (not that it's simply ordered with respect to other
|
|
|
- writes), since a full <function>readX</function> is a relatively
|
|
|
- expensive operation.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Generally, one should use <function>mmiowb</function> prior to
|
|
|
- releasing a spinlock that protects regions using <function>writeb
|
|
|
- </function> or similar functions that aren't surrounded by <function>
|
|
|
- readb</function> calls, which will ensure ordering and flushing. The
|
|
|
- following pseudocode illustrates what might occur if write ordering
|
|
|
- isn't guaranteed via <function>mmiowb</function> or one of the
|
|
|
- <function>readX</function> functions.
|
|
|
- </para>
|
|
|
-
|
|
|
-<programlisting>
|
|
|
-CPU A: spin_lock_irqsave(&dev_lock, flags)
|
|
|
-CPU A: ...
|
|
|
-CPU A: writel(newval, ring_ptr);
|
|
|
-CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
|
|
- ...
|
|
|
-CPU B: spin_lock_irqsave(&dev_lock, flags)
|
|
|
-CPU B: writel(newval2, ring_ptr);
|
|
|
-CPU B: ...
|
|
|
-CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
|
|
-</programlisting>
|
|
|
-
|
|
|
- <para>
|
|
|
- In the case above, newval2 could be written to ring_ptr before
|
|
|
- newval. Fixing it is easy though:
|
|
|
- </para>
|
|
|
-
|
|
|
-<programlisting>
|
|
|
-CPU A: spin_lock_irqsave(&dev_lock, flags)
|
|
|
-CPU A: ...
|
|
|
-CPU A: writel(newval, ring_ptr);
|
|
|
-CPU A: mmiowb(); /* ensure no other writes beat us to the device */
|
|
|
-CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
|
|
- ...
|
|
|
-CPU B: spin_lock_irqsave(&dev_lock, flags)
|
|
|
-CPU B: writel(newval2, ring_ptr);
|
|
|
-CPU B: ...
|
|
|
-CPU B: mmiowb();
|
|
|
-CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
|
|
-</programlisting>
|
|
|
-
|
|
|
- <para>
|
|
|
- See tg3.c for a real world example of how to use <function>mmiowb
|
|
|
- </function>
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- PCI ordering rules also guarantee that PIO read responses arrive
|
|
|
- after any outstanding DMA writes from that bus, since for some devices
|
|
|
- the result of a <function>readb</function> call may signal to the
|
|
|
- driver that a DMA transaction is complete. In many cases, however,
|
|
|
- the driver may want to indicate that the next
|
|
|
- <function>readb</function> call has no relation to any previous DMA
|
|
|
- writes performed by the device. The driver can use
|
|
|
- <function>readb_relaxed</function> for these cases, although only
|
|
|
- some platforms will honor the relaxed semantics. Using the relaxed
|
|
|
- read functions will provide significant performance benefits on
|
|
|
- platforms that support it. The qla2xxx driver provides examples
|
|
|
- of how to use <function>readX_relaxed</function>. In many cases,
|
|
|
- a majority of the driver's <function>readX</function> calls can
|
|
|
- safely be converted to <function>readX_relaxed</function> calls, since
|
|
|
- only a few will indicate or depend on DMA completion.
|
|
|
- </para>
|
|
|
- </sect1>
|
|
|
-
|
|
|
- </chapter>
|
|
|
-
|
|
|
- <chapter id="port_space_accesses">
|
|
|
- <title>Port Space Accesses</title>
|
|
|
- <sect1 id="port_space_explained">
|
|
|
- <title>Port Space Explained</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- Another form of IO commonly supported is Port Space. This is a
|
|
|
- range of addresses separate to the normal memory address space.
|
|
|
- Access to these addresses is generally not as fast as accesses
|
|
|
- to the memory mapped addresses, and it also has a potentially
|
|
|
- smaller address space.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Unlike memory mapped IO, no preparation is required
|
|
|
- to access port space.
|
|
|
- </para>
|
|
|
-
|
|
|
- </sect1>
|
|
|
- <sect1 id="accessing_port_space">
|
|
|
- <title>Accessing Port Space</title>
|
|
|
- <para>
|
|
|
- Accesses to this space are provided through a set of functions
|
|
|
- which allow 8-bit, 16-bit and 32-bit accesses; also
|
|
|
- known as byte, word and long. These functions are
|
|
|
- <function>inb</function>, <function>inw</function>,
|
|
|
- <function>inl</function>, <function>outb</function>,
|
|
|
- <function>outw</function> and <function>outl</function>.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Some variants are provided for these functions. Some devices
|
|
|
- require that accesses to their ports are slowed down. This
|
|
|
- functionality is provided by appending a <function>_p</function>
|
|
|
- to the end of the function. There are also equivalents to memcpy.
|
|
|
- The <function>ins</function> and <function>outs</function>
|
|
|
- functions copy bytes, words or longs to the given port.
|
|
|
- </para>
|
|
|
- </sect1>
|
|
|
-
|
|
|
- </chapter>
|
|
|
-
|
|
|
- <chapter id="pubfunctions">
|
|
|
- <title>Public Functions Provided</title>
|
|
|
-!Iarch/x86/include/asm/io.h
|
|
|
-!Elib/pci_iomap.c
|
|
|
- </chapter>
|
|
|
-
|
|
|
-</book>
|