Chad N. Tindel
Brian D. Pietsch
CSC550, Spring 2000
In the mid 1980s, Apple Computer began development of a new serial bus architecture called FireWire. It was designed to address several issues related to current and upcoming technology:
FireWire devices are generally multimedia based; examples are Digital Cameras and Camcorders, Digital VCRs, and Pro-audio equipment like DAT stations and other multi-track recorders. However, they can also be general PC peripherals like Hard Disk Drives, CD-ROM/DVD Drives, and Laser Printers.
Apple’s work caught the eyes of other vendors and an IEEE committee was formed to create a formal standard. This paper explains the concepts created by the resulting IEEE 1394-1995 specification and also explains the data structures and algorithms used by the FireWire subsystem in the 2.3.99-pre6 Linux kernel.
The 1394 specification creates a light amount of terminology that must be discussed before jumping into the technical details. A module is one physical device attached to the bus, containing at least one node. Generally physical devices are multimedia based; examples are digital cameras, digital camcorders, digital VCRs, and pro-audio equipment like DAT stations and other multi-track recorders. However, they can also be general PC peripherals like hard disk drives, CD-ROM/DVD drives, and laser printers. A node is a logical entity within a module. Devices on the bus are addressed at the node level. A unit is a functional subcomponent of a node that can identify processing, memory, or I/O functionality. Units of a node generally operate independently (they have their own drivers) but may share registers with each other. Figure 1 shows the internal architecture of a module. A port is a point of I/O within a node (where the node plugs into the bus). As shown in the Figure 2, nodes can be single or multi-ported. Packets are transferred in a peer-to-peer fashion, so when a multiport node receives a packet, it is retransmitted over its other ports. Each time a device is plugged into or unplugged from the bus, the entire bus topology is reconfigured. Each bus can be viewed as a tree of devices with one and only one root. The device at the root of the tree is the root node.
Figure 1. The Module Architecture
Figure 2. A Generic Set Of Interconnected Devices
Figure 3. The 1394 64-bit Virtual Address
The FireWire bus uses a 64-bit fixed addressing model. The address space is divided into equal space for 64k nodes, and these nodes are divided into 1024 buses with 64 nodes per bus. Bits [0-9] define the target bus, bits [10-15] identify the target node on the selected bus, and bits [16-63] define 256 terabytes of memory address space for each node.
For practical purposes, there can only be 63 nodes on each bus, because the last node is used as a broadcast address, which addresses the entire bus.
A Transfer describes how data is moved around between nodes. IEEE 1394 defines two different transfer modes:
The transfer type is dependent on the nature of the data being moved around. For example, if you wanted to stream video from a digital camera to the Internet, you would use an isochronous transfer because the necessary bandwidth is known a priori and the data needs to be sent at constant intervals. However, if you were simply copying the data from a CD-ROM to a hard drive you would use the asynchronous transfer mode because you don’t want to lose any information during the copy. These two transfer types have direct analogs in the socket-programming world; isochronous transfers are analogous to communication over a datagram socket and asynchronous transfers are analogous to communication over a stream socket.
When a node wishes to transmit a packet on the bus it needs to request permission to do so. The procedure for determining which node gets control of the bus is known as arbitration. There are two different kinds of arbitration depending on what kinds of nodes are on the bus: arbitration with only asynchronous devices and arbitration with isochronous devices. If isochronous devices are present, arbitration is handled the same whether or not any asynchronous devices are present.
Asynchronous-only arbitration is based on fair scheduling with priorities. After a 20μs gap (bus idle time) a new “arbitration round” starts. If a node wishes to transmit, it sends an arbitration request, which propagates up to the root node. If multiple nodes request arbitration at the same time, the node closest to the root node wins arbitration. If the nodes requesting arbitration are the same distance from the root node, then the node connecting to the lowest numbered root port wins arbitration. Each node can speak at most once during a given arbitration round. After a 10μs gap the remaining nodes arbitrate for their turn to use the bus; this continues until all nodes that wish to use the bus during that round have used it. Following another 20μs gap a new round starts over.
The arbitration mechanism gets more complicated when isochronous devices are connected on the bus, because those devices have already been guaranteed bandwidth. Each arbitration round is approximately 125μs long, so bandwidth is allocated as a portion of the 125μs interval. The root node broadcasts (sends a message to node 63, the broadcast address) a cycle start packet, which begins the arbitration round. All interested nodes send an arbitration request as before, and the winning node is still the node closest to the root. After .04μs of bus idle time, the remaining nodes arbitrate for control of the bus. Once each isochronous node has completed its transaction the time remaining in the 125μs interval is used for asynchronous transactions. Up to 80% of the bus bandwidth may be allocated to isochronous transactions and the remaining 20% is left available for asynchronous transactions.
Support for IEEE 1394 began with Linux kernel version 2.3.99 as part of the mainstream kernel, though patches are available for version 2.2.14. The project is still under development, though the current implementation is fairly complete and stable. The general subsystem is maintained by Andreas Bombe while others maintain the individual device drivers for supported PCI cards.
Two main data structures define the Linux host architecture: hpsb_host and hpsb_host_template. The hpsb_host_template structure is filled in and registered with Linux by each host device driver. There is exactly one instance of a host template per host type (i.e. PCI Lynx, Adaptec 5800, etc.). This structure holds function pointers for dealing with hosts on the system, such as detecting hosts, initializing them, releasing them, transmitting packets, etc. The hpsb_host structure serves to store information about a particular host. The most important field is a pointer to the hpsb_host_template that represents the type of host the structure is representing. Other fields stored in hpsb_host include the host’s node id, the bus manager’s id, a list of pending packets, etc. Figure 4 shows how these structures interact with one another in the system.
Figure 4. Interaction of Host Related Data Structures
The IEEE 1394 subsystem provides a callback mechanism for interaction with the bus. Two important data structures exist that allow users to register callback functions with the system to be called when certain events occur: hpsb_highlevel_ops and hpsb_address_ops. The first of these structures contains functions for host-level operations. These functions are called by the system when, for example, a host is added or removed, or when an isochronous packet is received. The second structure allows users to provide operations related to a specific address range. The functions provided include read, write, and lock. When a device on the bus attempts to read or write an address in the range specified for a particular hpsb_address_ops, the function in that structure is called by the system.
The high level callbacks are provided for when the bus wishes to interact with the system. When the system wishes to interact with the bus, however, it must use the high level operations provided by the IEEE 1394 subsystem. Many of the high level operations provided by the Linux subsystem mirror those of the high level callbacks. For example, there are functions to read, write, add a host, remove a host, listen on an isochronous channel, etc.
The IEEE 1394 subsystem in Linux provides a convenient interface to the bus in the form of the raw1394 module. The raw1394 module is both a hpsb_highlevel_ops and a character device. Being an hpsb_highlevel_ops allows the module to know about all hosts that exist on the system so that users can access all buses available on the system. As a character device, raw1394 provides the standard fops functions that allow reading, writing, etc. Reading and writing are accomplished in a slightly different manner than is traditionally used for character devices. There is a data structure, raw1394_request, which has data members for all important information regarding an IEEE 1394 transaction including type, address, and buffers for the actual data. An instance of this structure is passed to the read and write methods instead of actual buffers of data as is traditionally done.
The IEEE 1394 subsystem allows high speed devices to be
interconnected independent of the host system, processor, memory, etc. It provides for both guaranteed bandwidth
and guaranteed delivery type transactions via a simple, fairness based arbitration
system. The Linux implementation
supports all of the features of the IEEE 1394 subsystem in a simple to use
manner that is consistent with current support for other subsystems and