pciio_pio(D3)pciio_pio(D3)NAME
pciio_pio: pciio_pio_addr, pciio_piotrans_addr, pciio_piomap_alloc,
pciio_piomap_addr, pciio_piomap_done, pciio_piomap_free,
pciio_piospace_alloc, pciio_piospace_free - programmed I/O to PCI bus
SYNOPSIS
#include <sys/PCI/pciio.h>
caddr_t
pciio_pio_addr(
vertex_hdl_t vhdl,
device_desc_t desc,
pciio_space_t space,
iopaddr_t addr,
size_t size,
pciio_piomap_t *mapp,
unsigned flags)
caddr_t
pciio_piotrans_addr(
vertex_hdl_t vhdl,
device_desc_t desc,
pciio_space_t space,
iopaddr_t addr,
size_t size,
unsigned flags)
pciio_piomap_t
pciio_piomap_alloc(
vertex_hdl_t vhdl,
device_desc_t desc,
pciio_space_t space,
iopaddr_t addr,
size_t size,
size_t max,
unsigned flags)
caddr_t
pciio_piomap_addr(
pciio_piomap_t map,
iopaddr_t addr,
size_t size);
void
pciio_piomap_done(pciio_piomap_t map)
void
pciio_piomap_free(pciio_piomap_t map)
iopaddr_t
pciio_piospace_alloc(
vertex_hdl_t vhdl,
Page 1
pciio_pio(D3)pciio_pio(D3)
device_desc_t desc,
pciio_space_t space,
size_t size,
size_t align)
void
pciio_piospace_free(
vertex_hdl_t vhdl,
pciio_space_t space,
iopaddr_t addr,
size_t size)
Arguments
addr The offset within the given space.
align A desired alignment in PCI address space.
desc A device descriptor, usually zero.
flags Flags describing the use of the PIO map.
max The maximum size within space to be mapped at any one time.
map The map address returned by pciio_piomap_alloc().
mapp A pointer variable to receive the address of an allocated map.
size The size of the region to be mapped.
space Specifies the target PCI address space.
vhdl The PCI connection point as given to the attach() entry point.
DESCRIPTION
When a device driver wishes to use Programmed I/O (PIO) to communicate
with a device, the system needs to have a chance to set up any
appropriate mapping registers. The work to be done varies with the
available hardware and with the version of IRIX. The functions described
here provide an abstract interface to the creation of PIO mapping
objects, an interface that is consistent across most hardware. These
functions always do the least possible work given the available hardware.
There are two models for setting up a PIO map, one simple but fallible,
and one more general. In both models, the final goal is to retrieve a
physical address that, when used as the operand of a store or fetch, will
access a word in PCI bus address space rather than in CPU memory address
space.
Simple Model
The simple model provides permanent mappings through fixed mapping
resources that may or may not exist in a given system at a given time.
pciio_piotrans_addr() attempts to use shared hardware resources to
Page 2
pciio_pio(D3)pciio_pio(D3)
construct a physical address that, whenever used, routes the transaction
to the proper target on the PCI bus. This is not always possible. When
it is not, the function returns NULL.
When it works, pciio_piotrans_addr() allows the driver to do PIO with the
fewest complications. Typically pciio_piotrans_addr() always succeeds in
some platforms, and always fails in others. However, a driver that uses
it should be coded as if it could succeed or fail alternately in the same
system (which it could).
General Model
It is not always possible to establish a PIO mapping using common shared
system resources, so the concept of a PIO channel that preallocates
scarce mapping resources is provided.
Such a channel is allocated using pciio_piomap_alloc(), which is given
the limits of the region that will be mapped, and the maximum size to be
mapped at any time within that region. The model assumes that many
channels may be created, but that not all channels will be actively in
use at any time.
pciio_piomap_addr() is used to actually establish the proper mappings for
a PIO target. Given the offset within the target address space and the
size of the region for PIO, it returns the base address to be used for
accessing that region.
After all PIO transactions to that region are executed,
pciio_piomap_done() should be called to idle any mapping hardware and
possibly to flush out any pipes or buffers along the path that might do
unexpected things when mapping registers are modified.
Later, pciio_piomap_addr() can again be called, specifying the same or a
new target area.
When a driver is completely finished with a PIO channel -- either because
the channel is used only for initialization of the device, or because the
device or the driver is being shut down -- the PIO channel resources
should be released using pciio_piomap_free().
Utility Functions
pciio_pio_addr() is a wrapper function that calls pciio_piotrans_addr()
to establish a mapping. If that call fails, it then allocates a map
using pciio_piomap_alloc() (or uses the preallocated map passed in via
the mapp pointer), and fills it in using pciio_piomap_addr(), returning
the resulting piomap via the map pointer mapp. This function
encapsulates the common two-step process of attempting a simple address
translation and falling back to the more general process in the event the
simple approach fails.
pciio_piospace_alloc() can be used to find a block of PCI address space
that nobody else is using, which can then be used for whatever the device
and driver wish to use it for. The PCI infrastructure preallocates PCI
Page 3
pciio_pio(D3)pciio_pio(D3)
address space regions based on the device configuration BASE registers at
the time the bus is discovered. As a result this function is needed only
to manage a device that does not completely declare its address space
usage in its hardware configuration registers.
pciio_piospace_free() is used to release any allocations that were
previously made by pciio_piospace_alloc().
Specifying PCI Address Spaces
The space parameter takes on of the following values:
PCIIO_SPACE_WIN(n)
specifies one of the regions on the PCI bus decoded by the
PCI card's BASE registers. The address specified is the
offset within the decoded area, and the entire PIO region
must fit within the decoded area.
PCIIO_SPACE_CFG
requests a pointer handle that can be used to access the
configuration space for the card, via the pciio_config_get()
and pciio_config_set() functions documented in
pciio_config(D3).
Other space types are rarely needed but can be used:
PCIIO_SPACE_IO
requests a mapping into somewhere in the PCI bus I/O address
space.
PCIIO_SPACE_MEM
requests a mapping into somewhere in the PCI bus Memory
space. Since PCI bus address space is preallocated by the
kernel, this is a dangerous function to use.
PIO Attribute Flags
The flags argument specifies some uses of the map.
PCIIO_FIXED states that all translations will be done using fixed shared
resources; the results of those translations will remain
valid permanently, even if the map resource is subsequently
used to obtain additional mappings.
PCIIO_NOSLEEP
requests that any resources that are needed from the system
are allocated without sleeping. If any resource allocation
would have required the infrastructure to sleep, the service
call will return a failure code.
EXAMPLES
Here is a contrived example of how one might initialize a very strange
PCI card. It is not clear that this would be the best way to do it, but
it does give an example of the relationship between the various
Page 4
pciio_pio(D3)pciio_pio(D3)
functions.
pcifoo_attach(vertex_hdl_t vhdl)
{
unsigned *cfgspace;
struct pcifoo_devregs *devregs;
pciio_piomap_t pmap;
pciio_piomap_t cmap;
struct pcifoo_chan_config *tune;
...
/* Get the configuration space base
* pointer.
*/
cfgspace = pciio_piotrans_addr
(vhdl, 0, PCIIO_SPACE_CFG, 0, 256, 0);
if (cfgspace == NULL) {
cmn_err(CE_ALERT,
"pcifoo_attach: pciio_piotrans_addr failed");
return -1;
}
/* Get a pointer we can use for PIO to our
* device's control registers. This call
* attempts to use fixed shared resources,
* but will allocate unshared mapping resources
* if required.
*/
devregs = pciio_pio_addr
(vhdl, 0,
PCIIO_SPACE_WIN(0), 0,
sizeof (struct pcifoo_devregs),
&pmap, 0);
if (devregs == NULL) {
cmn_err(CE_ALERT,
"pcifoo_attach: pciio_pio_addr failed");
return -1;
}
/* save cfgspace and devregs for use;
* save pmap for pciio_dmamap_free
* call if/when we are unregistered.
*/
...
/* pretend our "channel" space is too big
* to successfully map with piotrans, so
* we have to use piomap, and that it is
* too big for us to get it in one call
* to piomap_addr.
*/
cmap = pciio_piomap_alloc(vhdl, 0,
PCIIO_SPACE_WIN(2), 0, CHAN_SEP * CHANS,
sizeof (struct pcifoo_chan_config), 0);
for (chan = 0; chan < chans; ++chan) {
tune = (struct pcifoo_chan_config *)
Page 5
pciio_pio(D3)pciio_pio(D3)
pciio_piomap_addr(cmap, CHAN_SEP * chan,
sizeof (struct pcifoo_chan_config));
/* now fiddle with this particular channel */
tune->chan = chan + 2;
tune->volume = 5;
tune->balance = 0;
pciio_piomap_done(cmap);
}
pciio_piomap_free(cmap);
...
}
NOTES
Do not point the mapp parameter to the pciio_pio_addr() function at your
only copy of a map pointer, since it will write a NULL through this
pointer when direct translations work.
It is not necessary to separately establish mappings for each individual
PIO target register. It is customary and more efficient to use a single
mapping to cover the entire register set of a device.
SEE ALSOpciio(D3), pciio_config(D3), pciio_dma(D3), pciio_error(D3),
pciio_get(D3), pciio_intr(D3).
DIAGNOSTICSpciio_piotrans_addr() returns a null pointer when shared (fixed)
resources can not be used to construct a valid physical address that maps
to the desired range of PCI addresses.
pciio_pio_addr() returns a null pointer when the target PCI address can
not be mapped either with shared (fixed) resources, or with unshared
mapping resources. If this happens, and the object being mapped is
large, it might be possible to set up mappings to smaller regions of the
target space.
pciio_piomap_alloc() returns a null pointer when resources can not be
allocated to establish PIO mappings to the described region, or if the
function parameters are inconsistent.
pciio_piomap_addr() returns a null pointer when the specified target
address can not be mapped using the specified PIO channel. This would
usually be due to specifying a target block that is outside the
previously specified target area or is larger than the previously
specified maximum mapping size. It may also return a null pointer if the
PIO channel is currently in use and has not been marked idle by a
pciio_piomap_done() call.
Page 6