1546 lines
56 KiB
Groff
1546 lines
56 KiB
Groff
.\" $NetBSD: bus_space.9,v 1.21 2001/12/26 01:02:01 wiz Exp $
|
|
.\"
|
|
.\" Copyright (c) 1997 The NetBSD Foundation, Inc.
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" This code is derived from software contributed to The NetBSD Foundation
|
|
.\" by Christopher G. Demetriou.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\" 3. All advertising materials mentioning features or use of this software
|
|
.\" must display the following acknowledgment:
|
|
.\" This product includes software developed by the NetBSD
|
|
.\" Foundation, Inc. and its contributors.
|
|
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
.\" contributors may be used to endorse or promote products derived
|
|
.\" from this software without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
|
.\"
|
|
.Dd August 13, 1997
|
|
.Dt BUS_SPACE 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm bus_space ,
|
|
.Nm bus_space_barrier ,
|
|
.Nm bus_space_copy_region_1 ,
|
|
.Nm bus_space_copy_region_2 ,
|
|
.Nm bus_space_copy_region_4 ,
|
|
.Nm bus_space_copy_region_8 ,
|
|
.Nm bus_space_free ,
|
|
.Nm bus_space_map ,
|
|
.Nm bus_space_peek_1 ,
|
|
.Nm bus_space_peek_2 ,
|
|
.Nm bus_space_peek_4 ,
|
|
.Nm bus_space_peek_8 ,
|
|
.Nm bus_space_poke_1 ,
|
|
.Nm bus_space_poke_2 ,
|
|
.Nm bus_space_poke_4 ,
|
|
.Nm bus_space_poke_8 ,
|
|
.Nm bus_space_read_1 ,
|
|
.Nm bus_space_read_2 ,
|
|
.Nm bus_space_read_4 ,
|
|
.Nm bus_space_read_8 ,
|
|
.Nm bus_space_read_multi_1 ,
|
|
.Nm bus_space_read_multi_2 ,
|
|
.Nm bus_space_read_multi_4 ,
|
|
.Nm bus_space_read_multi_8 ,
|
|
.Nm bus_space_read_multi_stream_1 ,
|
|
.Nm bus_space_read_multi_stream_2 ,
|
|
.Nm bus_space_read_multi_stream_4 ,
|
|
.Nm bus_space_read_multi_stream_8 ,
|
|
.Nm bus_space_read_region_1 ,
|
|
.Nm bus_space_read_region_2 ,
|
|
.Nm bus_space_read_region_4 ,
|
|
.Nm bus_space_read_region_8 ,
|
|
.Nm bus_space_read_region_stream_1 ,
|
|
.Nm bus_space_read_region_stream_2 ,
|
|
.Nm bus_space_read_region_stream_4 ,
|
|
.Nm bus_space_read_region_stream_8 ,
|
|
.Nm bus_space_read_stream_1 ,
|
|
.Nm bus_space_read_stream_2 ,
|
|
.Nm bus_space_read_stream_4 ,
|
|
.Nm bus_space_read_stream_8 ,
|
|
.Nm bus_space_set_region_1 ,
|
|
.Nm bus_space_set_region_2 ,
|
|
.Nm bus_space_set_region_4 ,
|
|
.Nm bus_space_set_region_8 ,
|
|
.Nm bus_space_subregion ,
|
|
.Nm bus_space_unmap ,
|
|
.Nm bus_space_vaddr ,
|
|
.Nm bus_space_mmap ,
|
|
.Nm bus_space_write_1 ,
|
|
.Nm bus_space_write_2 ,
|
|
.Nm bus_space_write_4 ,
|
|
.Nm bus_space_write_8 ,
|
|
.Nm bus_space_write_multi_1 ,
|
|
.Nm bus_space_write_multi_2 ,
|
|
.Nm bus_space_write_multi_4 ,
|
|
.Nm bus_space_write_multi_8 ,
|
|
.Nm bus_space_write_multi_stream_1 ,
|
|
.Nm bus_space_write_multi_stream_2 ,
|
|
.Nm bus_space_write_multi_stream_4 ,
|
|
.Nm bus_space_write_multi_stream_8 ,
|
|
.Nm bus_space_write_region_1 ,
|
|
.Nm bus_space_write_region_2 ,
|
|
.Nm bus_space_write_region_4 ,
|
|
.Nm bus_space_write_region_8
|
|
.Nm bus_space_write_region_stream_1 ,
|
|
.Nm bus_space_write_region_stream_2 ,
|
|
.Nm bus_space_write_region_stream_4 ,
|
|
.Nm bus_space_write_region_stream_8 ,
|
|
.Nm bus_space_write_stream_1 ,
|
|
.Nm bus_space_write_stream_2 ,
|
|
.Nm bus_space_write_stream_4 ,
|
|
.Nm bus_space_write_stream_8 ,
|
|
.Nd bus space manipulation functions
|
|
.Sh SYNOPSIS
|
|
.Fd #include <machine/bus.h>
|
|
.Ft int
|
|
.Fn bus_space_map "bus_space_tag_t space" "bus_addr_t address" \
|
|
"bus_size_t size" "int flags" "bus_space_handle_t *handlep"
|
|
.Ft void
|
|
.Fn bus_space_unmap "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t size"
|
|
.Ft int
|
|
.Fn bus_space_subregion "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "bus_size_t size" "bus_space_handle_t *nhandlep"
|
|
.Ft int
|
|
.Fo bus_space_alloc
|
|
.Fa "bus_space_tag_t space" "bus_addr_t reg_start" "bus_addr_t reg_end"
|
|
.Fa "bus_size_t size" "bus_size_t alignment" "bus_size_t boundary"
|
|
.Fa "int flags" "bus_addr_t *addrp" "bus_space_handle_t *handlep"
|
|
.Fc
|
|
.Ft void
|
|
.Fn bus_space_free "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t size"
|
|
.Ft void *
|
|
.Fn bus_space_vaddr "bus_space_tag_t space" "bus_space_handle_t handle"
|
|
.Ft paddr_t
|
|
.Fn bus_space_mmap "bus_space_tag_t space" "bus_addr_t addr" "off_t off" \
|
|
"int prot" "int flags"
|
|
.Ft int
|
|
.Fn bus_space_peek_1 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int8_t *datap"
|
|
.Ft int
|
|
.Fn bus_space_peek_2 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int16_t *datap"
|
|
.Ft int
|
|
.Fn bus_space_peek_4 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int32_t *datap"
|
|
.Ft int
|
|
.Fn bus_space_peek_8 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int64_t *datap"
|
|
.Ft int
|
|
.Fn bus_space_poke_1 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int8_t data"
|
|
.Ft int
|
|
.Fn bus_space_poke_2 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int16_t data"
|
|
.Ft int
|
|
.Fn bus_space_poke_4 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int32_t data"
|
|
.Ft int
|
|
.Fn bus_space_poke_8 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int64_t data"
|
|
.Ft u_int8_t
|
|
.Fn bus_space_read_1 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset"
|
|
.Ft u_int16_t
|
|
.Fn bus_space_read_2 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset"
|
|
.Ft u_int32_t
|
|
.Fn bus_space_read_4 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset"
|
|
.Ft u_int64_t
|
|
.Fn bus_space_read_8 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset"
|
|
.Ft void
|
|
.Fn bus_space_write_1 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int8_t value"
|
|
.Ft void
|
|
.Fn bus_space_write_2 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int16_t value"
|
|
.Ft void
|
|
.Fn bus_space_write_4 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int32_t value"
|
|
.Ft void
|
|
.Fn bus_space_write_8 "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "u_int64_t value"
|
|
.Ft void
|
|
.Fn bus_space_barrier "bus_space_tag_t space" "bus_space_handle_t handle" \
|
|
"bus_size_t offset" "bus_size_t length" "int flags"
|
|
.Ft void
|
|
.Fn bus_space_read_region_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_stream_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_stream_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_stream_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_region_stream_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_stream_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_stream_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_stream_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_region_stream_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_copy_region_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t srchandle" "bus_size_t srcoffset" \
|
|
"bus_space_handle_t dsthandle" "bus_size_t dstoffset" "bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_copy_region_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t srchandle" "bus_size_t srcoffset" \
|
|
"bus_space_handle_t dsthandle" "bus_size_t dstoffset" "bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_copy_region_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t srchandle" "bus_size_t srcoffset" \
|
|
"bus_space_handle_t dsthandle" "bus_size_t dstoffset" "bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_copy_region_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t srchandle" "bus_size_t srcoffset" \
|
|
"bus_space_handle_t dsthandle" "bus_size_t dstoffset" "bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_set_region_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int8_t value" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_set_region_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int16_t value" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_set_region_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int32_t value" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_set_region_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int64_t value" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_stream_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_stream_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_stream_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_read_multi_stream_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_stream_1 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int8_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_stream_2 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int16_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_stream_4 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int32_t *datap" \
|
|
"bus_size_t count"
|
|
.Ft void
|
|
.Fn bus_space_write_multi_stream_8 "bus_space_tag_t space" \
|
|
"bus_space_handle_t handle" "bus_size_t offset" "const u_int64_t *datap" \
|
|
"bus_size_t count"
|
|
.Sh DESCRIPTION
|
|
The
|
|
.Nm
|
|
functions exist to allow device drivers
|
|
machine-independent access to bus memory and register areas. All of the
|
|
functions and types described in this document can be used by including
|
|
the
|
|
.Pa Aq machine/bus.h
|
|
header file.
|
|
.Pp
|
|
Many common devices are used on multiple architectures, but are accessed
|
|
differently on each because of architectural constraints.
|
|
For instance, a device which is mapped in one system's I/O space may be
|
|
mapped in memory space on a second system. On a third system, architectural
|
|
limitations might change the way registers need to be accessed (e.g.
|
|
creating a non-linear register space).
|
|
In some cases, a single
|
|
driver may need to access the same type of device in multiple ways in a
|
|
single system or architecture. The goal of the
|
|
.Nm
|
|
functions is to allow a single driver source file to manipulate a set
|
|
of devices on different system architectures, and to allow a single driver
|
|
object file to manipulate a set of devices on multiple bus types on a
|
|
single architecture.
|
|
.Pp
|
|
Not all busses have to implement all functions described in this
|
|
document, though that is encouraged if the operations are logically
|
|
supported by the bus. Unimplemented functions should cause
|
|
compile-time errors if possible.
|
|
.Pp
|
|
All of the interface definitions described in this document are shown as
|
|
function prototypes and discussed as if they were required to be
|
|
functions. Implementations are encouraged to implement prototyped
|
|
(type-checked) versions of these interfaces, but may implement them as
|
|
macros if appropriate. Machine-dependent types, variables, and functions
|
|
should be marked clearly in
|
|
.Pa Aq machine/bus.h
|
|
to avoid confusion with the
|
|
machine-independent types and functions, and, if possible, should be
|
|
given names which make the machine-dependence clear.
|
|
.Sh CONCEPTS AND GUIDELINES
|
|
Bus spaces are described by bus space tags, which can be created only by
|
|
machine-dependent code. A given machine may have several different types
|
|
of bus space (e.g. memory space and I/O space), and thus may provide
|
|
multiple different bus space tags.
|
|
Individual busses or devices on a machine may use more than one bus space
|
|
tag. For instance, ISA devices are
|
|
given an ISA memory space tag and an ISA I/O space tag. Architectures
|
|
may have several different tags which represent the same type of
|
|
space, for instance because of multiple different host bus interface
|
|
chipsets.
|
|
.Pp
|
|
A range in bus space is described by a bus address and a bus size. The
|
|
bus address describes the start of the range in bus space. The bus
|
|
size describes the size of the range in bytes. Busses which are not byte
|
|
addressable may require use of bus space ranges with appropriately
|
|
aligned addresses and properly rounded sizes.
|
|
.Pp
|
|
Access to regions of bus space is facilitated by use of bus space handles,
|
|
which are usually created by mapping a specific range of a bus space.
|
|
Handles may also be created by allocating
|
|
and mapping a range of bus space, the actual location of which is picked
|
|
by the implementation within bounds specified by the caller of the
|
|
allocation function.
|
|
.Pp
|
|
All of the bus space access functions require one bus space tag
|
|
argument, at least one handle argument, and at least one offset argument
|
|
(a bus size).
|
|
The bus space tag specifies the space, each handle specifies a region in
|
|
the space, and each offset specifies the offset into the region of the
|
|
actual location(s) to be accessed. Offsets are given in bytes, though busses
|
|
may impose alignment constraints. The offset used to access data
|
|
relative to a given handle must be such that all of the data being
|
|
accessed is in the mapped region that the handle describes. Trying to
|
|
access data outside that region is an error.
|
|
.Pp
|
|
Because some architectures' memory systems use buffering to improve
|
|
memory and device access performance, there is a mechanism which can be
|
|
used to create
|
|
.Dq barriers
|
|
in the bus space read and write stream. There
|
|
are three types of barriers: read, write, and read/write. All reads
|
|
started to the region before a read barrier must complete before any reads
|
|
after the read barrier are started. (The analogous requirement is true for
|
|
write barriers.) Read/write barriers force all reads and writes started
|
|
before the barrier to complete before any reads or writes after the
|
|
barrier are started. Correctly-written drivers will include all
|
|
appropriate barriers, and assume only the read/write ordering imposed by
|
|
the barrier operations.
|
|
.Pp
|
|
People trying to write portable drivers with the
|
|
.Nm
|
|
functions should
|
|
try to make minimal assumptions about what the system allows. In particular,
|
|
they should expect that the system requires bus space addresses being
|
|
accessed to be naturally aligned (i.e. base address of handle added to
|
|
offset is a multiple of the access size), and that the system does
|
|
alignment checking on pointers (i.e. pointer to objects being read and
|
|
written must point to properly-aligned data).
|
|
.Pp
|
|
The descriptions of the
|
|
.Nm
|
|
functions given below all assume that
|
|
they are called with proper arguments. If called with invalid arguments
|
|
or arguments that are out of range (e.g. trying to access data outside of
|
|
the region mapped when a given handle was created), undefined behaviour
|
|
results. In that case, they may cause the
|
|
system to halt, either intentionally (via panic) or unintentionally (by
|
|
causing a fatal trap of by some other means) or may cause improper
|
|
operation which is not immediately fatal. Functions which return
|
|
void or which return data read from bus space (i.e., functions which
|
|
don't obviously return an error code) do not fail. They could only fail
|
|
if given invalid arguments, and in that case their behaviour is undefined.
|
|
Functions which take a count of bytes have undefined results if the specified
|
|
.Fa count
|
|
is zero.
|
|
.Sh TYPES
|
|
Several types are defined in
|
|
.Pa Aq machine/bus.h
|
|
to facilitate use of the
|
|
.Nm
|
|
functions by drivers.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fa bus_addr_t
|
|
.Pp
|
|
The
|
|
.Fa bus_addr_t
|
|
type is used to describe bus addresses. It must be an
|
|
unsigned integral type
|
|
capable of holding the largest bus address usable by the architecture. This
|
|
type is primarily used when mapping and unmapping bus space.
|
|
.Pp
|
|
.It Fa bus_size_t
|
|
.Pp
|
|
The
|
|
.Fa bus_size_t
|
|
type is used to describe sizes of ranges in bus space. It must be an
|
|
unsigned integral type capable of holding the size of the largest bus
|
|
address range usable on the architecture. This type is used by virtually all
|
|
of the
|
|
.Nm
|
|
functions, describing sizes when mapping regions and
|
|
offsets into regions when performing space access operations.
|
|
.Pp
|
|
.It Fa bus_space_tag_t
|
|
.Pp
|
|
The
|
|
.Fa bus_space_tag_t
|
|
type is used to describe a particular bus space on a machine. Its
|
|
contents are machine-dependent and should be considered opaque by
|
|
machine-independent code. This type is used by all
|
|
.Nm
|
|
functions to name the space on which they're operating.
|
|
.Pp
|
|
.It Fa bus_space_handle_t
|
|
.Pp
|
|
The
|
|
.Fa bus_space_handle_t
|
|
type is used to describe a mapping of a range of bus space. Its
|
|
contents are machine-dependent and should be considered opaque by
|
|
machine-independent code. This type is used when performing bus space
|
|
access operations.
|
|
.El
|
|
.Sh MAPPING AND UNMAPPING BUS SPACE
|
|
Bus space must be mapped before it can be used, and should be
|
|
unmapped when it is no longer needed. The
|
|
.Fn bus_space_map
|
|
and
|
|
.Fn bus_space_unmap
|
|
functions provide these capabilities.
|
|
.Pp
|
|
Some drivers need to be able to pass a subregion of already-mapped bus
|
|
space to another driver or module within a driver. The
|
|
.Fn bus_space_subregion
|
|
function allows such subregions to be created.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_map "space" "address" "size" "flags" "handlep"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_map
|
|
function maps the region of bus space named by the
|
|
.Fa space ,
|
|
.Fa address ,
|
|
and
|
|
.Fa size
|
|
arguments. If successful, it returns zero
|
|
and fills in the bus space handle pointed to by
|
|
.Fa handlep
|
|
with the handle
|
|
that can be used to access the mapped region. If unsuccessful,
|
|
it will return non-zero and leave the bus space handle pointed
|
|
to by
|
|
.Fa handlep
|
|
in an undefined state.
|
|
.Pp
|
|
The
|
|
.Fa flags
|
|
argument controls how the space is to be mapped. Supported flags include:
|
|
.Bl -tag -width BUS_SPACE_MAP_CACHEABLE -offset indent
|
|
.It Dv BUS_SPACE_MAP_CACHEABLE
|
|
Try to map the space so that accesses can be cached
|
|
by the system cache. If this flag is not specified, the
|
|
implementation should map the space so that it will not be cached.
|
|
This mapping method will only be useful in very rare occasions.
|
|
.Pp
|
|
This flag must have a value of 1 on all implementations for backward
|
|
compatibility.
|
|
.It Dv BUS_SPACE_MAP_PREFETCHABLE
|
|
Try to map the space so that accesses can be prefetched by the system,
|
|
and writes can be buffered.
|
|
This means, accesses should be side effect free (idempotent). The
|
|
.Fn bus_space_barrier
|
|
methods will flush the write buffer or force actual read accesses.
|
|
If this flag is not specified, the
|
|
implementation should map the space so that it will not be prefetched
|
|
or delayed.
|
|
.It Dv BUS_SPACE_MAP_LINEAR
|
|
Try to map the space so that its contents can be accessed linearly via
|
|
normal memory access methods (e.g. pointer dereferencing and structure
|
|
accesses). The
|
|
.Fn bus_space_vaddr
|
|
method can be used to obtain the kernel virtual address of the mapped range.
|
|
This is useful when software wants to do direct access to a memory
|
|
device, e.g. a frame buffer. If this flag is specified and linear
|
|
mapping is not possible, the
|
|
.Fn bus_space_map
|
|
call should fail. If this
|
|
flag is not specified, the system may map the space in whatever way is
|
|
most convenient.
|
|
Use of this mapping method is not encouraged for normal device access;
|
|
where linear access is not essential, use of the
|
|
.Fn bus_space_read/write
|
|
methods is strongly recommended.
|
|
.El
|
|
.Pp
|
|
Not all combinations of flags make sense or are supported with all
|
|
spaces. For instance,
|
|
.Dv BUS_SPACE_MAP_CACHEABLE
|
|
may be meaningless when
|
|
used on many systems' I/O port spaces, and on some systems
|
|
.Dv BUS_SPACE_MAP_LINEAR
|
|
without
|
|
.Dv BUS_SPACE_MAP_PREFETCHABLE
|
|
may never work.
|
|
When the system hardware or firmware provides hints as to how spaces should be
|
|
mapped (e.g. the PCI memory mapping registers' "prefetchable" bit), those
|
|
hints should be followed for maximum compatibility. On some systems,
|
|
requesting a mapping that cannot be satisfied (e.g. requesting a
|
|
non-prefetchable mapping when the system can only provide a prefetchable one)
|
|
will cause the request to fail.
|
|
.Pp
|
|
Some implementations may keep track of use of bus space for some or all
|
|
bus spaces and refuse to allow duplicate allocations. This is encouraged
|
|
for bus spaces which have no notion of slot-specific space addressing,
|
|
such as ISA and VME, and for spaces which coexist with those spaces
|
|
(e.g. EISA and PCI memory and I/O spaces co-existing with ISA memory and
|
|
I/O spaces).
|
|
.Pp
|
|
Mapped regions may contain areas for which no there is no device on the
|
|
bus. If space in those areas is accessed, the results are
|
|
bus-dependent.
|
|
.Pp
|
|
.It Fn bus_space_unmap "space" "handle" "size"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_unmap
|
|
function unmaps a region of bus space mapped with
|
|
.Fn bus_space_map .
|
|
When unmapping a region, the
|
|
.Fa size
|
|
specified should be
|
|
the same as the size given to
|
|
.Fn bus_space_map
|
|
when mapping that region.
|
|
.Pp
|
|
After
|
|
.Fn bus_space_unmap
|
|
is called on a handle, that handle is no longer
|
|
valid. (If copies were made of the handle they are no longer valid,
|
|
either.)
|
|
.Pp
|
|
This function will never fail. If it would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case,
|
|
.Fn bus_space_unmap
|
|
will never return.
|
|
.Pp
|
|
.It Fn bus_space_subregion "space" "handle" "offset" "size" "nhandlep"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_subregion
|
|
function is a convenience function which makes a
|
|
new handle to some subregion of an already-mapped region of bus space.
|
|
The subregion described by the new handle starts at byte offset
|
|
.Fa offset
|
|
into the region described by
|
|
.Fa handle ,
|
|
with the size given by
|
|
.Fa size ,
|
|
and must be wholly contained within the original region.
|
|
.Pp
|
|
If successful,
|
|
.Fn bus_space_subregion
|
|
returns zero and fills in the bus
|
|
space handle pointed to by
|
|
.Fa nhandlep .
|
|
If unsuccessful, it returns non-zero and leaves the bus space handle
|
|
pointed to by
|
|
.Fa nhandlep
|
|
in an
|
|
undefined state. In either case, the handle described by
|
|
.Fa handle
|
|
remains valid and is unmodified.
|
|
.Pp
|
|
When done with a handle created by
|
|
.Fn bus_space_subregion ,
|
|
the handle should
|
|
be thrown away. Under no circumstances should
|
|
.Fn bus_space_unmap
|
|
be used on the handle. Doing so may confuse any resource management
|
|
being done on the space, and will result in undefined behaviour. When
|
|
.Fn bus_space_unmap
|
|
or
|
|
.Fn bus_space_free
|
|
is called on a handle, all subregions of that handle become invalid.
|
|
.Pp
|
|
.It Fn bus_space_vaddr "tag" "handle"
|
|
.Pp
|
|
This method returns the kernel virtual address of a mapped bus space if and
|
|
only if it was mapped with the
|
|
.Dv BUS_SPACE_MAP_LINEAR
|
|
flag. The range can be accessed by normal (volatile) pointer dereferences.
|
|
If mapped with the
|
|
.Dv BUS_SPACE_MAP_PREFETCHABLE
|
|
flag, the
|
|
.Fn bus_space_barrier
|
|
method must be used to force a particular access order.
|
|
.Pp
|
|
.It Fn bus_space_mmap "tag" "addr" "off" "prot" "flags"
|
|
.Pp
|
|
This method is used to provide support for memory mapping bus space
|
|
into user applications. If an address space is addressable via
|
|
volatile pointer dereferences,
|
|
.Fn bus_space_mmap
|
|
will return the physical address (possibly encoded as a machine-dependent
|
|
cookie) of the bus space indicated by
|
|
.Fa addr
|
|
and
|
|
.Fa off .
|
|
.Fa addr
|
|
is the base address of the device or device region, and
|
|
.Fa off
|
|
is the offset into that region that is being requested.
|
|
If the request is made with
|
|
.Dv BUS_SPACE_MAP_LINEAR
|
|
as a flag, then a linear region must be returned to the caller.
|
|
If the region cannot be mapped (either the address does not exist,
|
|
or the constraints can not be met),
|
|
.Fn bus_space_mmap
|
|
returns
|
|
.Dv -1
|
|
to indicate failure.
|
|
.Pp
|
|
Note that it is not necessary that the region being requested by a
|
|
.Fn bus_space_mmap
|
|
call be mapped into a
|
|
.Fa bus_space_handle_t .
|
|
.Pp
|
|
.Fn bus_space_mmap
|
|
is called once per
|
|
.Dv PAGE_SIZE
|
|
page in the range. The
|
|
.Fa prot
|
|
argument indicates the memory protection requested by the user application
|
|
for the range.
|
|
.El
|
|
.Sh ALLOCATING AND FREEING BUS SPACE
|
|
Some devices require or allow bus space to be allocated by the operating
|
|
system for device use. When the devices no longer need the space, the
|
|
operating system should free it for use by other devices. The
|
|
.Fn bus_space_alloc
|
|
and
|
|
.Fn bus_space_free
|
|
functions provide these capabilities.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Xo
|
|
.Fo bus_space_alloc
|
|
.Fa "space" "reg_start" "reg_end" "size"
|
|
.Fa "alignment" "boundary" "flags" "addrp" "handlep"
|
|
.Fc
|
|
.Xc
|
|
.Pp
|
|
The
|
|
.Fn bus_space_alloc
|
|
function allocates and maps a region of bus space with the size given by
|
|
.Fa size ,
|
|
corresponding to the given constraints. If successful, it returns
|
|
zero, fills in the bus address pointed to by
|
|
.Fa addrp
|
|
with the bus space address of the allocated region, and fills in
|
|
the bus space handle pointed to by
|
|
.Fa handlep
|
|
with the handle that can be used to access that region.
|
|
If unsuccessful, it returns non-zero and leaves the bus address pointed to by
|
|
.Fa addrp
|
|
and the bus space handle pointed to by
|
|
.Fa handlep
|
|
in an undefined state.
|
|
.Pp
|
|
Constraints on the allocation are given by the
|
|
.Fa reg_start ,
|
|
.Fa reg_end ,
|
|
.Fa alignment ,
|
|
and
|
|
.Fa boundary
|
|
parameters. The allocated region will start at or after
|
|
.Fa reg_start
|
|
and end before or at
|
|
.Fa reg_end .
|
|
The
|
|
.Fa alignment
|
|
constraint must be a power of two, and the allocated region will start at
|
|
an address that is an even multiple of that power of two. The
|
|
.Fa boundary
|
|
constraint, if non-zero, ensures that the region is allocated so that
|
|
.Fa "first address in region"
|
|
/
|
|
.Fa boundary
|
|
has the same value as
|
|
.Fa "last address in region"
|
|
/
|
|
.Fa boundary .
|
|
If the constraints cannot be met,
|
|
.Fn bus_space_alloc
|
|
will fail. It is an error to specify a set of
|
|
constraints that can never be met
|
|
.Po
|
|
for example,
|
|
.Fa size
|
|
greater than
|
|
.Fa boundary
|
|
.Pc .
|
|
.Pp
|
|
The
|
|
.Fa flags
|
|
parameter is the same as the like-named parameter to
|
|
.Fa bus_space_map ,
|
|
the same flag values should be used, and they have the
|
|
same meanings.
|
|
.Pp
|
|
Handles created by
|
|
.Fn bus_space_alloc
|
|
should only be freed with
|
|
.Fn bus_space_free .
|
|
Trying to use
|
|
.Fn bus_space_unmap
|
|
on them causes undefined behaviour. The
|
|
.Fn bus_space_subregion
|
|
function can be used on
|
|
handles created by
|
|
.Fn bus_space_alloc .
|
|
.Pp
|
|
.It Fn bus_space_free "space" "handle" "size"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_free
|
|
function unmaps and frees a region of bus space mapped
|
|
and allocated with
|
|
.Fn bus_space_alloc .
|
|
When unmapping a region, the
|
|
.Fa size
|
|
specified should be the same as the size given to
|
|
.Fn bus_space_alloc
|
|
when allocating the region.
|
|
.Pp
|
|
After
|
|
.Fn bus_space_free
|
|
is called on a handle, that handle is no longer valid. (If copies were
|
|
made of the handle, they are no longer valid, either.)
|
|
.Pp
|
|
This function will never fail. If it would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case,
|
|
.Fn bus_space_free
|
|
will never return.
|
|
.El
|
|
.Sh READING AND WRITING SINGLE DATA ITEMS
|
|
The simplest way to access bus space is to read or write a single data
|
|
item. The
|
|
.Fn bus_space_read_N
|
|
and
|
|
.Fn bus_space_write_N
|
|
families of functions provide
|
|
the ability to read and write 1, 2, 4, and 8 byte data items on busses
|
|
which support those access sizes.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_read_1 "space" "handle" "offset"
|
|
.It Fn bus_space_read_2 "space" "handle" "offset"
|
|
.It Fn bus_space_read_4 "space" "handle" "offset"
|
|
.It Fn bus_space_read_8 "space" "handle" "offset"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_read_N
|
|
family of functions reads a 1, 2, 4, or 8 byte data item from
|
|
the offset specified by
|
|
.Fa offset
|
|
into the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
The location being read must lie within the bus space region specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data item being read.
|
|
On some systems, not obeying this requirement may cause incorrect data to
|
|
be read, on others it may cause a system crash.
|
|
.Pp
|
|
Read operations done by the
|
|
.Fn bus_space_read_N
|
|
functions may be executed out
|
|
of order with respect to other pending read and write operations unless
|
|
order is enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.Pp
|
|
.It Fn bus_space_write_1 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_2 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_4 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_8 "space" "handle" "offset" "value"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_write_N
|
|
family of functions writes a 1, 2, 4, or 8 byte data item to the offset
|
|
specified by
|
|
.Fa offset
|
|
into the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
The location being written must lie within
|
|
the bus space region specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data item being
|
|
written. On some systems, not obeying this requirement may cause
|
|
incorrect data to be written, on others it may cause a system crash.
|
|
.Pp
|
|
Write operations done by the
|
|
.Fn bus_space_write_N
|
|
functions may be executed
|
|
out of order with respect to other pending read and write operations
|
|
unless order is enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.El
|
|
.Sh PROBING BUS SPACE FOR HARDWARE WHICH MAY NOT RESPOND
|
|
One problem with the
|
|
.Fn bus_space_read_N
|
|
and
|
|
.Fn bus_space_write_N
|
|
family of functions is that they provide no protection against
|
|
exceptions which can occur when no physical hardware or
|
|
device responds to the read or write cycles. In such a situation,
|
|
the system typically would panic due to a kernel-mode bus error. The
|
|
.Fn bus_space_peek_N
|
|
and
|
|
.Fn bus_space_poke_N
|
|
family of functions provide a mechanism to handle these exceptions
|
|
gracefully without the risk of crashing the system.
|
|
.Pp
|
|
As with
|
|
.Fn bus_space_read_N
|
|
and
|
|
.Fn bus_space_write_N ,
|
|
the peek and poke functions provide the ability to read and
|
|
write 1, 2, 4, and 8 byte data items on busses which support those
|
|
access sizes. All of the constraints specified in the descriptions of
|
|
the
|
|
.Fn bus_space_read_N
|
|
and
|
|
.Fn bus_space_write_N
|
|
functions also apply to
|
|
.Fn bus_space_peek_N
|
|
and
|
|
.Fn bus_space_poke_N .
|
|
.Pp
|
|
In addition, explicit calls to the
|
|
.Fn bus_space_barrier
|
|
function are not required as the implementation will ensure all
|
|
pending operations complete before the peek or poke operation starts.
|
|
The implementation will also ensure that the peek or poke operations
|
|
complete before returning.
|
|
.Pp
|
|
The return value indicates the outcome of the peek or poke operation.
|
|
A return value of zero implies that a hardware device is
|
|
responding to the operation at the specified offset in the bus space.
|
|
A non-zero return value indicates that the kernel intercepted a
|
|
hardware exception (e.g. bus error) when the peek or poke operation
|
|
was attempted.
|
|
Note that some busses are incapable of generating exceptions when
|
|
non-existent hardware is accessed. In such cases, these functions
|
|
will always return zero and the value of the data read by
|
|
.Fn bus_space_peek_N
|
|
will be unspecified.
|
|
.Pp
|
|
Finally, it should be noted that at this time the
|
|
.Fn bus_space_peek_N
|
|
and
|
|
.Fn bus_space_poke_N
|
|
functions are not re-entrant and should not, therefore, be used
|
|
from within an interrupt service routine.
|
|
This constraint may be removed at some point in the future.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_peek_1 "space" "handle" "offset" "datap"
|
|
.It Fn bus_space_peek_2 "space" "handle" "offset" "datap"
|
|
.It Fn bus_space_peek_4 "space" "handle" "offset" "datap"
|
|
.It Fn bus_space_peek_8 "space" "handle" "offset" "datap"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_peek_N
|
|
family of functions cautiously read a 1, 2, 4, or 8 byte data item from
|
|
the offset specified by
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
The data item read is stored in the location pointed to by
|
|
.Fa datap .
|
|
It is permissible for
|
|
.Fa datap
|
|
to be NULL, in which case the data item will be discarded after being read.
|
|
.Pp
|
|
.It Fn bus_space_poke_1 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_poke_2 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_poke_4 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_poke_8 "space" "handle" "offset" "value"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_poke_N
|
|
family of functions cautiously write a 1, 2, 4, or 8 byte data item
|
|
specified by
|
|
.Fa value
|
|
to the offset specified by
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
.El
|
|
.Sh BARRIERS
|
|
In order to allow high-performance buffering implementations to avoid bus
|
|
activity on every operation, read and write ordering should be specified
|
|
explicitly by drivers when necessary. The
|
|
.Fn bus_space_barrier
|
|
function provides that ability.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_barrier "space" "handle" "offset" "length" "flags"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_barrier
|
|
function enforces ordering of bus space read and write operations
|
|
for the specified subregion (described by the
|
|
.Fa offset
|
|
and
|
|
.Fa length
|
|
parameters) of the region named by
|
|
.Fa handle
|
|
in the space named by
|
|
.Fa space .
|
|
.Pp
|
|
The
|
|
.Fa flags
|
|
argument controls what types of operations are to be ordered.
|
|
Supported flags are:
|
|
.Bl -tag -width BUS_SPACE_BARRIER_WRITE -offset indent
|
|
.It Dv BUS_SPACE_BARRIER_READ
|
|
Synchronize read operations.
|
|
.It Dv BUS_SPACE_BARRIER_WRITE
|
|
Synchronize write operations.
|
|
.El
|
|
.Pp
|
|
Those flags can be combined (or-ed together) to enforce ordering on both
|
|
read and write operations.
|
|
.Pp
|
|
All of the specified type(s) of operation which are done to the region
|
|
before the barrier operation are guaranteed to complete before any of the
|
|
specified type(s) of operation done after the barrier.
|
|
.Pp
|
|
Example: Consider a hypothetical device with two single-byte ports, one
|
|
write-only input port (at offset 0) and a read-only output port (at
|
|
offset 1). Operation of the device is as follows: data bytes are written
|
|
to the input port, and are placed by the device on a stack, the top of
|
|
which is read by reading from the output port. The sequence to correctly
|
|
write two data bytes to the device then read those two data bytes back
|
|
would be:
|
|
.Pp
|
|
.Bd -literal
|
|
/*
|
|
* t and h are the tag and handle for the mapped device's
|
|
* space.
|
|
*/
|
|
bus_space_write_1(t, h, 0, data0);
|
|
bus_space_barrier(t, h, 0, 1, BUS_SPACE_BARRIER_WRITE); /* 1 */
|
|
bus_space_write_1(t, h, 0, data1);
|
|
bus_space_barrier(t, h, 0, 2,
|
|
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); /* 2 */
|
|
ndata1 = bus_space_read_1(t, h, 1);
|
|
bus_space_barrier(t, h, 1, 1, BUS_SPACE_BARRIER_READ); /* 3 */
|
|
ndata0 = bus_space_read_1(t, h, 1);
|
|
/* data0 == ndata0, data1 == ndata1 */
|
|
.Ed
|
|
.Pp
|
|
The first barrier makes sure that the first write finishes before the
|
|
second write is issued, so that two writes to the input port are done
|
|
in order and are not collapsed into a single write. This ensures that
|
|
the data bytes are written to the device correctly and in order.
|
|
.Pp
|
|
The second barrier makes sure that the writes to the output port finish
|
|
before any of the reads to the input port are issued, thereby making sure
|
|
that all of the writes are finished before data is read. This ensures
|
|
that the first byte read from the device really is the last one that was
|
|
written.
|
|
.Pp
|
|
The third barrier makes sure that the first read finishes before the
|
|
second read is issued, ensuring that data is read correctly and in order.
|
|
.Pp
|
|
The barriers in the example above are specified to cover the absolute
|
|
minimum number of bus space locations. It is correct (and often
|
|
easier) to make barrier operations cover the device's whole range of bus
|
|
space, that is, to specify an offset of zero and the size of the
|
|
whole region.
|
|
.El
|
|
.Sh REGION OPERATIONS
|
|
Some devices use buffers which are mapped as regions in bus space.
|
|
Often, drivers want to copy the contents of those buffers to or from
|
|
memory, e.g. into mbufs which can be passed to higher levels of the
|
|
system or from mbufs to be output to a network. In order to allow
|
|
drivers to do this as efficiently as possible, the
|
|
.Fn bus_space_read_region_N
|
|
and
|
|
.Fn bus_space_write_region_N
|
|
families of functions are provided.
|
|
.Pp
|
|
Drivers occasionally need to copy one region of a bus space to another,
|
|
or to set all locations in a region of bus space to contain a single
|
|
value. The
|
|
.Fn bus_space_copy_region_N
|
|
family of functions and the
|
|
.Fn bus_space_set_region_N
|
|
family of functions allow drivers to perform these operations.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_read_region_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_8 "space" "handle" "offset" "datap" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_read_region_N
|
|
family of functions reads
|
|
.Fa count
|
|
1, 2, 4, or 8 byte data items from bus space
|
|
starting at byte offset
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space
|
|
and writes them into the array specified by
|
|
.Fa datap .
|
|
Each successive data item is read from an offset
|
|
1, 2, 4, or 8 bytes after the previous data item (depending on which
|
|
function is used). All locations being read must lie within the bus
|
|
space region specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data items being
|
|
read and the data array pointer should be properly aligned. On some
|
|
systems, not obeying these requirements may cause incorrect data to be
|
|
read, on others it may cause a system crash.
|
|
.Pp
|
|
Read operations done by the
|
|
.Fn bus_space_read_region_N
|
|
functions may be executed in any order. They may also be executed out
|
|
of order with respect to other pending read and write operations unless
|
|
order is enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function. There is no way to insert barriers between reads of
|
|
individual bus space locations executed by the
|
|
.Fn bus_space_read_region_N
|
|
functions.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.Pp
|
|
.It Fn bus_space_write_region_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_8 "space" "handle" "offset" "datap" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_write_region_N
|
|
family of functions reads
|
|
.Fa count
|
|
1, 2, 4, or 8 byte data items from the array
|
|
specified by
|
|
.Fa datap
|
|
and writes them to bus space starting at byte offset
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified
|
|
by
|
|
.Fa space .
|
|
Each successive data item is written to an offset 1, 2, 4,
|
|
or 8 bytes after the previous data item (depending on which function is
|
|
used). All locations being written must lie within the bus space region
|
|
specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data items being
|
|
written and the data array pointer should be properly aligned. On some
|
|
systems, not obeying these requirements may cause incorrect data to be
|
|
written, on others it may cause a system crash.
|
|
.Pp
|
|
Write operations done by the
|
|
.Fn bus_space_write_region_N
|
|
functions may be
|
|
executed in any order. They may also be executed out of order with
|
|
respect to other pending read and write operations unless order is
|
|
enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function. There is no way to insert barriers between writes of
|
|
individual bus space locations executed by the
|
|
.Fn bus_space_write_region_N
|
|
functions.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.Pp
|
|
.It Fn bus_space_copy_region_1 "space" "srchandle" "srcoffset" "dsthandle" \
|
|
"dstoffset" "count"
|
|
.It Fn bus_space_copy_region_2 "space" "srchandle" "srcoffset" "dsthandle" \
|
|
"dstoffset" "count"
|
|
.It Fn bus_space_copy_region_4 "space" "srchandle" "srcoffset" "dsthandle" \
|
|
"dstoffset" "count"
|
|
.It Fn bus_space_copy_region_8 "space" "srchandle" "srcoffset" "dsthandle" \
|
|
"dstoffset" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_copy_region_N
|
|
family of functions copies
|
|
.Fa count
|
|
1, 2, 4, or 8 byte data items in bus space
|
|
from the area starting at byte offset
|
|
.Fa srcoffset
|
|
in the region specified by
|
|
.Fa srchandle
|
|
of the bus space specified by
|
|
.Fa space
|
|
to the area starting at byte offset
|
|
.Fa dstoffset
|
|
in the region specified by
|
|
.Fa dsthandle
|
|
in the same bus space. Each successive data item read or written has
|
|
an offset 1, 2, 4, or 8 bytes after the previous data item (depending
|
|
on which function is used). All locations being read and written must
|
|
lie within the bus space region specified by their respective handles.
|
|
.Pp
|
|
For portability, the starting addresses of the regions specified by
|
|
each handle plus its respective offset should be a multiple of the size
|
|
of data items being copied. On some systems, not obeying this
|
|
requirement may cause incorrect data to be copied, on others it may cause
|
|
a system crash.
|
|
.Pp
|
|
Read and write operations done by the
|
|
.Fn bus_space_copy_region_N
|
|
functions may be executed in any order. They may also be executed out
|
|
of order with respect to other pending read and write operations unless
|
|
order is enforced by use of the
|
|
.Fn bus_space_barrier function .
|
|
There is no way to insert barriers between reads or writes of
|
|
individual bus space locations executed by the
|
|
.Fn bus_space_copy_region_N
|
|
functions.
|
|
.Pp
|
|
Overlapping copies between different subregions of a single region
|
|
of bus space are handled correctly by the
|
|
.Fn bus_space_copy_region_N
|
|
functions.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.Pp
|
|
.It Fn bus_space_set_region_1 "space" "handle" "offset" "value" "count"
|
|
.It Fn bus_space_set_region_2 "space" "handle" "offset" "value" "count"
|
|
.It Fn bus_space_set_region_4 "space" "handle" "offset" "value" "count"
|
|
.It Fn bus_space_set_region_8 "space" "handle" "offset" "value" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_set_region_N
|
|
family of functions writes the given
|
|
.Fa value
|
|
to
|
|
.Fa count
|
|
1, 2, 4, or 8 byte
|
|
data items in bus space starting at byte offset
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
Each successive data item has an offset 1, 2, 4, or 8 bytes after the
|
|
previous data item (depending on which function is used). All
|
|
locations being written must lie within the bus space region specified
|
|
by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data items being
|
|
written. On some systems, not obeying this requirement may cause
|
|
incorrect data to be written, on others it may cause a system crash.
|
|
.Pp
|
|
Write operations done by the
|
|
.Fn bus_space_set_region_N
|
|
functions may be
|
|
executed in any order. They may also be executed out of order with
|
|
respect to other pending read and write operations unless order is
|
|
enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function. There is no way to insert barriers between writes of
|
|
individual bus space locations executed by the
|
|
.Fn bus_space_set_region_N
|
|
functions.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.El
|
|
.Sh READING AND WRITING A SINGLE LOCATION MULTIPLE TIMES
|
|
Some devices implement single locations in bus space which are to be read
|
|
or written multiple times to communicate data, e.g. some ethernet
|
|
devices' packet buffer FIFOs. In order to allow drivers to manipulate
|
|
these types of devices as efficiently as possible, the
|
|
.Fn bus_space_read_multi_N
|
|
and
|
|
.Fn bus_space_write_multi_N
|
|
families of functions are provided.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_read_multi_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_8 "space" "handle" "offset" "datap" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_read_multi_N
|
|
family of functions reads
|
|
.Fa count
|
|
1, 2, 4, or 8 byte data items from bus space
|
|
at byte offset
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space
|
|
and writes them into the array specified by
|
|
.Fa datap .
|
|
Each successive data item is read from the same location in bus
|
|
space. The location being read must lie within the bus space region
|
|
specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data items being
|
|
read and the data array pointer should be properly aligned. On some
|
|
systems, not obeying these requirements may cause incorrect data to be
|
|
read, on others it may cause a system crash.
|
|
.Pp
|
|
Read operations done by the
|
|
.Fn bus_space_read_multi_N
|
|
functions may be
|
|
executed out of order with respect to other pending read and write
|
|
operations unless order is enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function. Because the
|
|
.Fn bus_space_read_multi_N
|
|
functions read the same bus space location multiple times, they
|
|
place an implicit read barrier between each successive read of that bus
|
|
space location.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.Pp
|
|
.It Fn bus_space_write_multi_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_8 "space" "handle" "offset" "datap" "count"
|
|
.Pp
|
|
The
|
|
.Fn bus_space_write_multi_N
|
|
family of functions reads
|
|
.Fa count
|
|
1, 2, 4, or 8 byte data items from the array
|
|
specified by
|
|
.Fa datap
|
|
and writes them into bus space at byte offset
|
|
.Fa offset
|
|
in the region specified by
|
|
.Fa handle
|
|
of the bus space specified by
|
|
.Fa space .
|
|
Each successive data item is written to the same location in
|
|
bus space. The location being written must lie within the bus space
|
|
region specified by
|
|
.Fa handle .
|
|
.Pp
|
|
For portability, the starting address of the region specified by
|
|
.Fa handle
|
|
plus the offset should be a multiple of the size of data items being
|
|
written and the data array pointer should be properly aligned. On some
|
|
systems, not obeying these requirements may cause incorrect data to be
|
|
written, on others it may cause a system crash.
|
|
.Pp
|
|
Write operations done by the
|
|
.Fn bus_space_write_multi_N
|
|
functions may be executed out of order with respect to other pending
|
|
read and write operations unless order is enforced by use of the
|
|
.Fn bus_space_barrier
|
|
function. Because the
|
|
.Fn bus_space_write_multi_N
|
|
functions write the same bus space location multiple times, they
|
|
place an implicit write barrier between each successive write of that
|
|
bus space location.
|
|
.Pp
|
|
These functions will never fail. If they would fail (e.g. because of an
|
|
argument error), that indicates a software bug which should cause a
|
|
panic. In that case, they will never return.
|
|
.El
|
|
.Sh STREAM FUNCTIONS
|
|
Most of the
|
|
.Nm
|
|
functions imply a host byte-order and a bus byte-order and take care of
|
|
any translation for the caller. In some cases, however, hardware may
|
|
map a FIFO or some other memory region for which the caller may want to
|
|
use multi-word, yet untranslated access. Access to these types of memory
|
|
regions should be with the
|
|
.Fn bus_space_*_stream_N
|
|
functions.
|
|
.Pp
|
|
.Bl -ohang -compact
|
|
.It Fn bus_space_read_stream_1 "space" "handle" "offset"
|
|
.It Fn bus_space_read_stream_2 "space" "handle" "offset"
|
|
.It Fn bus_space_read_stream_4 "space" "handle" "offset"
|
|
.It Fn bus_space_read_stream_8 "space" "handle" "offset"
|
|
.It Fn bus_space_read_multi_stream_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_stream_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_stream_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_multi_stream_8 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_stream_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_stream_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_stream_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_read_region_stream_8 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_stream_1 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_stream_2 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_stream_4 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_stream_8 "space" "handle" "offset" "value"
|
|
.It Fn bus_space_write_multi_stream_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_stream_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_stream_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_multi_stream_8 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_stream_1 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_stream_2 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_stream_4 "space" "handle" "offset" "datap" "count"
|
|
.It Fn bus_space_write_region_stream_8 "space" "handle" "offset" "datap" "count"
|
|
.El
|
|
.Pp
|
|
These functions are defined just as their non-stream counterparts,
|
|
except that they provide no byte-order translation.
|
|
.Sh EXPECTED CHANGES TO THE BUS_SPACE FUNCTIONS
|
|
The definition of the
|
|
.Nm
|
|
functions should not yet be considered finalized. There are several
|
|
changes and improvements which should be explored, including:
|
|
.Pp
|
|
.Bl -bullet
|
|
.It
|
|
Providing a mechanism by which incorrectly-written drivers will be
|
|
automatically given barriers and properly-written drivers won't be forced
|
|
to use more barriers than they need. This should probably be done via a
|
|
.Li #define
|
|
in the incorrectly-written drivers.
|
|
Unfortunately, at this time, few drivers actually use barriers correctly
|
|
(or at all). Because of that,
|
|
.Nm
|
|
implementations on architectures which do buffering must always
|
|
do the barriers inside the
|
|
.Nm
|
|
calls, to be safe. That has a potentially significant
|
|
performance impact.
|
|
.It
|
|
Exporting the
|
|
.Nm
|
|
functions to user-land so that applications
|
|
(such as X servers) have easier, more portable access to device space.
|
|
.It
|
|
Redefining bus space tags and handles so that machine-independent bus
|
|
interface drivers (for example PCI to VME bridges) could define and
|
|
implement bus spaces without requiring machine-dependent code. If this
|
|
is done, it should be done in such a way that machine-dependent
|
|
optimizations should remain possible.
|
|
.It
|
|
Converting bus spaces (such as PCI configuration space) which currently
|
|
use space-specific access methods to use the
|
|
.Nm
|
|
functions where that is appropriate.
|
|
.It
|
|
Redefining the way bus space is mapped and allocated, so that mapping
|
|
and allocation are done with bus specific functions which return bus
|
|
space tags. This would allow further optimization than is currently
|
|
possible, and would also ease translation of the
|
|
.Nm
|
|
functions
|
|
into user space (since mapping in user space would look like it just used
|
|
a different bus-specific mapping function).
|
|
.El
|
|
.Sh COMPATIBILITY
|
|
The current version of the
|
|
.Nm
|
|
interface specification differs slightly from the original
|
|
specification that came into wide use.
|
|
A few of the function names and arguments have changed
|
|
for consistency and increased functionality.
|
|
Drivers that were written to the
|
|
old, deprecated specification can be compiled by defining the
|
|
.Dv __BUS_SPACE_COMPAT_OLDDEFS
|
|
preprocessor symbol before including
|
|
.Pa Aq machine/bus.h .
|
|
.Sh SEE ALSO
|
|
.Xr bus_dma 9
|
|
.Sh HISTORY
|
|
The
|
|
.Nm
|
|
functions were introduced in a different form (memory and I/O spaces
|
|
were accessed via different sets of functions) in
|
|
.Nx 1.2 .
|
|
The functions were merged to work on generic
|
|
.Dq spaces
|
|
early in the
|
|
.Nx 1.3
|
|
development cycle, and many drivers were converted to use them.
|
|
This document was written later during the
|
|
.Nx 1.3
|
|
development cycle and the specification was updated to fix some
|
|
consistency problems and to add some missing functionality.
|
|
.Sh AUTHORS
|
|
The
|
|
.Nm
|
|
interfaces were designed and implemented by the
|
|
.Nx
|
|
developer
|
|
community. Primary contributors and implementors were Chris Demetriou,
|
|
Jason Thorpe, and Charles Hannum, but the rest of the
|
|
.Nx
|
|
developers and the user community played a significant role in development.
|
|
.Pp
|
|
Chris Demetriou wrote this manual page.
|