360 lines
16 KiB
Text
360 lines
16 KiB
Text
<!--
|
|
The FreeBSD Documentation Project
|
|
$FreeBSD$
|
|
|
|
Originally by: Jeroen Ruigrok van der Warven
|
|
Date: newbus-draft.txt,v 1.8 2001/01/25 08:01:08
|
|
Copyright (c) 2000 Jeroen Ruigrok van der Warven (asmodai@wxs.nl)
|
|
Copyright (c) 2002 Hiten Mahesh Pandya (hiten@uk.FreeBSD.org)
|
|
|
|
Future Additions:
|
|
|
|
o Expand the information about device_t
|
|
o Add information about the bus_* functions.
|
|
o Add information about bus specific (e.g. PCI) functions.
|
|
o Add a reference section for additional information.
|
|
o Add more newbus related structures and typedefs.
|
|
o Add a 'Terminology' section.
|
|
o Add information on resource manager functions, busspace
|
|
manager functions, newbus events related functions.
|
|
o More cleanup ... !
|
|
|
|
Provided under the FreeBSD Documentation License.
|
|
-->
|
|
<chapter id="newbus">
|
|
<chapterinfo>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Jeroen</firstname>
|
|
<surname>Ruigrok van der Werven (asmodai)</surname>
|
|
<affiliation><address><email>asmodai@FreeBSD.org</email></address>
|
|
</affiliation>
|
|
<contrib>Written by </contrib>
|
|
</author>
|
|
<author>
|
|
<firstname>Hiten</firstname>
|
|
<surname>Pandya</surname>
|
|
<affiliation><address><email>hiten@uk.FreeBSD.org</email></address>
|
|
</affiliation>
|
|
</author>
|
|
</authorgroup>
|
|
</chapterinfo>
|
|
<title>Newbus</title>
|
|
|
|
<para><emphasis>Special thanks to Matthew N. Dodd, Warner Losh, Bill Paul,
|
|
Doug Rabson, Mike Smith, Peter Wemm and Scott Long</emphasis>.</para>
|
|
|
|
<para>This chapter explains the Newbus device framework in detail.</para>
|
|
<sect1 id="devdrivers">
|
|
<title>Device Drivers</title>
|
|
<sect2>
|
|
<title>Purpose of a Device Driver</title>
|
|
<para>A device driver is a software component which provides the
|
|
interface between the kernel's generic view of a peripheral
|
|
(e.g. disk, network adapter) and the actual implementation of the
|
|
peripheral. The <emphasis>device driver interface (DDI)</emphasis> is
|
|
the defined interface between the kernel and the device driver component.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Types of Device Drivers</title>
|
|
<para>There used to be days in &unix;, and thus FreeBSD, in which there
|
|
were four types of devices defined:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><para>block device drivers</para></listitem>
|
|
<listitem><para>character device drivers</para></listitem>
|
|
<listitem><para>network device drivers</para></listitem>
|
|
<listitem><para>pseudo-device drivers</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para><emphasis>Block devices</emphasis> performed in way that used
|
|
fixed size blocks [of data]. This type of driver depended on the
|
|
so called <emphasis>buffer cache</emphasis>, which had the purpose
|
|
to cache accessed blocks of data in a dedicated part of the memory.
|
|
Often this buffer cache was based on write-behind, which meant that when
|
|
data was modified in memory it got synced to disk whenever the system
|
|
did its periodical disk flushing, thus optimizing writes.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Character devices</title>
|
|
<para>However, in the versions of FreeBSD 4.0 and onward the
|
|
distinction between block and character devices became non-existent.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="newbus-overview">
|
|
<!--
|
|
Real title:
|
|
Newbus, Busspace and the Resource Manager, an Explanation of the Possibilities
|
|
-->
|
|
<title>Overview of Newbus</title>
|
|
<para><emphasis>Newbus</emphasis> is the implementation of a new bus
|
|
architecture based on abstraction layers which saw its introduction in
|
|
FreeBSD 3.0 when the Alpha port was imported into the source tree. It was
|
|
not until 4.0 before it became the default system to use for device
|
|
drivers. Its goals are to provide a more object oriented means of
|
|
interconnecting the various busses and devices which a host system
|
|
provides to the <emphasis>Operating System</emphasis>.</para>
|
|
|
|
<para>Its main features include amongst others:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><para>dynamic attaching</para></listitem>
|
|
<listitem><para>easy modularization of drivers</para></listitem>
|
|
<listitem><para>pseudo-busses</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>One of the most prominent changes is the migration from the flat and
|
|
ad-hoc system to a device tree lay-out.</para>
|
|
|
|
<para>At the top level resides the <emphasis><quote>root</quote></emphasis>
|
|
device which is the parent to hang all other devices on. For each
|
|
architecture, there is typically a single child of <quote>root</quote>
|
|
which has such things as <emphasis>host-to-PCI bridges</emphasis>, etc.
|
|
attached to it. For x86, this <quote>root</quote> device is the
|
|
<emphasis><quote>nexus</quote></emphasis> device and for Alpha, various
|
|
different different models of Alpha have different top-level devices
|
|
corresponding to the different hardware chipsets, including
|
|
<emphasis>lca</emphasis>, <emphasis>apecs</emphasis>,
|
|
<emphasis>cia</emphasis> and <emphasis>tsunami</emphasis>.</para>
|
|
|
|
<para>A device in the Newbus context represents a single hardware entity
|
|
in the system. For instance each PCI device is represented by a Newbus
|
|
device. Any device in the system can have children; a device which has
|
|
children is often called a <emphasis><quote>bus</quote></emphasis>.
|
|
Examples of common busses in the system are ISA and PCI which manage lists
|
|
of devices attached to ISA and PCI busses respectively.</para>
|
|
|
|
<para>Often, a connection between different kinds of bus is represented by
|
|
a <emphasis><quote>bridge</quote></emphasis> device which normally has one
|
|
child for the attached bus. An example of this is a
|
|
<emphasis>PCI-to-PCI bridge</emphasis> which is represented by a device
|
|
<emphasis><devicename>pcibN</devicename></emphasis> on the parent PCI bus
|
|
and has a child <emphasis><devicename>pciN</devicename></emphasis> for the
|
|
attached bus. This layout simplifies the implementation of the PCI bus
|
|
tree, allowing common code to be used for both top-level and bridged
|
|
busses.</para>
|
|
|
|
<para>Each device in the Newbus architecture asks its parent to map its
|
|
resources. The parent then asks its own parent until the nexus is
|
|
reached. So, basically the nexus is the only part of the Newbus system
|
|
which knows about all resources.</para>
|
|
|
|
<tip><para>An ISA device might want to map its IO port at
|
|
<literal>0x230</literal>, so it asks its parent, in this case the ISA
|
|
bus. The ISA bus hands it over to the PCI-to-ISA bridge which in its turn
|
|
asks the PCI bus, which reaches the host-to-PCI bridge and finally the
|
|
nexus. The beauty of this transition upwards is that there is room to
|
|
translate the requests. For example, the <literal>0x230</literal> IO port
|
|
request might become memory-mapped at <literal>0xb0000230</literal> on a
|
|
<acronym>MIPS</acronym> box by the PCI bridge.</para></tip>
|
|
|
|
<para>Resource allocation can be controlled at any place in the device
|
|
tree. For instance on many Alpha platforms, ISA interrupts are managed
|
|
separately from PCI interrupts and resource allocations for ISA interrupts
|
|
are managed by the Alpha's ISA bus device. On IA-32, ISA and PCI
|
|
interrupts are both managed by the top-level nexus device. For both
|
|
ports, memory and port address space is managed by a single entity - nexus
|
|
for IA-32 and the relevant chipset driver on Alpha (e.g. CIA or tsunami).
|
|
</para>
|
|
|
|
<para>In order to normalize access to memory and port mapped resources,
|
|
Newbus integrates the <literal>bus_space</literal> APIs from NetBSD.
|
|
These provide a single API to replace inb/outb and direct memory
|
|
reads/writes. The advantage of this is that a single driver can easily
|
|
use either memory-mapped registers or port-mapped registers
|
|
(some hardware supports both).</para>
|
|
|
|
<para>This support is integrated into the resource allocation mechanism.
|
|
When a resource is allocated, a driver can retrieve the associated
|
|
<structfield>bus_space_tag_t</structfield> and
|
|
<structfield>bus_space_handle_t</structfield> from the resource.</para>
|
|
|
|
<para>Newbus also allows for definitions of interface methods in files
|
|
dedicated to this purpose. These are the <filename>.m</filename> files
|
|
that are found under the <filename>src/sys</filename> hierarchy.</para>
|
|
|
|
<para>The core of the Newbus system is an extensible
|
|
<quote>object-based programming</quote> model. Each device in the system
|
|
has a table of methods which it supports. The system and other devices
|
|
uses those methods to control the device and request services. The
|
|
different methods supported by a device are defined by a number of
|
|
<quote>interfaces</quote>. An <quote>interface</quote> is simply a group
|
|
of related methods which can be implemented by a device.</para>
|
|
|
|
<para>In the Newbus system, the methods for a device are provided by the
|
|
various device drivers in the system. When a device is attached to a
|
|
driver during <emphasis>auto-configuration</emphasis>, it uses the method
|
|
table declared by the driver. A device can later
|
|
<emphasis>detach</emphasis> from its driver and
|
|
<emphasis>re-attach</emphasis> to a new driver with a new method table.
|
|
This allows dynamic replacement of drivers which can be useful for driver
|
|
development.</para>
|
|
|
|
<para>The interfaces are described by an interface definition language
|
|
similar to the language used to define vnode operations for file systems.
|
|
The interface would be stored in a methods file (which would normally named
|
|
<filename>foo_if.m</filename>).</para>
|
|
|
|
<example>
|
|
<title>Newbus Methods</title>
|
|
<programlisting>
|
|
# Foo subsystem/driver (a comment...)
|
|
|
|
INTERFACE foo
|
|
|
|
METHOD int doit {
|
|
device_t dev;
|
|
};
|
|
|
|
# DEFAULT is the method that will be used, if a method was not
|
|
# provided via: DEVMETHOD()
|
|
|
|
METHOD void doit_to_child {
|
|
device_t dev;
|
|
driver_t child;
|
|
} DEFAULT doit_generic_to_child;
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>When this interface is compiled, it generates a header file
|
|
<quote><filename>foo_if.h</filename></quote> which contains function
|
|
declarations:</para>
|
|
|
|
<programlisting>
|
|
int FOO_DOIT(device_t dev);
|
|
int FOO_DOIT_TO_CHILD(device_t dev, device_t child);
|
|
</programlisting>
|
|
|
|
<para>A source file, <quote><filename>foo_if.c</filename></quote> is
|
|
also created to accompany the automatically generated header file; it
|
|
contains implementations of those functions which look up the location
|
|
of the relevant functions in the object's method table and call that
|
|
function.</para>
|
|
|
|
<para>The system defines two main interfaces. The first fundamental
|
|
interface is called <emphasis><quote>device</quote></emphasis> and
|
|
includes methods which are relevant to all devices. Methods in the
|
|
<emphasis><quote>device</quote></emphasis> interface include
|
|
<emphasis><quote>probe</quote></emphasis>,
|
|
<emphasis><quote>attach</quote></emphasis> and
|
|
<emphasis><quote>detach</quote></emphasis> to control detection of
|
|
hardware and <emphasis><quote>shutdown</quote></emphasis>,
|
|
<emphasis><quote>suspend</quote></emphasis> and
|
|
<emphasis><quote>resume</quote></emphasis> for critical event
|
|
notification.</para>
|
|
|
|
<para>The second, more complex interface is
|
|
<emphasis><quote>bus</quote></emphasis>. This interface contains
|
|
methods suitable for devices which have children, including methods to
|
|
access bus specific per-device information
|
|
<footnote><para>&man.bus.generic.read.ivar.9; and
|
|
&man.bus.generic.write.ivar.9;</para></footnote>, event notification
|
|
(<emphasis><literal>child_detached</literal></emphasis>,
|
|
<emphasis><literal>driver_added</literal></emphasis>) and resource
|
|
management (<emphasis><literal>alloc_resource</literal></emphasis>,
|
|
<emphasis><literal>activate_resource</literal></emphasis>,
|
|
<emphasis><literal>deactivate_resource</literal></emphasis>,
|
|
<emphasis><literal>release_resource</literal></emphasis>).</para>
|
|
|
|
<para>Many methods in the <quote>bus</quote> interface are performing
|
|
services for some child of the bus device. These methods would normally
|
|
use the first two arguments to specify the bus providing the service
|
|
and the child device which is requesting the service. To simplify
|
|
driver code, many of these methods have accessor functions which
|
|
lookup the parent and call a method on the parent. For instance the
|
|
method
|
|
<literal>BUS_TEARDOWN_INTR(device_t dev, device_t child, ...)</literal>
|
|
can be called using the function
|
|
<literal>bus_teardown_intr(device_t child, ...)</literal>.</para>
|
|
|
|
<para>Some bus types in the system define additional interfaces to
|
|
provide access to bus-specific functionality. For instance, the PCI
|
|
bus driver defines the <quote>pci</quote> interface which has two
|
|
methods <emphasis><literal>read_config</literal></emphasis> and
|
|
<emphasis><literal>write_config</literal></emphasis> for accessing the
|
|
configuration registers of a PCI device.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="newbus-api">
|
|
<title>Newbus API</title>
|
|
<para>As the Newbus API is huge, this section makes some effort at
|
|
documenting it. More information to come in the next revision of this
|
|
document.</para>
|
|
|
|
<sect2>
|
|
<title>Important locations in the source hierarchy</title>
|
|
|
|
<para><filename>src/sys/[arch]/[arch]</filename> - Kernel code for a
|
|
specific machine architecture resides in this directory. for example,
|
|
the <literal>i386</literal> architecture, or the
|
|
<literal>SPARC64</literal> architecture.</para>
|
|
|
|
<para><filename>src/sys/dev/[bus]</filename> - device support for a
|
|
specific <literal>[bus]</literal> resides in this directory.</para>
|
|
|
|
<para><filename>src/sys/dev/pci</filename> - PCI bus support code
|
|
resides in this directory.</para>
|
|
|
|
<para><filename>src/sys/[isa|pci]</filename> - PCI/ISA device drivers
|
|
reside in this directory. The PCI/ISA bus support code used to exist
|
|
in this directory in FreeBSD version <literal>4.0</literal>.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Important structures and type definitions</title>
|
|
<para><literal>devclass_t</literal> - This is a type definition of a
|
|
pointer to a <literal>struct devclass</literal>.</para>
|
|
|
|
<para><literal>device_method_t</literal> - This is same as
|
|
<literal>kobj_method_t</literal> (see
|
|
<filename>src/sys/kobj.h</filename>).</para>
|
|
|
|
<para><literal>device_t</literal> - This is a type definition of a
|
|
pointer to a <literal>struct device</literal>.
|
|
<literal>device_t</literal> represents a device in the system. It is
|
|
a kernel object. See <filename>src/sys/sys/bus_private.h</filename>
|
|
for implementation details.</para>
|
|
|
|
<para><literal>driver_t</literal> - This is a type definition which,
|
|
references <literal>struct driver</literal>. The
|
|
<literal>driver</literal> struct is a class of the
|
|
<literal>device</literal> kernel object; it also holds data private
|
|
to for the driver.</para>
|
|
|
|
<figure>
|
|
<title><emphasis>driver_t</emphasis> implementation</title>
|
|
<programlisting>
|
|
struct driver {
|
|
KOBJ_CLASS_FIELDS;
|
|
void *priv; /* driver private data */
|
|
};
|
|
</programlisting>
|
|
</figure>
|
|
|
|
<para>A <literal>device_state_t</literal> type, which is
|
|
an enumeration, <literal>device_state</literal>. It contains
|
|
the possible states of a Newbus device before and after the
|
|
autoconfiguration process.</para>
|
|
|
|
<figure>
|
|
<title>Device states<emphasis>device_state_t</emphasis></title>
|
|
<programlisting>
|
|
/*
|
|
* src/sys/sys/bus.h
|
|
*/
|
|
typedef enum device_state {
|
|
DS_NOTPRESENT, /* not probed or probe failed */
|
|
DS_ALIVE, /* probe succeeded */
|
|
DS_ATTACHED, /* attach method called */
|
|
DS_BUSY /* device is open */
|
|
} device_state_t;
|
|
</programlisting>
|
|
</figure>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|