--- /dev/null Tue Aug 13 00:58:30 2002 +++ newbus-handbook.sgml Tue Aug 13 00:58:03 2002 @@ -0,0 +1,378 @@ + + + + + + Jeroen + Ruigrok van der Werven + Written by + + + + + Hiten + Pandya + Additions and modifications for the Developer's Handbook by + + + + Newbus + + I hope the information within is something people can use to finally + answer their questions with when it comes to FreeBSD and its new device + driver framework. It explains the nitty-gritty behind Newbus. + + + + Device Drivers + + Purpose of a Device Driver + 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 device driver interface (DDI) is + the defined interface between the kernel and the device driver component. + + + + + Types of Device Drivers + There used to be days in &unix;, and thus FreeBSD, in which there + were four types of devices defined: + + + block device drivers + character device drivers + network device drivers + pseudo-device drivers + + + Block devices performed in way that used + fixed size blocks [of data]. This type of driver depended on the + so called buffer cache, 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 synched to disk whenever the system + did its periodical disk flushing, thus optimizing writes. + + + + Character devices + However, in the versions of FreeBSD 4.0 and onwards the + distinction between block and character devices became non-existent. + + + + + + + Overview of Newbus + Newbus 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 Operating System. + + Its main features include amongst others: + + + dynamic attaching + easy modularization of drivers + pseudo-busses + + + One of the most prominent changes is the migration from the flat and + ad-hoc system to a device tree lay-out. + + At the top level resides the root + device which is the parent to hang all other devices on. For each + architecture, there is typically a single child of root + which has such things as host-to-PCI bridges, etc. + attached to it. For x86, this root device is the + nexus device and for Alpha, various + different different models of Alpha have different top-level devices + corresponding to the different hardware chipsets, including + lca, apecs, + cia and tsunami. + + 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 bus. + Examples of common busses in the system are ISA and PCI which manage lists + of devices attached to ISA and PCI busses respectively. + + Often, a connection between different kinds of bus is represented by + a bridge device which normally has one + child for the attached bus. An example of this is a + PCI-to-PCI bridge which is represented by a device + pcibN on the parent PCI bus + and has a child pciN 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. + + 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. + + an ISA device might want to map its IO port at + 0x23c, 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 0x23c IO port + request might become memory-mapped at 0xb000023c on a + MIPS box by the PCI bridge. + + 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). + + + In order to normalize access to memory and port mapped resources, + newbus integrates the bus_space 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). + + This support is integrated into the resource allocation mechanism. + When a resource is allocated, a driver can retrieve the associated + bus_space_tag_t and + bus_space_handle_t from the resource. + + Newbus also allows for definitions of interface methods in files + dedicated to this purpose. These are the .m files + that are found under the src/sys hierarchy. + + The core of the Newbus system is an extensible + object-based programming 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 + interfaces. An interface is simply a group + of related methods which can be implemented by a device. + + 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 auto-configuration, it uses the method + table declared by the driver. A device can later + detach from its driver and + re-attach to a new driver with a new method table. + This allows dynamic replacement of drivers which can be useful for driver + development. + + 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 + foo_if.m). + + + Newbus Methods + + # 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; + + + + When this interface is compiled, it generates a header file + foo_if.h which contains function + declarations: + + + int FOO_DOIT(device_t dev); + int FOO_DOIT_TO_CHILD(device_t dev, device_t child); + + + A source file, foo_if.c 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. + + + The system defines two main interfaces. The first fundamental + interface is called device and includes + methods which are relevant to all devices. Methods in the + device interface include + probe, + attach and + detach to control detection of + hardware and shutdown, + suspend and + resume for critical event + notification. + + The second, more complex interface is + bus. This interface contains methods + suitable for devices which have children, including methods to access + bus specific per-device information + &man.bus.generic.read.ivar.9; and + &man.generic.write.ivar.9;, event notification + (child_detached, + driver_added) and resource + management (alloc_resource, + activate_resource, + deactivate_resource, + release_resource). + + Many methods in the bus 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 + BUS_TEARDOWN_INTR(device_t dev, device_t child, ...) + can be called using the function + bus_teardown_intr(device_t child, ...). + + Some bus types in the system define additional interfaces to provide + access to bus-specific functionality. For instance, the PCI bus driver + defines the pci interface which has two methods + read_config and + write_config for accessing the + configuration registers of a PCI device. + + + Newbus API + 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. + + + Important locations in the source hierarchy + src/sys// - + Kernel code for a specific machine architecture resides in this + directory. for example, the i386 architecture, or + the SPARC64 architecture. + + src/sys/dev/bus - device + support for a specific + resides in this directory. + + src/sys/dev/pci - PCI bus support code + resides in this directory. + + src/sys/[isa|pci] - PCI/ISA device drivers + reside in this directory. The PCI/ISA bus support code used to exist + in this directory in FreeBSD version 4.0. + + + + Important structures and type definitions + devclass_t - This is a type definition of a + pointer to a struct devclass. + + device_method_t - This is same as + kobj_method_t (see src/sys/kobj.h. + + + device_t - This is a type definition of a + pointer to a struct device. + device_t represents a device in the system. It is + a kernel object. See src/sys/sys/bus_private.h for + implementation details. + + driver_t - This is a type definition which, + references struct driver. The + driver struct is a class of the + device kernel object; it also holds data private to + for the driver. + +
+ <emphasis>driver_t</emphasis> implementation + + struct driver { + KOBJ_CLASS_FIELDS; + void *priv; /* driver private data */ + }; + +
+ + A device_state_t type, which is + an enumeration, device_state. It contains + the possible states of a Newbus device before and after the + autoconfiguration process. + +
+ Newbus device states <emphasis>device_state_t</emphasis> + + /* + * 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; + +
+
+
+ + Thanks to + The following people provided me with explanations and corrections, + aside from their patience and proofreading are: + + + Mathew N. Dodd + () + M. Warner Losh + () + Bill Paul + () + Doug Rabson + () + Mike Smith + () + Peter Wemm + () + + +