Device Driver Programming 0890425-070 October 1999
Copyright 1999 by Concurrent Computer Corporation. All rights reserved. This publication or any part thereof is intended for use with Concurrent Computer Corporation products by Concurrent Computer Corporation personnel, customers, and end–users. It may not be reproduced in any form without the written permission of the publisher. The information contained in this document is believed to be correct at the time of publication. It is subject to change without notice.
Preface Scope of Manual This manual provides reference information and procedures for developing device driver for all Concurrent systems (except PowerStack) running PowerMAX OS. It focuses only on development of drivers for character devices. Structure of Manual This manual consists of seventeen chapters, one appendix, a glossary, and an index. A brief description of the chapters is presented as follows: • Chapter 1 introduces this manual. • Chapter 2 overviews device drivers.
Device Driver Programming The glossary defines technical terms important to understanding the concepts this guide presents. The index contains an alphabetical reference to key terms and concepts and the page numbers where they occur in the text. Syntax Notation This manual uses the following notation: italic Books, reference cards, and items that users must specify print in italic type. Special terms might also print in italic.
Preface On line Command Reference On line Operating System API Reference On line System Files and Devices Reference On line Device Driver Reference v
Device Driver Programming vi
Contents Contents Chapter 1 Introduction Focus of Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of the Driver Development Effort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Writing a New Device Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Porting an Existing Device Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Organization of Manual . . . . . .
Device Driver Programming Configuration Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Base Address Registers(BAR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Decode into I/O Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Decode into Memory Space. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ROM Base Address Registers(BAR) . . . . . . . . . . . . . . . . . .
Contents Buses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interrupts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Byte-Ordering and Alignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . VME Addressing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Transfer Width Support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Address Types . . . . . . . . . . .
Contents Timing and Timeout Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interrupt Vector Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debug Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Small vs. Large Offset Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming Using Multiple Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-18 Synchronization Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-18 Chapter 12 Supporting Direct Memory Access (DMA) Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DMA into User Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Contents idspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . idtune. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Driver Software Package (DSP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of DSP Components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DSP Component Files . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming Breakpoints in the Initialization Phase . . . . . . . . . . . . . . . . . . . . . . . . . Using crash to Debug a Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Saving the Core Image of Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Initializing crash on the Memory Dump . . . . . . . . . . . . . . . . . . . . . . . . . . . Using crash Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Contents The Asynchronous I/O Support Routines. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The aread Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The awrite Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The acheck Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The await Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming Tables Table 4-1. HVME Address Range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6 Table 4-2. HVME Bus Slave Access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6 Table 4-3. HVME Bus Master Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-7 Table 5-1. VME Bus Slave Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-7 Table 5-2. VME Bus Master Access . . .
1 Introduction Focus of Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of the Driver Development Effort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Writing a New Device Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Porting an Existing Device Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Organization of Manual . . . . . . . . . . . . . . . . . . . .
Device Driver Programming
1 Chapter 1Introduction 1 1 1 This chapter defines the scope of this manual and overviews the effort required to develop a device driver for PowerMAX OS. It describes the PowerMAX OS manuals potentially needed to develop a device driver. Focus of Manual 1 This document is written for programmers with experience in writing device drivers and using UNIX® operating systems. It focuses on device driver development for Concurrent Computer Corporation hardware and the PowerMAX OS.
Device Driver Programming 2. Design the driver. 3. Write the driver. 4. Integrate the driver into the system 5. Test and debug the driver. Procedures for installing and testing the device and developing the driver component of the driver reside in Chapter 10. Procedures for integrating the driver into the system reside in Chapter 14. Techniques for debugging the driver reside in Chapter 15. Three phases constitute the driver development process: 1. Design 2. Development 3. Testing.
Introduction Chapters 4-8 describe the hardware environments, briefly overview the platform and then provide more information on configuring and operating each system. Chapter 9 explains the kernel environment. It describes the kernel I/O structure and flow of control and maps the system source directories and files important to driver development. It also details the system data structures and kernel support routines pertinent to driver development.
Device Driver Programming PowerMAX OS Real-Time Guide (Pub. No. 0890466) Explains user-level interrupt routines and inter-process synchronization on PowerMAX OS. System Administration, Volume 1 (Pub. No. 0890429) System Administration, Volume 2 (Pub. No. 0890430) Designed to help system administrators, these explain how to set up, configure, and maintain the operating system. Volume 1 explains system set-up, configuration, and security administration.
2 Understanding Device Drivers What Is a Device Driver?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Application Programs Versus Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parallel Execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interrupts. . . . . . .
Device Driver Programming
2 Chapter 2Understanding Device Drivers 2 2 2 This chapter explains what a device driver is and how a driver differs from an application. It describes the different types of devices and device driver interfaces. It also introduces driver entry points and kernel utilities and describes the driver environment.
Device Driver Programming User Level System Call Interface Kernel Level Process Control Subsystem File Subsystem I/O Subsystem Device Drivers Hardware Control Hardware Level 160970 Figure 2-1. Driver Placement in the Kernel UNIX systems see every device as a file. Even the user-level interface to the device is called a “special file.” The device special files reside in the /dev directory, and executing a simple ls command reveals much about the device.
Understanding Device Drivers System data structures, called switch tables, contain the starting addresses for the principal routines included in all drivers. Switch tables contain a row for each driver, and a column for each standard routine. Standard routines are collectively named “entry-point routines”, referring to the memory address where executions begins. The kernel translates the arguments of the system call into a value used as an index into the switch table.
Device Driver Programming much more slowly than the CPU, the data transfer can squander many processor cycles if the CPU waits on the drive. To avoid this, the driver normally suspends execution of the process until the transfer completes, freeing the CPU to service other processes. When the data transfer completes, the device sends an interrupt telling the original process to resume execution.
Understanding Device Drivers NOTE Some of the DDI/DKI functions (such as kmem_alloc(D3)) resemble standard library functions (such as malloc(3C)), but use different arguments. Serious errors result from ignoring such differences. • The kernel calls drivers using a set of system tables and the standard C function-calling mechanism. Every member of these tables is a structure containing pointers to the driver's entry point routines. The entry point routines connect the calling process to the device driver.
Device Driver Programming Types of Device Driver Interfaces 2 A device driver interface is the set of structures, routines, and optional functions used to implement a device driver. UNIX systems provide three device driver interfaces, all based on one specification, the Device Driver Interface/Driver Kernel Interface (DDI/DKI). Block and Character Interfaces 2 Block and character are the two traditional UNIX system device driver interfaces, corresponding to the two basic ways drivers move data.
Understanding Device Drivers Major and Minor Numbers 2 Before the operating system can access a device, the device needs its driver installed and a special device file created for it in /dev. The special device file contains the major and minor device numbers. Major Numbers 2 The major number identifies the device class or group, such as a controller for several terminals. It tells the kernel which driver's open routine to call.
Device Driver Programming • System calls by applications • Interrupts by devices. The process of initializing the system creates several tables so the system can activate the correct driver routine. Because the system uses these tables to determine which driver routines to enter, common practice refers to the routines as driver entry points. Each table corresponds to a specific set of entry-point routines: • Initialization tables correspond with either init(D2) or start(D2) routines.
Understanding Device Drivers 1. The system directs the I/O system call (open and read, for example) to a special device file. This file includes the major number for the driver that controls the device. 2. The system uses the major number as an index into its switch tables to find the appropriate routine to call. 3. The operating system calls the appropriate routine. (Figure 2-3 depicts the between these components.
Device Driver Programming Devices need not use all the entry points provided by the switch table. For instance, printer drivers do not need read routines. The operating system provides place holders in the switch tables for unneeded routines. Interrupt Entry Points 2 The operating system must handle many kinds of system interrupts (such as clock and software interrupts), system exceptions (such as page faults), and interrupts from peripheral devices controlled by drivers.
Understanding Device Drivers 1. Prepare a Driver Software Package (DSP), including the Driver.o object module (the actual driver code), Master, System, and if needed Sadapters file definitions, and other components. 2. Install the driver's DSP 3. Update the system configuration files 4. Prepare to generate a new kernel. 5. Shutdown and reboot the system.
Device Driver Programming ram_ results in routines named ram_open, ram_init and so on. For more information, see the prefix(D1) manual page. The Master file can also contain the driver's major number and various flags defining specific characteristics of that driver (for example, whether a character or block driver). During installation, the idtools assign a major number if the driver's Master file doesn't specify one. For more information, see the Master(4) manual page.
3 The PCI Environment Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PCI Variants and Form Factors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Big Vs Little Endian Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . RISC Vs CISC CPU Processor Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Types of PCI Resources. . . . .
Device Driver Programming
3 Chapter 3The PCI Environment 3 3 3 Introduction 3 The PCI (Peripheral Component Interconnect) BUS specifications was created out of the need to create a simple plug and play mechanism for access I/O resources. PCI has several physical and electrical variances. Generally, a PCI based system can have up to 256 PCI buses with upwards of ten(10) PCI devices per bus. Practically, the actual number of PCI buses and devices is generally restricted by other factors.
Device Driver Programming high performance form factors are used only when the design of the add on device requires performance or resources that exceed that available in the commonly available form factors. These high performance buses must be directly connected or bridged into by other equally high performance PCI buses to System memory, to do otherwise the would compromise the performance gain available.
The PCI Environment Endian translation is necessary whenever a memory or I/O mapped address space is accessed, or when accessing configuration space in data widths less than 32 bits. To provide a common mechanism of byte swapping, the BUSGETSR, BUSGETLR, BUSPUTSR and BUSPUTLR macros are provided in the xxxx.h header file. RISC Vs CISC CPU Processor Issues 3 Generally RISC processors behave in a similar fashion to CISC processors except in two areas.
Device Driver Programming of the configuration space. The remaining 192 or 1984(2048-64) is reserved for custom use by the device. Within the configuration space of a PCI device/function 28 of the 64 bytes are reserved for Base address registers(BAR’s). These are read/write registers that are used to set the starting I/O and Memory space address for any additional resources required by the device.
The PCI Environment ROM Base Address Registers(BAR) 3 Decode into Memory Space 3 Similar to Base Address Registers that decode into Memory Space with the same characteristics. These areas are allocated out of the space set aside for PCI memory space. Interrupts 3 Each sub function of a PCI device can request one interrupt to be attached to the specified Interrupt Pin defined at offset 0x3d.
Device Driver Programming Finding the Correct Adapter Structure 3 Use the routines adapter_find and adapter_find2 to locate instances of your device. An alternate method is to scan the external “adapters” array for “adapter_count” entries and match the “adapter_type” element with a value generated from the macro “ P C I _ A DA P T E R _ T Y P E ” a n d c h e c k t h e “ a d a p t e r _ s t a t e ” e l e m e n t f o r t h e “ADAPTER_PRESENT” flag.
The PCI Environment call must be used. The arguments must include the CPU physical address and the size of the PCI BAR register returned from the “pci_XXXspc_alloc” call. Use the “physmap_free” call to release the Kernel virtual address assignment associated with a PCI BAR assignment. Accessing PCI Device Registers and Memory Space Though Kernel Virtual Maps 3 It is important to remember to use the byte swapping and pipeline flushing Macros provided when accessing PCI devices directly.
Device Driver Programming 3-8
3 Series 6000 Hardware Environment System Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Processor Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Buses. . . .
Device Driver Programming
4 Chapter 4Series 6000 Hardware Environment 4 4 4 This chapter provides hardware-specific information useful in developing device drivers for the Series 6000 computer systems. The Series 6000 covers models HN6200 and HN6800; the text points out model-specific information. This chapter also explains how hardware configuration affects I/O function and performance.
Device Driver Programming Processor Bus Local Bus Control PowerPC 604 Local Memory 50MHz Static or 50MHz Dynamic PowerPC 604 Local Bus Port Interface Bus Watcher (Snoop Filter) Frontplane Interface HVME Interface ISE Global Memory Disc Tape System Frontplane HVME Backplane CIO Secondary Interface I/O Local Bus Error Add Reg TOC RTC EPROM Diagnostic Control UART Interval Timer CPU ID Register Error ID Register Health Register Interrupt Controller Figure 4-1.
Series 6000 Hardware Environment Memory 4 The HN6800 system uses 32-bit addresses for up to four gigabytes of virtual address space. Figure 4-1 shows that any processor on the processor board has cached access to local memory. The local memory resides on a daughter card attached to the processor board. The daughter card provides up to 128 MB of dynamic or 64 MB of static memory.
Device Driver Programming Byte-Ordering and Alignment 4 The Series 6000 platform orders bytes according to the Big Endian convention, in which the most significant byte (MSB) always has the lowest address. This provides consistent addressing independent of the machine word size, as Figure 4-2 depicts. (Note that the bit ordering depicted (with bit 31 most significant) applies to I/O addressing. The bit ordering of the PowerPC 604 is the opposite (with bit 0 most significant).
Series 6000 Hardware Environment Transfer Width Support 4 For all non-block mode transfers, (H)VME supports byte, word and long-word addresses. It supports byte addresses on even and odd addresses. It supports word addresses (16-bit) on even addresses. It supports longword transfers on longword addresses. Synchronous Block Transfers or VME Block Mode Transfers (BMT) only support longword addresses.
Device Driver Programming HVME Address Ranges 4 Table 4-1 shows the address ranges for HVME devices: Table 4-1. HVME Address Range Address Type HVME Primary A32 0xC00000000xD5FFFFFF VME Address Ranges 4 This section details the address ranges VME devices use on the (H)VME primary I/O bus as bus masters or slaves. (H)VME Devices as (H)VME Bus Slaves 4 When a processor acts as bus master on the (H)VME bus and addresses (H)VME devices on the (H)VME I/O bus, the (H)VME devices are slave devices.
Series 6000 Hardware Environment Table 4-3 shows the address ranges for (H)VME bus master accesses: Table 4-3.
Device Driver Programming Bus Time-Out 4 The (H)VME bus measures with a bus timer the duration of data transfers accessing slave devices. If a data transfer malfunctions, the bus timer detects the malfunction and generates a bus time-out, preventing a dead VME slave from hanging the I/O channel. After a device applies an address to the bus and asserts the address strobe (AS*) and data strobe (DS*) signals, the VME device addressed must assert the data transfer acknowledge (DTACK*) signal within 51.
Series 6000 Hardware Environment then the device vendor must build a programmable assembly for a suitable address. NOTE Installing components not specified or marketed by the device vendor might void the warranty. Patent and copyrights that apply to the device also cover programmable assemblies, which require written permission from the vendor to modify or copy. (License fees might accompany such permission.
Device Driver Programming NOTE The VMEbus specification defines an optional bus clear (BCLR) signal for the present master to relinquish the bus. HVME does not implement this optional signal. The HVME bus implementation of the VMEbus standard uses only the BR0 bus request level (for boards that cannot use BR0/BG0, see the following procedure). The bus arbiter neither uses nor attends to other bus request levels, with the exception of BR3.
Series 6000 Hardware Environment Interrupt Request Levels and Priorities 4 In the Series 6000, interrupts come from both processors or other hardware devices external to or attached to the processors and software. Sources of hardware interrupts include: • Device controllers on the I/O bus • Powerfail • 60 Hz clock • Timers • Real-time clocks • Console processor • Port controllers (serial or parallel.) Sources of software interrupts include: • Inter-processor requests • Softclock • Context switches.
Device Driver Programming NOTE For system speed and proper device operation, increase the priority of devices needing a quick response to interrupts. Decrease the priority of devices that tolerate longer interrupt latencies; devices whose interrupts can wait longer before service. Interrupt Vector Generation and Configuration In hardware, the interrupt process functions as follows: 1.
Series 6000 Hardware Environment • If hardware settings determine the interrupt vector (preset), then r e c o n fi g u r e t h e i n t e r r u p t v e c t o r b y m o d i f y i n g t h e /etc/conf/cf.d/ivt.s file and rebuilding the kernel. • If slave or master register programming determines the interrupt vector, then the kernel interrupt vector table can dynamically allocate and assign the interrupt vector to the device during bootstrap.
Device Driver Programming 4-14
5 Power Hawk 610 Hardware Environment System Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Processor Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Buses. . .
Device Driver Programming
5 Chapter 5Power Hawk 610 Hardware Environment 5 5 5 This chapter provides hardware-specific information useful in developing device drivers for the Power Hawk 610 computer system. This chapter also explains how hardware configuration affects I/O function and performance. Some hardware issues are general in nature—for example, I/O error handling (power failure, alignment errors, controller errors, and bus hangs.
Device Driver Programming RTC/ NVRAM PowerPC 604 MOUSE DRAM DRAM ROM BUFFERS KEYBOARD PARALLEL I/O MPC105 PCI BRIDGE RAM104 ISA BRIDGE SERIAL PM604 MPU/DRAM MODULE FLOPPY DISK CONTROLLER (NOT USED) 32-BIT PCI LOCAL BUS VME2PCI PCI EXPANSION PMC SLOT VME VMEchip2 SCSI NCR-53C825 ETHERNET DECchip 21040 VGA CL-GD5434 VIDEO RAM MVME1600-001/011 BASE BOARD Figure 5-1.
Power Hawk 610 Hardware Environment Memory 5 The Power Hawk 610 uses 32-bit addresses for up to four gigabytes of virtual address space. Figure 5-1 depicts both the memory provided on the processor card and on an additional DRAM daughter card. Each location can contain up to 64 MB of dynamic memory for a total capacity of 128 MB. Power Hawk DRAM has a non-burst access time of eight 66 Mhz cycles or about 120 nanoseconds. This memory provides no parity or Error Correction (ECC) capability.
Device Driver Programming individually enable and disable them. It sends the resultant interrupt through the MPC105 Bridge chip to the PowerPC 604 processor. The VMEchip2 initially handles VMEbus interrupts, and can individually enable and disable them. The chip routes them through the PCI bus to the ISA Bridge chip, which resolves the interrupts into one of sixteen levels.
Power Hawk 610 Hardware Environment LOW ADDRESS = MSB LOW ADDRESS HIGHER ADDRESS 0 7 MSB 15 LSB 8 7 0 LSB MSB 31 24 23 16 15 8 7 0 Figure 5-2. Big Endian Bit and Byte Notation VME Addressing 5 This section describes the characteristics of data transfers on the VME bus. Doing so aids in building device addresses and understanding the error detection and recovery feature of the VMEbus.
Device Driver Programming Address Modifiers 5 For each data transfer on the VME bus, the bus master (either a processor or an I/O device) must identify the characteristics of the data transfer by sending a special six-bit code along with the transfer. This code is called an address modifier. For each different type of data transfer there is one unique address modifier value to be used.
Power Hawk 610 Hardware Environment Table 5-1. VME Bus Slave Access Address Type Processor Address VME Address A32 0xC10100000xE0BFFFFF 0xE00100000xFFBFFFFF A24 0xE0C000000xE0F3FFFF 0xFFC000000xFFF3FFFF A16 0xC10000000xC100FFFF 0xFFFF00000xFFFFFFFF VME Devices as Bus Masters 5 When a VME device addresses memory (or other VME sources), the VME device is the bus master. Table 5-2 shows the address ranges for VME bus master accesses. Table 5-2.
Device Driver Programming • Invalid transfer • Nonexistent device addressed • Device correctly addressed but malfunctioning The kernel tries to recognize VME bus errors and determines their cause. The most common response by the kernel is to panic the system. A panic halts the system so that the administrator can fix a malfunctioning board or device, or take some other corrective action. An alternative system service, iobus_err(2), can handle some types of VME bus errors without panicking the system.
Power Hawk 610 Hardware Environment Bus Arbitration 5 Busses that support multiple bus masters must provide a means of resolving the contention of concurrent requests for bus mastership by multiple devices. This is the purpose of a special unit on the VME bus, the VME bus arbiter. Bus arbitration is important only for devices that can act as bus masters. Device specifications indicate this ability as either “bus master” or “DMA Operation.
Device Driver Programming A system can use more than one of these options. By default, the system uses the straight slot priority scheme, wherein the lowest numbered slot not occupied by a processor board has the highest priority. A configuration register in the VME interface module defines the bus arbitration schemes. The processor can read from or write to this register.
Power Hawk 610 Hardware Environment If two interrupt requests with the same interrupt level occur simultaneously on the VME I/O bus, the system resolves the contention by applying the following rules: 1. In devices sharing the same interrupt level on the same I/O bus, the device with the lowest slot number has the highest priority. 2. In interrupt levels on the same I/O bus, the device connected to level 7 has the highest priority down to level 1, which has the lowest priority. 3.
Device Driver Programming 7. When the interrupt handler on the (H)VME bus forwards an interrupt acknowledge to a processor, the low-level portion of the operating system interrupt subsystem reads the code to index one of 256 addresses of interrupt-handling routines. This one-byte code, contained by the VME device, is an interrupt vector. Several ways exist to set the interrupt vector: • jumpers or switches • programmable hardware assemblies (PROMs or PALs) • slave or master programmed registers 8.
6 PowerMAXION Hardware Environment System Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Processor Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Buses. . . .
Device Driver Programming
6 Chapter 6PowerMAXION Hardware Environment 6 6 6 This chapter provides hardware-specific information useful in developing device drivers for PowerMAXION computer systems.This chapter also explains how hardware configuration affects I/O function and performance. Some hardware information applies to every driver—for instance, I/O error handling (affects power failure, alignment errors, controller errors, and bus hangs.
Device Driver Programming 50MHz Processor Bus Local Bus Control Secondary Cache PowerPC 604 Dynamic Local Memory 25MHz Local Bus VME64 Bus SCSI PCI Bus Frontplane Interface VME64 Interface PCI Interface Ethernet System Bus System Frontplane VME64 Backplane Interrupt Controller System Bus Global Memory CIO Clock Generation Interface Console Bus Error Add Reg TOC RTC FLASH PROM Diagnostic Control Local Memory Diagnostic Control CPU ID Register Error ID Register UART Interval Time
PowerMAXION Hardware Environment tained in the hardware. Secondary data cache support is provided. Caches can be disabled in software. They can also be locked and parity checked. Refer to the PowerMAXION Architecture Manual for additional details on the processor board. Memory 6 The PowerMAXION system uses 32-bit addresses for up to four gigabytes of virtual address space. As shown in Figure 6-1, the processor has cached access to local memory.
Device Driver Programming Byte-Ordering and Alignment 6 The byte-ordering convention used in the PowerMAXION platform is Big Endian. In this model, the most significant byte (MSB) always has the lowest address. This provides a consistency of addressing which is independent of the word size of the machine. This is shown in Figure 6-2. (Note that the depicted bit ordering (with bit 31 most significant) is applicable to I/O addressing.
PowerMAXION Hardware Environment Transfer Width Support 6 For all non-block mode transfers, byte, word and long-word addresses are supported. Byte addresses are supported on even and odd addresses. Word addresses (16-bit) are supported on even addresses. Longword transfers are supported on longword addresses. Only longword transfers are supported using VME Block Mode Transfers (BMT).
Device Driver Programming VME Devices as VME Bus Slaves 6 When a processor acts as bus master on the VME bus and addresses VME devices on the VME I/O bus, the VME device is a slave device. The address ranges for VME slave accesses are shown in Table 6-1: Table 6-1.
PowerMAXION Hardware Environment Table 6-2. VME Bus Master Access (Cont.
Device Driver Programming A data transfer malfunction occurs when using an invalid address, address modifier, or transfer on the bus. Another possibility is that the device being addressed does not exist or malfunctions. The kernel normally recognizes VME bus errors and determines, to some extent, the reason for the error. In most cases, the next action taken by the kernel is to panic the system. A panic allows for a fix to be made to a board or device, or for some other action to be taken.
PowerMAXION Hardware Environment Bus Arbitration 6 Because a bus provides the capability to support multiple bus masters, a means of resolving the contention of concurrent requests for bus mastership by multiple devices must be provided. This is the purpose of a special unit on the VME bus, the VME bus arbiter. Bus arbitration is important only for devices that can act as bus masters. This is indicated in a device specification as either “bus master” or “DMA Operation.
Device Driver Programming powerfail, 60 Hz clock, timers, real-time clocks, the console processor, serial or parallel port controllers, and so on. Software interrupt sources include inter-processor interrupts, the softclock interrupt, and context switch interrupts. Interrupt Lines (Levels) 6 On the VME I/O bus, the bus lines carrying the interrupt signal from an interrupt requester to a processor are called interrupt lines. The VME chassis supports 7 interrupt levels.
PowerMAXION Hardware Environment Interrupt Vector Generation and Configuration 6 In hardware, the interrupt process functions as follows. On the VME I/O bus, the interrupt requester requests an interrupt by driving one of the interrupt request lines (IRQ1* to IRQ7* on the bus) active low. This is detected by an interrupt controller that monitors all request lines. The interrupt acknowledge is generated by the CPU to which the request has been directed to by the interrupt controller.
Device Driver Programming 6-12
7 Power Hawk 620/640 Hardware Environment System Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Processor Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Buses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming
7 Chapter 7Power Hawk 620/640 Hardware Environment 7 7 7 The objective of this chapter is to give some background information to address hardware issues involved in developing a device driver for the Power Hawk 620/640 computer systems. This chapter helps understand the effect that hardware configuration has on I/O function and performance. Some hardware issues are general in nature—for example, I/O error handling (power failure, alignment errors, controller errors, bus hangs, and so on).
Device Driver Programming MOUSE PowerPC 604 KEYBOARD L2 Cache PARALLEL I/O 604 System Bus Async Serial ISA SIO PS/2 Floppy Falcon Falcon Sync Serial DRAM ISA Local Resource Bus FLASH NVRAM Raven PIB Sys CSR ISA CSR RTC 33MHz 32/64-BIT PCI LOCAL BUS PMC Slot 1 PMC/PCIX Slot 2 VME Figure 7-1.
Power Hawk 620/640 Hardware Environment Processor/Memory Mezzanine Memory Expansion Connectors Clock Generator Debug Connector (64MB - 1GB DRAM On Mezzanne) Flash PROM L2 Cache 1MB 256K MPC604 Processor 1 MPC604 PHB and MPIC ASIC Secondary Ethernet And SCSI Flash PROM 66MHz MP604 Processor Bus Processor 0 4MB or 8MB DRAM 64MB System Registers Memory Controller Falcon Chipset PCI Expansion 33MHz 32/64-Bit PCI Local Bus PCI Connector 33MHz 32/64-Bit PCI Local Bus Floppy and LED Graphics V
Device Driver Programming Processor Board 7 Figure 7-1 and Figure 7-2 give an overview of the main architectural features of the Power Hawk 620/640 processor boards. The Power Hawk 620 processor board hosts a single processor. The Power Hawk 640 hosts either a single processor or a dual processor. Both the Power Hawk 620 and Power Hawk 640 contain various amounts of memory, an optional L2 cache, I/O interface, various bridge chips, real-time clocks, UART, UltraSCSI interface, etc.
Power Hawk 620/640 Hardware Environment Another bus on the Power Hawk systems is the local ISA bus, which is used to communicate with the serial and parallel ports, NVRAM, and the Real-time Clock Module. There is no provision for customers to add devices to the ISA bus. VMEbus support is provided by a Tundra Universe chip. This chip interfaces between the PCI bus and the industry-standard VMEbus. The VMEbus provides A32 addressing and D64 data transfers.
Device Driver Programming Byte-Ordering and Alignment 7 The byte-ordering convention used in the Power Hawk 620/640 platform is Big Endian. In this model, the most significant byte (MSB) always has the lowest address. This provides a consistency of addressing which is independent of the word size of the machine. See Figure 7-3, “Big Endian Bit and Byte Notation” for more information. (Note that the depicted bit ordering (with bit 31 most significant) is applicable to I/O addressing.
Power Hawk 620/640 Hardware Environment VME Addressing 7 The main objective of this section is to help comprehend the characteristics of data transfers on the VME bus. Understanding these characteristics aids in building device addresses and understanding the error detection and recovery feature of the VMEbus. Transfer Width Support 7 For all non-block mode transfers, byte, word and long-word addresses are supported. Byte addresses are supported on even and odd addresses.
Device Driver Programming VME Address Ranges 7 The following text explains the address ranges used by VME devices on the (H)VME primary I/O bus when they are bus masters or bus slaves. These ranges are detailed in the sections that follow. Unlike PowerMAXION (Night Hawk) systems, on Power Hawk systems the processor address and VME address are not always the same. The various busses and bridge chips between the processor and the VMEbus provide mappings and translations. These are summarized below.
Power Hawk 620/640 Hardware Environment Table 7-2.
Device Driver Programming Considerations” for more information. Also refer to Device Drivers and VME Bus Errors and the iobus_err(2) man page for more details on this feature. VME Device Address Assignment and Configuration 7 The range of addresses reserved within the system memory map for I/O purposes is documented in either the Motorola MVME 2600 Programmer’s Reference Manual or the Motorola MVME 4600 Programmer’s Reference Manual.
Power Hawk 620/640 Hardware Environment Bus arbitration is important only for devices that can act as bus masters. This is indicated in a device specification as either “bus master” or “DMA Operation.” Because bus arbitration is implementation-dependent, the following explains what you need to know about arbitration on the Power Hawk 620/640 systems. Bus Request Levels 7 The VMEbus specification defines extensive bus arbitration options.
Device Driver Programming VME interrupt request lines are only one source of interrupts in the system. VME interrupt request lines are mapped to the Power Hawk 620/640 system’s interrupt levels. For additional details and a list of priority levels and the mapping of interrupt sources to these levels, refer to either the Motorola MVME 2600 Architecture Manual or the Motorola MVME 4600 Architecture Manual. Following are some additional characteristics of the Power Hawk 620/640 interrupt levels.
Power Hawk 620/640 Hardware Environment whereby the IACK* signal is propagated to each device via an IACKIN/IACKOUT* signal chain through the slots on the I/O bus, the interrupt request acknowledgment signal IACK* is received first by the interrupt requester in the lowest slot number. The falling edge of the active low on the IACK* signal validates the data on A03 to A01 address lines.
Device Driver Programming Table 7-3.
8 Motorola MCP750 Hardware Environment SYSTEM OVERVIEW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSOR BOARD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MEMORY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . BUSSES. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . TIMERS.
Device Driver Programming
8 Chapter 8Motorola MCP750 Hardware Environment 8 8 8 SYSTEM OVERVIEW 8 The Motorola MCP750 system is a , single board, uniprocessor, real-time, super-minicomputer. It is based on the Motorola MPC750 processor, an implementation of the PowerPC microprocessor family of reduced instruction set (RISC) microprocessors.
Device Driver Programming The MCP750 provides the 1 MB backdoor external cache option. The Falcon chip set controls the boot Flash and the ECC DRAM. The Raven ASIC functions as the 64-bit PCI host bridge and the MPIC interrupt controller. PCI devices include: Ethernet, a PCI-to-PCI bridge for CompactPCI bus interface (optional second bridge located on companion card), a PCI-toISA/IDE/USB bridge, and one PMC slot.
Motorola MCP750 Hardware Environment Figure 8-1.
Device Driver Programming BUSSES 8 There are two main busses on the MCP750, the processor bus (also called the MPC60X bus) and the 64-bit PCI bus. Interfacing with the processor bus is the MPC750 processor with external cache, the Falcon chipset and the Raven. The Raven supplies the host bridge interface to the primary PCI bus. Interfacing with the primary PCI bus is a PMC slot, a PCI-to-PCI bridge supporting the compact PCI backplane, a PCI-to-ISA/IDE/USB bridge, Ethernet, and one PMC slot.
Motorola MCP750 Hardware Environment - The PCI bus (interrupts from PCI devices) The CPCI bus (interrupts from CPCI devices) Power monitor interrupts Watchdog timer interrupt The ISA bus (interrupts from ISA devices) Some of the features of the Raven ASIC include: Support for 16 external interrupts Support for 15 programmable Interrupt & Processor Task priority levels Support for the connection of an external 8259 for ISA/AT compatibility Distributed interrupt delivery for external I/O interrupts Direct/
Device Driver Programming Figure 8-2, “Big Endian Bit and Byte Notation” for more information. (Note that the depicted bit ordering (with bit 31 most significant) is applicable to I/O addressing. The bit ordering of the Motorola MCP750 is the opposite (with bit 0 most significant). Byte ordering for both I/O and the Motorola MCP750 is the same.) Byte ordering on the PCI bus is little endian. The various bridge chips provide appropriate translation from one ordering to the other for VME bus drivers.
Motorola MCP750 Hardware Environment 8-7
Device Driver Programming 8-8
Motorola MCP750 Hardware Environment 8-9
Device Driver Programming 8-10
9 Understanding the Kernel Environment Overview of the Kernel I/O Structure and Flow of Control . . . . . . . . . . . . . . . . . . . Overview of Source Directories and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . System Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Header Files . . . . . . . . . . . .
Device Driver Programming
9 Chapter 9Understanding the Kernel Environment 9 9 9 This chapter describes the role of device drivers within the kernel and gives an overview of various system files, structures, and kernel support routines that a driver programmer must understand in order to develop a device driver.
Device Driver Programming USER LEVEL User Processes KERNEL LEVEL System Call Interface Scheduler File Subsystem Buffer Cache Character Process Control Subsystem Interprocess Communication Block Memory Management Device Drivers Hardware Control HARDWARE LEVEL Hardware Figure 9-1. Kernel I/O Structure By issuing system calls from the user level, a program accesses the file and process control subsystems, which, in turn, use the character and block interfaces to access the device drivers.
Understanding the Kernel Environment /usr/include/sys directories contain the system header files that contain the definitions of the structures used by device drivers. System Data Structures 9 This section examines the system data structures that are used by all device drivers. Many of these are set up and maintained by the kernel itself. They are often passed as arguments to your device driver routines and can provide information needed by your driver.
Device Driver Programming Table 9-1. System Data Types (Cont.) Type Size Purpose Alignment dev_t 4 major & minor device numbers longword off_t 4 small offset (-OFF_MAX to +OFF_MAX, longword as defined in sys/types.h off64_t 8 l a r g e o ff s e t ( - O F F 6 4 _ M A X t o doubleword + O F F 6 4 _ M A X , a s d e fi n e d i n sys/types.
Understanding the Kernel Environment cmn_err.h Defines the interface to display messages or panic the system. param.h Defines the machine type dependent parameters and various system constants and macros. file.h Defines the status flags that are set by the user on open(2) and fcntl(2) system calls and passed to the driver’s open(D2), close(D2), and ioctl(D2) routines. user.h Defines the per process user structure containing data that is not needed in core when the process is swapped out. uio.
Device Driver Programming The cdevsw structure specifies the interface routines present for the character device. Each device driver can provide open, close, read, write, ioctl, chpoll, and mmap entry point routines. All of these are not necessary. The driver’s entry points are specified in the Master(4) file associated with the driver (see Chapter 16 for an explanation of this file). A driver can be either statically or dynamically linked to the kernel image.
Understanding the Kernel Environment d_msgio VOP_MSGIO() routine called for non-STREAMS character devices that support msgio. d_ttys Pointer to the driver’s array of tty structures. This is for downward compatibility with the advent of STREAMS programming. d_str Pointer to the streamtab structure (used only by STREAMS device drivers). d_name Pointer to character string that contains the name of the device driver.
Device Driver Programming the transfer, two structures are used: the iovec(D4) and uio(D4) structures. These structures are defined in /usr/include/sys/uio.
Understanding the Kernel Environment uio_fmode The file status flags set by the value of the oflag argument specified when the file was opened with an open(2) system call. The flags are defined in the file /usr/include/sys/file.h uio_limit The maximum size in bytes of a file created by a process. This limit is a tunable parameter.
Device Driver Programming /* * Used by drivers */ device_t *devices; /* List of devices on this adapter */ long adapter_state;/* Adapter has been probed,etc */ char *add_info1; /* Pointers to device specific info */ char *add_info2; char *add_info3; char *add_info4; char *add_info5; char *add_info6; char *add_info7; char *add_info8; } adapter_t; The fields in the adapter structure are defined as follows: adapter_name The internal name of the adapter.
Understanding the Kernel Environment cpu Reserved for future use. sio_address Short I/O address of the adapter. The term short I/O refers to the sixteen-bit wide address space of the I/O bus. Drivers do not normally access this field. bus_address Bus I/O address of the adapter. Bus I/O refers to the thirtytwo bit wide address space of the I/O bus. Drivers do not normally access this field. v_sio_address Virtual short I/O address of the adapter.
Device Driver Programming The device Structure 9 The device_t structure is defined in adapter.h as follows: typedef struct struct devices char dev_t long device_t }; Kernel Support Routines devices device_t; { driver[15];/* driver name*/ dev_no;/* major/minor device number*/ dev_type;/* type of device*/ *next;/* next in linked list*/ 9 The objective of this section is to give a synopsis of the kernel support routines for device driver programming.
Understanding the Kernel Environment The command word is a 32-bit integer divided into several fields. The fields are explained in Table 9-2: Table 9-2. Fields in ioctl Command Bits Field Name Purpose 0-7 Command Number A unique number identifying the command. 8-15 IOC Type An arbitrary character (usually first character of driver name). 16-22 Param Size Holds length of argument data. Data must be less than 256 bytes. 29 IO Void If bit is on, there are no parameters.
Device Driver Programming manual for additional information. The system buffers are used to implement the traditional UNIX buffer cache, which is used by block drivers to support I/O operations. The buffer sizes are the size of a file system block, which depends, in turn, on the file system. NOTE Device drivers ported from earlier releases of System V UNIX kernels often used another kernel buffering technique called clist. This feature is not supported in this kernel.
Understanding the Kernel Environment ready to manage its own allocation and deallocation requests. This is done by indexing the memory units in the map structure and calling rmalloc() and rmfree(), respectively. (Note that rmfree() calls have different meanings depending on the context in which they are made; the first call to rmfree() is used to add space to the map. After the first call to rmalloc() occurs, rmfree() is used to return memory space to the map.
Device Driver Programming btopr(D3) Convert size in bytes to size in pages (round up) ptob(D3) Convert size in pages to size in bytes vtop(D3) Convert virtual address to physical address Data Transfer Routines 9 As mentioned previously, one of the roles of device drivers is to perform data transfers between user address space and kernel address space. The kernel provides support routines for this purpose.
Understanding the Kernel Environment Synchronization Routines 9 The kernel provides three broad categories of synchronization/serialization routines: spin locks, sleep locks, and event synchronization primitives. These routines are used to maintain data integrity in the system by serializing process access to shared resources and by synchronizing processes. The routines associated with each category are presented in the sections that follow.
Device Driver Programming Sleep Locks 9 Sleep locks are used for serializing access to shared resources when spin locks cannot be used. At base level, basic locks and read/write locks cannot be used if there is a a possibility that the kernel might put the process to sleep while the lock is being held, as in the case of a context switch. Sleep locks are blocking—the calling process is put to sleep until the lock becomes available.
Understanding the Kernel Environment sor. Only interrupt requests at level 4 or higher are presented to the processor. All other requests are ignored until the same processor lowers the interrupt level. A device driver can be programmed to temporarily raise the processor Interrupt Priority Level (IPL) to block undesirable interrupts. Thereafter, the driver lowers the processor’s IPL to its previous level.
Device Driver Programming To assist you in converting between microseconds and clock ticks, the kernel provides the following routines: drv_hztousec(D3) Convert clock ticks to microseconds drv_usectohz(D3) Convert microseconds to clock ticks The kernel provides the following routines for introducing execution delays within the driver code: delay(D3) Delay process execution for a specified number of clock ticks drv_usecwait(D3) Busy wait for a specified time interval Interrupt Vector Routines 9 Fo
Understanding the Kernel Environment device unit identifier or a pointer to a configuration structure. When the interrupt becomes active, the interrupt handler parameter is passed as the first and only parameter to the interrupt routine.
Device Driver Programming offsets in all of its dealings with the rest of the kernel. This is the new off64_t type and with it offsets, up to approximately 1 Terabyte, can be handled by drivers. Having two offset types implicitly requires that the kernel provide two different DDI/DKI interfaces to drivers. On the DKI side, the kernel must know what kind of driver it is dealing with so that it can pass the correctly sized offset whenever it needs to invoke one of the driver's DKI services.
Understanding the Kernel Environment Although old binaries will install correctly, old sources cannot be rebuilt under the new PowerMAX OS without some changes. If they are to remain small offset drivers, an #undef _LARGEFILE64_SOURCE line must be added to the start of the file. In addition, it is recommended that all drivers, large or small, have their sources modified to include D_AUTO in their devflag(D1) declarations.
Device Driver Programming 9-24
10 Developing a Device Driver Understanding the Device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Device Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Configuration Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Device Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Command Sequences . . . . .
Device Driver Programming
10 Chapter 10Developing a Device Driver 10 10 10 This chapter describes the procedures for developing a device driver. It identifies aspects of the device that you need to understand prior to writing the driver and explains the procedures for installing the device in a Series 6000 system. It explains how to develop the driver header file, data structures, and source file. Detailed descriptions of the different types of driver routines are provided.
Device Driver Programming reset in hardware or via a software command. While in this mode, the only functions that the HPS can perform are to open channels, allow the processor to download firmware, run diagnostics, and issue configuration commands. Until the adapter receives a valid configuration command, the adapter cannot open channels or perform any kind of serial I/O. Consult the technical reference manual for your board to learn the configuration modes that are used by your device.
Developing a Device Driver Programmed I/O Support 10 A programmed I/O device does not directly access physical memory. Instead the device supplies data to the CPU only when the CPU reads the data directly from device registers. Data read from a programmed I/O device can be placed in the user’s I/O buffer via the buffer’s virtual address, which is supplied on a call to the driver’s read routine. Consult the technical reference manual for your board to determine whether it is a programmed I/O device.
Device Driver Programming NOTE This section illustrates the installation procedure for a 13-slot model of the Series 6000 platform. Different models have different configurations of the card enclosures and hardware switches. Refer to your Installation Manual for configuration details specific to your particular model. Installing the Device 10 To install a VME board in the system, use the following steps: 1. Power down the machine. 2.
Developing a Device Driver To install the board on the HVME primary I/O bus: • Mount the VME board onto an HVME adapter board (see A1). There is a mounting assembly (four screws) located just above the clock loading board that holds the board in place. • Plug the adapter board into the first available slot position past the processor and memory boards (see A2).
Device Driver Programming The e command displays a byte, word, or longword of memory beginning at the specified memory location. This command can also change the data at that location and subsequent locations to the specified data. 3. Note the result If the console processor returns with the message “HVME Backplane Timeout,” the device has not responded to the given address, address modifier, or word size.
Developing a Device Driver Each type of entry point is briefly described as follows. Initialization Routines 10 Typically, there are some initialization tasks that must be performed before the device is ready to operate within the system. Typically, the initialization tasks include initializing the device hardware, allocating control and data buffers, registering interrupt handlers, and so on. These routines can perform these tasks: init(D2) and start(D2).
Device Driver Programming You might also want to declare other structures for your device driver. The definitions for such structures should be in the device driver’s header file (the .h file) or in the device driver’s source file (the .c file). If the structures are internal to the device driver and not part of a user interface or if they are shared by other kernel files, they can be declared in the driver’s .c file.
Developing a Device Driver Typically, the types of activities performed by a driver’s init() or start() routine are as follows: 1. Find the adapter’s entry in the array of adapter structures keying on the adapter type and adapter number. 2. Read the device’s bus I/O address, and map the device into virtual address space via physmap(D3). 3. Probe for the presence of the adapter at that address by calling badaddr(D3). 4.
Device Driver Programming tine. The rest of the initialization tasks can be coded either in the init() routine or in the start() routine. The Start Routine 10 Specification void xxstart (void ) Return Values None. During system start up, the kernel calls this routine to initialize the driver once it has completely initialized its system services.
Developing a Device Driver Information needed to develop each type of driver I/O service routine is presented in the sections that follow. The Open Routine 10 Specification #include #include #include #include #include #include int xxopen (devp, oflag, otyp, crp) dev_t devp; int oflag; int otyp; cred_t *crp; Return Values • 0 if the device open is successful • A nonzero value if the open fails.
Device Driver Programming FEXCL Interpreted in a driver dependent manner. Some drivers interpret this flag to mean open the device with exclusive access. (fail all other attempts to open the device) The otyp argument specifies the type of open call that is being made. Three distinct and mutually exclusive types of open calls are defined in the file .
Developing a Device Driver The Close Routine 10 Specification #include #include #include #include #include #include int xxclose (dev, oflag, otyp, crp) dev_t dev; int oflag; int otyp; cred_t *crp; Return Values • 0, if the device close is successful • A nonzero integer value if the close fails. The number is returned to the u s e r i n e r r n o ; i t s h o u l d b e a n e r r o r n u m b e r a s d e fi n e d i n
Device Driver Programming The Read Routine 10 Specification #include #include #include #include #include int xxread (dev, uio_p, crp) dev_t dev; uio_t *uio_p; cred_t *crp; Return Values • 0 if the device read is successful • A nonzero value if the read fails. The number is returned to the user in errno; it should be an error number as defined in .
Developing a Device Driver To transfer characters to the user’s I/O buffers, the driver calls the uiomove(D3) kernel function and sets the read–write flag to UIO_READ . Reference information on the uiomove() routine is provided in the corresponding system manual page. Following is a code fragment that illustrates this operation: #include #include #include #include #include #include #include #include
Device Driver Programming The Write Routine 10 Specification #include #include #include #include #include int xxwrite (dev, uio_p, crp) dev_t dev; uio_t *uio_p; cred_t *crp; Return Values • 0 if the device write is successful • A nonzero value if the write fails. The number is returned to the user in errno; it should be an error number as defined in .
Developing a Device Driver The Ioctl Routine 10 Specification #include #include #include #include #include int xxioctl (dev, cmd, arg, mode, crp, rvalp) dev_t dev; int cmd; void * arg; int mode; cred_t *crp; int *rvalp; Return Values • 0 if the device ioctl is successful • A nonzero value if the ioctl fails. The number is returned to the user in errno; it should be an error number as defined in .
Device Driver Programming The Chpoll Routine 10 Specification #include #include #include #include #include int xxchpoll (dev, events, anyyet, reventsp, phpp) dev_t dev; int events; void * anyyet; int reventsp; cred_t *phpp; Return Values • 0 if the poll is successful • A nonzero value if the poll fails. The number is returned to the user in errno; it should be an error number as defined in .
Developing a Device Driver device minor number. If the I/O event for which the device is being polled has not occurred when the driver’s chpoll routine is initially called, the driver returns a pointer to the pollhead structure associated with the device minor number (see the chpoll(D2) manual page in the Device Driver Reference). The poll service then links onto this pollhead structure such information as the processes that are waiting for the I/O event and the events for which they are waiting.
Device Driver Programming the mmap routine returns NOPAGE. If the offset does exist, mmap returns the physical page ID for the page at offset off in the device’s memory. This physical page ID is a machine-specific token that uniquely identifies a page of physical memory in the system. A driver calls kvtoppid(D3) to get the physical page ID for a particular virtual address. Drivers call phystoppid(D3) to get the physical page ID for a physical address.
Developing a Device Driver The Intr Routine 10 Specification void xxintr(ivec) int ivec; Return Values None. The ivec argument specifies a driver-defined number that identifies the device that generated the interrupt. This entry point is required only if the driver provides support for interrupts generated by a device it controls. This entry point is called by the kernel when the processor services a hardware interrupt request from the device.
Device Driver Programming waiting on completion of a write request that data have been written from the internal driver buffers by waking up any base-level driver processes sleeping on the I/O event. If the driver has called SV_WAIT(D3) or SV_WAIT_SIG(D3) to wait for the completion of the write request, the interrupt handler must call SV_SIGNAL(D3) to wake the sleeping process, thus completing the write request on behalf of the user process.
Developing a Device Driver device driver uses a local routine to probe each VME slot until the device is found. It ignores slots that are already marked as configured. When it finds the HSA controller in a slot, it fills the associated adapter array entry with the slot and bus address Error Handling 10 A device driver should be coded to handle all sorts of error possibilities, including invalid arguments and data passed from a user to a malfunctioning hardware device.
Device Driver Programming Finally, the kernel provides an error reporting facility. This facility consists of a kernel error logging routine, an error log driver, and user commands that collect and report errors. To use this facility, you must make sure that the error daemon is invoked during the boot from the /etc/rc2.d/S30errdemon scripts. The error daemon is invoked using errdemon(1M).
Developing a Device Driver When a process blocked by SLEEP_LOCK_SIG is interrupted by a job control stop signal and is subsequently continued, the SLEEP_LOCK_SIG routine transparently retries the lock (the call cannot return without the lock). If the lock is acquired, SLEEP_LOCK_SIG returns TRUE. When the process is interrupted by another type of signal, or a stop signal for which a non-default disposition has been specified, SLEEP_LOCK_SIG returns FALSE.
Device Driver Programming in SV_WAIT_SIG and needs to be wakened. If the flag is still set, the interrupt routine clears it and then invokes SV_SIGNAL to wake the process: . . . case HPS_IOCB_COMPLETE: . . . if ( iocb->iocb_state & IOCB_NEEDS_SV_SIGNAL ) { . . . iocb->iocb_state &= ~IOCB_NEEDS_SV_SIGNAL; . . . SV_SIGNAL(hp->hps_syncvar, 0); . . . } In this case, the driver frees the IOCB at base level.
11 Multithreading a Device Driver The Multithreaded, Preemptive Kernel and Device Drivers . . . . . . . . . . . . . . . . . . . 11-1 Protecting a Device Driver. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-1 Using the Synchronization Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-4 Spin Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-5 Basic Locks . . . . .
Device Driver Programming
11 Chapter 11Multithreading a Device Driver 11 11 11 This chapter describes the methods for protecting a device driver in a multiprocessor system. It provides an introduction to the multithreaded, preemptive kernel and protection mechanisms. It shows the procedures for using spin locks, sleep locks, and synchronization variables to protect critical sections of code. The Multithreaded, Preemptive Kernel and Device Drivers 11 The kernel used on the Series 6000 system is multithreaded and preemptive.
Device Driver Programming • Linked lists, state fields, and other data structures used by the driver • Global variables • Hardware registers As indicated in the previous section, the mechanisms that can be used are spin locks, sleep locks, and synchronization variables. When multithreading a driver, the first step is to check the areas of the program level code that raise IPL. These areas are protecting device driver structures from being corrupted by program level/interrupt level interactions.
Multithreading a Device Driver of some code depends upon the current state being constant, then the lock that protects updates to the state must be held during execution of this code. Note that words that contain more than one state are a problem. Different bits in the same word used for distinctly different purposes must be protected by a single lock. This is because an update of a bit is not necessarily an interlocked operation.
Device Driver Programming Using the Synchronization Primitives 11 The synchronization primitives to use in a multithreaded environment are spin locks, sleep locks, and synchronization variables. The choice of the type of primitives to be used depends on the way the data are accessed, the amount of contention for the data, and the duration of the accesses. The following sections describe these synchronization primitives and explain their usage.
Multithreading a Device Driver Spin Locks 11 Spin locks are low-level, busy waiting synchronization primitives. They coordinate access to data structures and coordinate the activities of an interrupt stream on one processor with execution streams on other processors. They also guard critical regions that are very short in duration (that is, less than the time that it takes to perform two context switches). Spin locks have no mechanism for queueing waiters on a critical section.
Device Driver Programming Basic Locks 11 After you have defined a basic lock’s lock information structure by using the LKINFO_DECL(D5) macro, you must allocate and initialize the lock. This is done by calling the calling the LOCK_ALLOC(D3) routine. While the kernel sometimes statically allocates locks, device drivers are strongly encouraged to always use LOCK_ALLOC to allocate their locks. Use of LOCK_ALLOC enhances the portability of the driver. #include #include #include #include
Multithreading a Device Driver Note that strictly speaking, the interrupt levels listed here are machine independent abstractions of the hardware interrupt priority levels used by a hardware platform. In particular, the interrupt levels defined here have no absolute value, but a relative ordering. Setting a given priority level blocks interrupts at or below that level. The following partial order is defined: pltimeout < pldisk, plstr <= plhi.
Device Driver Programming Upon acquiring a lock with the priority level set at the specified pl, LOCK returns the previous priority level to the caller. NOTE Be sure that the calling context has not already acquired the specified spin lock using LOCK because a deadlock results. To attempt to acquire the lock without busy waiting if the lock is not immediately available, you use the TRYLOCK routine: #include #include #include
Multithreading a Device Driver #include #include #include void lock_t LOCK_DEALLOC(lockp) *lockp; where: lockp is a pointer to the basic lock to be deallocated. The LOCK_DEALLOC routine has no return value. For additional information on the spin lock interfaces, refer to the corresponding system manual pages.
Device Driver Programming #include #include #include #include rwlock_t uchar_t pl_t lkinfo_t int *RW_ALLOC(hierarchy, min_pl, lkinfo_p, flag) hierarchy; min_pl; *lkinfo_p; flag; where: hierarchy is the hierarchy value that asserts the order in which to acquire the lock relative to other basic and read/write locks. Acceptable hierarchy values range from 1 to 32 inclusive.
Multithreading a Device Driver NOTE Do not use the plbase priority value for the min_pl argument This value is invalid because it does not block any interrupts. lkinfo_p is a pointer to a lkinfo structure. The lk_name component of the lkinfo structure points to a character string defining a name that identifies the lock. This name should begin with the driver prefix. The lkinfo structure can be shared only with other basic locks or read/write locks. It cannot be shared with sleep locks.
Device Driver Programming Upon acquiring the lock, the RW_TRYRDLOCK routine returns the previous priority level. If the lock is not acquired, the RW_TRYRDLOCK routine returns the value invpl (invalid IPL). To acquire a read/write lock in write mode, invoke the RW_WRLOCK routine. #include #include #include pl_t rwlock_t pl_t RW_WRLOCK(lockp, pl) *lockp; pl; where: lockp is a pointer to the read/write lock to be acquired.
Multithreading a Device Driver pl is the interrupt priority level to be set after releasing the lock. The RW_UNLOCK routine has no return value. Finally, to deallocate a read/write lock, you use the RW_DEALLOC routine: #include #include #include void rwlock_t RW_DEALLOC(lockp) *lockp; where: lockp is a pointer to the read/write lock to be deallocated. The RW_DEALLOC routine has no return value.
Device Driver Programming #include #include #include #include sleep_t int lkinfo_t int *SLEEP_ALLOC(arg, lkinfo_p, flag) arg; *lkinfo_p; flag; where: arg is an unused argument reserved for future use that must be set to 0. lkinfo_p is a pointer to a lkinfo structure. The lk_name component of the lkinfo structure points to a character string defining a name that identifies the lock. This name should begin with the driver prefix.
Multithreading a Device Driver prihi High priority primed Medium priority (recommended) prilo Low priority Drivers can use these values to request a priority appropriate to a given type of device or to request a priority that is high, medium or low relative to other activities within the kernel. In general, it is recommended that you use the primed value. The SLEEP_LOCK routine has no return value. SLEEP_LOCK attempts to acquire the lock specified by lockp.
Device Driver Programming porarily boost the priority of an LWP which is in the timesharing class as a reward for voluntarily blocking itself.
Multithreading a Device Driver #include #include #include bool_t lock_t SLEEP_LOCKOWNED(lockp) *lockp; where: lockp is a pointer to the sleep lock to be queried. The SLEEP_LOCKOWNED routine returns TRUE (a non-zero value) if the lock is currently held by the calling context or FALSE (zero) if the lock is not currently held by the calling context. To release a sleep lock, use the SLEEP_UNLOCK routine: #include #include
Device Driver Programming Using Multiple Locks 11 If multiple LWPs are contending for the resources of the driver, it can be more efficient to have a different lock for each data item. Efficiency is gained because access to the different data is allowed from different processors at the same time. The trade-off is the overhead that comes from having to make more lock and unlock calls.
Multithreading a Device Driver flag specifies if the caller can sleep waiting for memory if sufficient memory is not immediately available to allocate the synchronization variable. If flag is set to KM_SLEEP, the caller sleeps if necessary until sufficient memory is available. If flag is set to KM_NOSLEEP and if sufficient memory is not immediately available, the SV_ALLOC routine does not sleep but returns immediately.
Device Driver Programming primed Medium priority (recommended) prilo Low priority Drivers can use these values to request a priority appropriate to a given type of device or to request a priority that is high, medium or low relative to other activities within the kernel. In general, it is recommended that you use the primed value. lkp is a pointer to a spin lock which must be locked when SV_WAIT is called. The spin lock is released (atomically) as the calling LWP goes to sleep.
Multithreading a Device Driver If an LWP sleeps because of a call to SV_WAIT_SIG, signals can cause the LWP to wake up. Job control stop signals (SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU) result in the caller’s entering a stopped state; when continued, SV_WAIT_SIG returns normally as if the LWP has been wakened by a call to SV_SIGNAL or SV_BROADCAST.
Device Driver Programming svp is a pointer to the synchronization variable to be broadcast signaled. flags is a bit field for flags. No flags are currently defined for use in drivers, and the flags argument must be set to 0. The SV_BROADCAST routine has no return value. Each LWP that wakes up needs to recheck the sleep condition in case some other LWP has been awakened first and changed this condition. An example of the code for the wake up is as follows: s = LOCK(driver.lock, pldisk) driver.
11 Supporting Direct Memory Access (DMA) Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DMA into User Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DMA into Discontiguous Physical Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Building a Scatter/Gather Chain List. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming
12 Chapter 12 Supporting Direct Memory Access (DMA) 12 12 12 This chapter explains how to program devices that support Direct Memory Access (DMA) using this operating system on the Series 6000 platform. From a hardware perspective, DMA is an optional hardware feature that is commonly supported by devices that must transfer large amounts of data between the device and either system or bus memory. Its chief advantage is that it allows the device to drive its own data transfer in parallel with the processor.
Device Driver Programming system loads it from disk back into RAM. This activity is not under the control of the user and may happen at any time. Memory must not be swapped out when DMA is occurring to it for obvious reasons. Block device drivers, which contain a strategy() entry point, do not need to worry about this issue because the memory defined by the buf header is already locked down when the strategy() routine is called.
Supporting Direct Memory Access (DMA) physical memory pages. If the device is capable of performing scatter/gather DMA, then the driver should create a list of physical addresses and byte counts to define the virtual buffer. This list is often referred to as a chain list. The device will peruse this list and perform the DMA into the proper physical memory areas. The driver, in this case, typically uses vtop(D3) for each page in the buffer.
Device Driver Programming count. Also construct a new chain pair if the addition of this count to the previous pair would result in the count exceeding the maximum permitted. The HSA driver's implementation of the preceding pseudo-code follows. Comments within the code explain each step of the routine. /* * Convert the virtual address range [va, va+len) into the series * of contiguous memory areas in its physical mapping.
Supporting Direct Memory Access (DMA) else { /* * we must add another chain pair * * return an error if there are too many discontiguous * memory areas to fit in an HSA data chain. */ if (chn >= HSHD_MAXCHAIN) return (IMERR_XFER_TOO_LONG); /* * construct a new chain pair here * always set the LWC_DATA_CHAIN flag indicating * that there are more pairs in the list. */ mcb->hdw.chain[chn].ta = pa; mcb->hdw.chain[chn].
Device Driver Programming Direct Memory Access to Kernel Space 12 Because kernel memory is never paged out, the driver writer needs only to handle virtual to physical mapping and construction of data chain lists in order to perform DMA using this memory.
12 Loadable Modules The DLM Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Loadable Module Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Difference between Static Modules and Loadable Modules. . . . . . . . . . . . Overview of the Load Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of the Unload Process . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming
13 Chapter 13Loadable Modules 13 13 13 The Dynamically Loadable Modules (DLM) feature allows you to add a device driver (or other kernel module) to a running system without rebooting the system or rebuilding the kernel.
Device Driver Programming The DLM Mechanism 13 Loadable Module Types 13 Since this book is about device drivers, this chapter focuses on loadable device drivers. However, you should be aware that the DLM feature supports loading and unloading of a variety of kernel module types.
Loadable Modules Overview of the Load Process 13 When a loadable module needs to be added to the system, the DLM mechanism reads the module's loadable image on disk and copies the module into dynamically allocated kernel memory. Once the module is in memory, DLM relocates the module's symbols and resolves any references the module makes to external symbols. DLM then executes special code in the module (called “wrapper” code) that enables the module to initialize itself dynamically.
Device Driver Programming NOTE Loadable high-level drivers (HDRV) cannot be auto loaded. HDRV drivers can, however, be demand loaded using the modadmin command, or demand loaded by init(1M) through the idmodload(1M) command during a system reboot. Demand Unload 13 A demand unload is a user request, made using the modadmin(1M) command, to remove a loadable module from the running system.
Loadable Modules Making Modules Loadable 13 The following sections explain how to convert your non-loadable driver to be a loadable driver. Coding a Wrapper 13 The first step in converting a non-loadable driver to a loadable driver is writing some special initialization code called a “wrapper.” Each loadable module is required to supply the DLM mechanism with a wrapper.
Device Driver Programming The mod_drvdetach routine is called by the driver's _unload routine to disable and remove the driver's interrupts from the running system. This routine is only called if the driver uses interrupts, and is described on the mod_drvdetach(D3) manual page. prefixhalt The halt entry point is called by the DLM mechanism.
Loadable Modules NOTE A DLM can contain only one wrapper macro definition. Note that only MOD_DRV_WRAPPER and MOD_HDRV_WRAPPER module types have the halt argument; all other wrappers have only the remaining four arguments, prefix, load, unload, and description. For non-driver modules, the keyword halt is omitted from the wrapper macro coding. The keyword prefix specifies the driver's prefix, as defined in the driver's Master(4) file, and described on the prefix(D1) manual page.
Device Driver Programming Screen 13-2 shows a sample wrapper for a high level (HDRV) driver. #include #define DRVNAME “xyz - High-Level Driver” STATIC int void int xyz_load(), xyz_unload(); xyzinit(); xyzstart(); MOD_HDRV_WRAPPER(xyz, xyz_load, xyz_unload, NULL, DRVNAME); . . . STATIC int xyz_load(c) int c; { int status; . . .
Loadable Modules Screen 13-4 shows a sample wrapper for a file system module. Notice that this file system module doesn't need to do any clean-up when it is unloaded, so its wrapper defines a NULL _unload routine. #include STATIC int s5_load(void); MOD_FS_WRAPPER(s5, s5_load, NULL, “Loadable s5 FS Type”); . . . STATIC int s5_load(void) { inoinit(); bzero((caddr_t)&s5fshead, sizeof(s5fshead)); s5fshead.f_freelist = &s5ifreelist; s5fshead.f_inode_cleanup = s5_cleanup; s5fshead.
Device Driver Programming Packaging a Loadable Module for Installation 13 Dynamically Loadable Modules under PowerUX are compiled as shared objects. The shared object format gives the DLM implementation the advantages of position independent code and easier module relocation when the DLM is dynamically loaded and linked into the kernel. To compile shared objects, certain compiler and linker options must be specified. Most of these additional options have been hidden from the developer.
Loadable Modules The $modtype line in the Master file lets you define a character string that helps identify a driver in error messages. This string can be a maximum of 40 characters long, including all white spaces. For a description of the Master file format, refer to the Master(4) manual page. System File Definitions for Loadable Modules 13 To be configured into a running system, all loadable drivers must identify themselves as loadable drivers in the System component of their DSP.
Device Driver Programming The global auto-unload delay values are defined as: DEF_UNLOAD_DELAY 60 0 3600 This says that, by default, any loadable module becomes a candidate for auto unloading when the module has not been accessed for 60 seconds. If your driver wants to override the kernel's default auto-unload delay value, you can specify a PREFIX_UNLOAD_DELAY value in your driver's Mtune component.
Loadable Modules The -l option instructs modadmin to load a loadable module into the running system. For example, the command modadmin -l lp loads a line printer driver named lp. If the lp driver references symbols in other loadable modules (as defined in the $depend line in its Master file), and some or all of these modules are not already loaded, modadmin loads them along with the lp driver. When loading completes, modadmin prints (on stdout) an integer module-id used to identify driver lp.
Device Driver Programming Unloading the Module 13 The -u and -U options instruct modadmin to unload a module from the running system. For example, the command modadmin -U lp unloads the lp driver by specifying its module name, and the command modadmin -u module-id unloads the lp driver by specifying the module-id returned by the -l option.
14 Driver Installation and Tuning Using idtools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . idtools Utilities and Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . idbuild . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . idcheck . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . idinstall . . . . . . .
Device Driver Programming
14 Chapter 14Driver Installation and Tuning 14 14 14 For device driver writers, installation means different things. If you are installing a driver for a piece of hardware, for example, you'll have some hardware-related installation procedures to follow. When you install the driver you've written on your computer for the first time, you probably are installing the driver without the installation scripts recommended for customer use.
Device Driver Programming for these commands are provided in the Command Reference. Details about the DSP component files (such as the Driver.o, Master, and so on) are covered later in this chapter. idbuild 14 idbuild builds a UNIX system base kernel and/or configures loadable kernel modules using the current system configuration in $OBJ/etc/conf. NOTE $OBJ is a shell environment variable that you must set and export.
Driver Installation and Tuning Base kernel rebuilds are usually needed after a statically linked kernel module is installed, when any static module is removed, or when system tunable parameters are modified. If you execute idbuild without any options and if the environment variable $OBJ is null or /, a flag is set and the kernel rebuild is deferred to next system reboot. idcheck 14 The idcheck command is used to obtain selected information about the system configuration.
Device Driver Programming NOTE The exact pathnames of installed files in /etc/conf can change in future releases. These files should be accessed only by using idinstall, and should never be accessed directly; this is necessary to ensure they work in the future. idinstall -a requires that the module specified is not currently installed. idinstall -u module-name performs an Update DSP (that is, one that replaces an existing device driver component) to be installed.
Driver Installation and Tuning On the next system reboot after a kernel reconfiguration, in sysinit state, the idmknod command is run automatically (by idmkenv) to establish the correct representation of device nodes in the /dev directory tree for the running kernel. idmknod (with the -M option) is also called by idbuild when loadable kernel module configuration is requested. idmknod can be executed as a user level command to test modification of the /dev directory before a DSP is actually built.
Device Driver Programming By default, if the parameter has already been tuned previously, you are asked to confirm the change with the message Tunable Parameter parm is currently set to old_value in /etc/conf/cf.d/stune Is it OK to change it to value? (y/n) If you answer y, the change is made. Otherwise, the tunable parameter is not changed, and the following message is displayed parm left at old_value. However, if you use the -f (force) option, the change is always made and no messages are reported.
Driver Installation and Tuning figuration files from the installation media to the hard disk of the system, installs any DSPs using idinstall, then the UNIX system kernel reconfigures and builds. What this means to you, as the device driver programmer, is that writing the driver is only part of the job. You also need to create the configuration files and write the package installation and removal scripts.
Device Driver Programming Table 14-1. Components of Driver Software Package (DSP) (Cont.) DSP Module Purpose File Affected in /etc/conf Sd Optional system shutdown script sd.d/module-name Space.c Optional driver data structure allocations and initializations pack.d/module-name/space.c Stubs.c Optional stubs for symbols defined in a driver that are not installed pack.d/module-name/stubs.c Modstub.o Optional stub object file for loadable module pack.d/module-name/Modstub.
Driver Installation and Tuning Driver.o 14 A required component, the Driver.o component is the driver object module that is to be configured into the kernel. This object file should be compiled using the C programming language. Master 14 A required component, the Master file describes a kernel module for configuration into the system.
Device Driver Programming component of a DSP is installed, idinstall stores the module's System file information in /etc/conf/sdevice.d/module-name, where the file module-name is the name of the module being installed. Packages should never access System files in /etc/conf directly; they should use the idinstall and idcheck commands instead.
Driver Installation and Tuning 2. Generates a valid id field value (called a tag) and prepends it to the entry. 3. Generates an rstate field with a value of 2, and adds it to the entry, following the id field. Lines of the second form should be used when an rstate value other than 2 must be specified. When presented with a line of this form, idmkinit generates only the id field value and prepends it to the entry. Lines of the third form should be used with caution.
Device Driver Programming * KMA Parameters * KMAGBTIME -------------------------------# seconds btw giveback runs KMAGBTIME * KMA_PAGEOUT_POOL -- 30 5 2400 # bytes reserved for pageout daemon (inc. overhead) KMA_PAGEOUT_POOL 0x1000 0 0x100000 For complete information about the Mtune file format, refer to the Mtune(4) manual page.
Driver Installation and Tuning The contents of the /etc/conf/rc.d directory are linked to /etc/idrc.d whenever a new configuration of the kernel is first booted. On this initial reboot, and on all subsequent reboots, the module's Rc file is invoked upon entering init level 2 (see init(1M)). Following is an example Rc file for pts: if [ -c /dev/pts000 ] then exit fi cd /dev/pts for i in * do NUM=`echo $i | awk '{printf(“%.
Device Driver Programming Packages should never access Sd files in /etc/conf directly; they should use the idinstall command instead. The contents of the /etc/conf/sd.d directory are linked to etc/idsd.d whenever a new configuration of the kernel is first booted. On this initial reboot, and on all subsequent reboots, the module's Sd file is invoked upon entering init level 0, 5, or 6 (see init(1M)). Space.c 14 An optional component, the Space.
Driver Installation and Tuning Packaging the Driver 14 For complete information on the system packaging tools, refer to System Administration Volume 1 and the applicable Section 4 manual pages for the DSP component files. However, following is a brief summary of what is required to create software packages containing drivers, presented here to provide a better context for understanding.
Device Driver Programming Following is an example of a prototype file for a driver add-on package. i pkginfo i postinstall i preremove !default 644 root sys d none d none # # # v v v v /tmp??? /tmp/xyzzy These files are installed by the idinstall command in the postinstall script none/tmp/xyzzy/Driver.o=/etc/conf/pack.d/xyzzy/Driver.o none/tmp/xyzzy/Space.c=/etc/conf/pack.d/xyzzy/space.c none/tmp/xyzzy/Master=/etc/conf/mdevice.d/xyzzy none/tmp/xyzzy/System=/etc/conf/sdevice.
Driver Installation and Tuning When writing a postinstall script, you should make liberal use of echo and message commands to tell the user what is going on. You should also make sure to exit with the appropriate return value based on a successful or unsuccessful installation. Following is an example postinstall script for a driver add-on package.
Device Driver Programming 3. Invoke idbuild without any options to cause the kernel to be rebuilt when the system is rebooted. Following is an example preremove script for a driver add-on package. CONFDIR=/etc/conf CONFBIN=${CONFDIR}/bin DRIVER=xyzzy for MODULE in ${DRIVER} do ${CONFBIN}/idcheck -p ${MODULE} RES=“$?“ if [ “${RES}“ -ne “100” -a “${RES}“ -ne “0” ] then ${CONFBIN}/idinstall -P ${pkgname} -d ${MODULE} 2>> /tmp/${MODULE}.
Driver Installation and Tuning Removing a Package 14 As shown above, the installation process is relatively simple and straightforward from the user's viewpoint. Removing a package is even easier. 1. The user executes the pkgrm command. 2. A prompt asks the user which package to remove. 3. The preremove script deletes all the files and commands associated with the package, calling the idinstall -d command. 4.
Device Driver Programming Updating a DSP 14 If a check for the existence of the DSP (using idcheck) turns up positive, a postinstall script should use the idinstall update option. This is assuming that it makes sense to update the DSP, and in any event, you should require a positive verification, or at least give the user the option of aborting, before updating an existing DSP.
Driver Installation and Tuning removed. An idbuild is required to reconfigure the kernel once the DSP has been removed. Building a New Kernel 14 A new kernel needs to be built when installing or removing a DSP, after all of the DSP component modules (for example, Master, System, Init, and so on) have been installed or removed from the appropriate locations. It is usually a good idea to rebuild and reboot after a DSP update, as well.
Device Driver Programming Documenting Your Driver Installation 14 If you are developing a DSP to be installed by users who might not be familiar with the implications of reconfiguration, some words of caution might be worthwhile. • Although experience has shown little difficulty in installing and removing a variety of device drivers, there is the possibility that you might have difficulty booting the system. The cause of this probably would be due to some fault in the added driver.
15 Driver Testing and Debugging Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preparing a Driver for Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . General Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Putting Debug Statements in a Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Device Driver Programming
15 Chapter 15Driver Testing and Debugging 15 15 15 Introduction 15 Testing a device driver consists of installing the driver on a working system and attempting to try all of its functions under a variety of operating conditions. Debugging a driver is largely a process of analyzing the code to determine what could have caused a given problem. The UNIX system includes some tools that can help, but because the driver operates at the kernel level, these tools can only provide limited information.
Device Driver Programming 4. ioctl(D2), read(D2), write(D2) and/or strategy(D2) and print(D2) When the driver seems to be functioning properly under normal conditions, begin testing the error logs by provoking failures. For instance, take a tape or disk off-line while a read/write operation is going. After you are comfortable that both the hardware and software behaves as it should during error situations, it is time to concentrate on formal performance testing.
Driver Testing and Debugging a file or to a remote terminal. You can also write cmn_err statements to the console, but massive amounts of statements to the console severely slows system speed. Calculations and cmn_err statements that are for debugging and other testing should be coded within conditional compiler statements in the driver.
Device Driver Programming Installing a Driver for Testing 15 Many of the steps that follow require you to modify files and directories owned by root. You must therefore be logged in as root or execute with the appropriate privileges to develop and debug device drivers. 1. First of all, it would be a good idea to make a copy of your current UNIX operating system kernel before reconfiguring the system. The backup is made automatically by the idbuild command saving the kernel as /stand/unix.
Driver Testing and Debugging Common Driver Problems 15 Following is a discussion of some common driver bugs, with possible symptoms. These should be used only as suggestions. Each driver is unique and can have unique bugs. Coding Problems 15 Simple coding problems usually show up when you try to compile the driver. In general, these are similar to coding problems for any C program, such as failure to #include necessary header files, define all data structures, or properly delineate comment lines.
Device Driver Programming Timing Errors 15 Timing errors occur when the driver code executes too quickly or too slowly for the device being driven. For instance, the driver might read a status register on a device too soon after sending the device a command. The device might not have had time to update the status register, so the status register is perceived by the driver to be all 0 bits when, in fact, the device might just be slow in posting the correct status register setting.
Driver Testing and Debugging the input and output. As soon as any one of these operations fails, you should reboot the system immediately to ensure that kernel memory is sane. Driver Debugging Techniques 15 This section describes the key facilities that are available to help you debug a driver. These include the console processor, crash(1M), kdb(1), and cmn_err(D3). Use of these facilities is explained in the sections that follow.
Device Driver Programming • If a system panic is repetitively occurring in a section of driver code, a breakpoint can be set beforehand in that code in order to halt the processor and examine the machine state before the kernel panic code is executed. If you want to set a breakpoint during system boot, the following procedure is used: • Before booting the system (CP fb or fr /boot command), set bit 8 in processor register boot (CP command p boot 100).
Driver Testing and Debugging Understanding the p command of the console processor debugging commands is essential to booting the system and debugging the device driver. The hexadecimal values that are beneficial to use with the p command for processor register boot are as follows: Table 15-2. Important Parameters to the p Console Processor Command Value Meaning 1 Requests file name for boot. Asks user to specify the program to load. 2 Boots the operating system to single–user mode.
Device Driver Programming # # INIT: :New run level: 0 The system is coming down. Please wait. CPU 0 halted 001fea24 [001fea24] pause_self+60% 48000000 b pause_self+60 CPU 1 halted 001fe9a0 [001fe9a0] reboot+34 % 3c600053 lis r3,0x53 #0>p boot boot = 00000882 82. #0>fb Reset Backplane Initialize Interrupts Set Run Mode CPU 0 CPU 1 dsk(a,0,0,0)/. dsk(a,0,0,0)/boot NH Boot Loader Boot : /stand/unix 3011036+629040+1806412 start 0xE000 symbol table loaded NightHawk Power_UNIX Release 2.
Driver Testing and Debugging 001baf5c [001baf5c] idle+84 % 80700014 lwz r3,0x14(r16) #0> #0>b gdread #0>r # dd if=/dev/rusr of=/dev/null count=1 CPU 1 breakpoint 001247ec [001247ec] gdread %*3821ffb0 subi r1,r1,0x50 CPU 0 halted 001baf5c [001baf5c] idle+84 % 80700014 lwz r3,0x14(r16) #1> #1>g (CPU 1 halted) pc = 001247ec r1 = 029c4190 lr = 000c6908 msr cr = 43200000 ctr = 001247ec ipl = 00 r0 r2 = 00000000 r3 = 01980002 r4 = 029c4280 r5 r6 = 001247ec r7 = 00000000 r8 = 00000001 r9 r10 = 2f44e976 r11 = 0000
Device Driver Programming CPU 1 breakpoint 00124808 [00124808] gdread+1c %*48000095 bl gdsize CPU 0 halted 001baf5c [001baf5c] idle+84 % 80700014 lwz r3,0x14(r16) #1> #1>qs sp --------- KERNEL STACK --------029c4140 gdread() at 124808(gdread+1c) 029c4190 spec_read() at c6908(spec_read+248) 029c4210 read() at 469bc(read+1ac) 029c42a0 systrap() at 204728(systrap+378) 029c4400 process_trapret() at 20bdb8(process_trapret) #1> System Panic 15 The scenario presented in this section shows the probable result of
Driver Testing and Debugging 00: 00: hsa: Adapter 8 configured in slot 10. 00: SCSI disk @ID 0 on hsa adapter 8. 00: hsa: Adapter 9 configured in slot 11. 00: SCSI disk @ID 0 on hsa adapter 9. 00: hs8 scsi id 0: Generic Fujitsu settings established. Checking root filesystem 997 files, 54883 used, 15396 free (2356 frags, 1630 blocks, 3.
Device Driver Programming STACK TRACE FOR PROCESS 30 LWP 0: xcmn_panic+0x64 () xcmn_err+0x160 () cmn_err+0x58 () kpageflt+0x268 () trap+0xe8c () Xexcept+0x140 () TRAP TO Xexcept+0x100 REGISTER VALUES: TYPE: c dsisr: 0 r2: 0 r6: 7 r10: 20030000 r14: 0 r18: 2ff7ef5c r22: 0 r26: 0 r30: 0 cr: 42224000 strread+0x344 spec_read+0x218 read+0x1ac systrap+0x378 process_trapret TRAP TO process_trapret REGISTER VALUES: TYPE: c dsisr: 0 r2: 0 r6: 7 r10: 20030000 r14: 0 r18: 2ff7ef5c r22: 0 r26: 0 r30: 0 cr: 42224000 RE
Driver Testing and Debugging CPU 0 CPU 1 dsk(a,0,0,0)/. dsk(a,0,0,0)/boot NH Boot Loader Boot : /stand/unix 2997340+626016+2768732 start 0xE000 symbol table loaded Load-Only option set (VM NOT enabled). CPU 0 halted 00788598 ____debug_line+141838% 3821ff10 subi r1,r1,0xf0 #0>r Load-Only option set (VM enabled). CPU 0 halted 001efff4 [001efff4] sysinit+54 % 48000459 bl conf_proc #0> #0>b gdinit #0>r NightHawk Power_UNIX Release 2.
Device Driver Programming #0> #0>bk all #0>r 00: 00: The system is coming up. Please wait. 00: 00: hsa: Adapter 8 configured in slot 10. 00: SCSI disk @ID 0 on hsa adapter 8. 00: hsa: Adapter 9 configured in slot 11. 00: SCSI disk @ID 0 on hsa adapter 9. 00: hs8 scsi id 0: Generic Fujitsu settings established. Checking root filesystem Node: betsy Checking /var filesystem INIT: :option: boot to single user mode.
Driver Testing and Debugging The system automatically saves the dump image when it detects an improper shutdown. By default, when entering multi-user mode, the memory image and the kernel image are saved to /var/crashfiles. NOTE To reduce the amount of memory to be copied to disk at a system crash, you can reduce the amount of RAM used by the system by using the MAXPMEM tunable parameter. This parameter is set in the /etc/conf/mtune.d/kernel file.
Device Driver Programming the starting address of the stack, list the registers with the panic command. proc List the process table. Use this information to obtain the process slot number of the process that panicked the system. stack Dump the stack. Use this information to determine the size of the stack frame. If stack returns information that you suspect is corrupted, use proc to get a list of process table slots and then use stack on each individual slot entry. stat List system statistics.
Driver Testing and Debugging matically under various conditions, such as panics and breakpoint traps. Any time the kdb>> prompt displays, you are in the debugger. I/O is performed through the console or a serial terminal. To exit the debugger, press CTRL-d or q. When you exit and re-enter the debugger, its state is preserved, including the contents of the value stack.
Device Driver Programming analysis. If the error is recoverable, the driver should not panic the system.
16 Special Considerations Device Drivers and Real Time. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Device Drivers and VME Bus Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Additional Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Device Drivers and Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . System Requirements . . . . . . . . . . . . .
Device Driver Programming
16 Chapter 16Special Considerations 16 16 16 This chapter describes the special factors that you must consider when developing a device driver for a real-time production environment. It also provides an overview of the security issues that affect development of a device driver for the PowerUX kernel. Device Drivers and Real Time 16 The length of an interrupt routine is very important in a real-time system because an interrupt routine cannot be preempted to execute a high-priority task.
Device Driver Programming should not be blocked for long periods of time. A device driver that is written for a conventional UNIX kernel can block interrupts for long periods of time without causing problems. Because a conventional UNIX kernel cannot be preempted while executing in kernel mode, blocking interrupts is detrimental only to device throughput. Device interrupts can be blocked for a very long time before throughput is affected.
Special Considerations system start-up script, to register itself to catch a range of VME addresses. If a VME bus error occurs within this registered range of VME addresses, then a user-specified signal is sent to that process. It is up to the signal handler to decide what action should be taken in order to correct the situation, such as resetting the device, re-issuing a command to the device, or even shutting the simulation and/or system down. The usual coding sequence for using iobus_err(2) is to: 1.
Device Driver Programming 4. Based on the state of the device and the information from the IO_INFO iobus_err(2) call, the signal handler should decide what action to take, such as resetting the device, re-issuing the command, shutting down the simulation, etc. Additional Considerations 16 On some systems, a VME bus error warning signal is sent to any process registered to catch a VME bus error, regardless of which range of VME addresses that process is registered to catch.
Special Considerations labeling of imported or exported data. For a description of these and related issues, refer to the TCSEC. Design and Implementation Issues 16 The file system is designed to implement overall system requirements for device protection, naming, access control, and auditing. Device driver files must be marked with appropriate system MAC (Mandatory Access Control) and DAC (Discretionary Access Control) access permissions.
Device Driver Programming 16-6
17 Writing a User-Level Device Driver Understanding a User-Level Device Driver. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What Is a User-Level Device Driver?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What Are the Advantages and Disadvantages of a User-Level Driver?. . . . . . . Which Types of Devices Are Candidates for a User-Level Driver?. . . . . . . . . . What Affects the Complexity of a User-Level Device Driver? . . . . . . . . . . . . .
Device Driver Programming Create a User-Level Interrupt Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Provide Debug and Status Information. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Restore the Device to its Initial State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debugging the Driver. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17 Chapter 17Writing a User-Level Device Driver This chapter provides an overview of user-level device drivers. It describes the components that make up a user-level driver and explores the issues that are involved in developing one. It provides an introduction to the operating system support for user-level drivers. It explains the procedures for developing the driver routines and a configuration program for the device controlled by the driver.
Device Driver Programming What Are the Advantages and Disadvantages of a User-Level Driver?17 The chief advantage of a user-level device driver is that it provides a low-overhead method of performing I/O operations. Without a user-level device driver, you must use system calls to perform I/O operations--a procedure that is costly in terms of time and overhead.
Writing a User-Level Device Driver Because of these limitations, it is intended that a user-level device driver be used only by applications that execute in a controlled environment and have strict real-time performance requirements.
Device Driver Programming Single-User Drivers versus Multiuser Drivers 17 Developing a user-level device driver that allows only one lightweight process to access a device at a time is much simpler than developing a driver that permits multiple lightweight processes to access a device simultaneously. The reason is that there is little need to synchronize access to the device, its associated driver, and shared resources when access is limited to a single lightweight process.
Writing a User-Level Device Driver different types of driver routines that can be provided is presented in “Overview of UserLevel Device Driver Routines” on page 17-9; the standard error codes that can be returned by the driver routines are described in “Overview of Error Returns” on page 17-13. An overview of the device configuration program is provided in “Overview of the Device Configuration Program” on page 17-14.
Device Driver Programming Shared Memory Regions 17 Shared memory regions are needed to provide access to a device’s registers and to provide access to driver-related status information that must be shared by multiple processes. Two shared memory regions are required for each device controller--a device register region and a driver status region. The shared memory regions created for a particular controller are used by all of the user processes that perform I/0 to the controller.
Writing a User-Level Device Driver int register_id; /* IPC id for register region */ unsigned int register_offset;/* register offset into shared memory */ unsigned short ivct; /* interrupt vector for interrupt routine */ unsigned short initial_ivct; /* old interrupt vector */ unsigned short vme_modifier; /* vme modifier */ unsigned short initial_vme_modifier; /* old vme modifier */ int device_spl; /* spl level requested for interrupts */ int spl_level; /* spl level to use for spin-locks */ dr11w_modes_t mo
Device Driver Programming 1. Define a reserved section of physical memory by initializing the res_sects[] array in the /etc/conf/pack.d/mm/space.c file. The size of the section that you reserve should be bound by the size of the largest single data transfer that can be made by using the particular DMA device or the size of the largest single transfer that the application makes. 2.
Writing a User-Level Device Driver you use the userdma(2) system call to prepare a buffer for DMA transfers. The dmavec structure has been defined to describe a physical buffer fragment. This structure is defined in the file
Device Driver Programming Generally a user-level device driver performs I/O asynchronously rather than synchronously. The reason is that asynchronous I/O operations require the least amount of overhead. Blocking for synchronous I/O operations requires a process to enter the kernel; entering the kernel defeats the purpose of providing a user-level device driver. A user-level driver usually provides routines for initiating an asynchronous I/O request and checking the status of an asynchronous I/O operation.
Writing a User-Level Device Driver Overview of Interrupt-Handling Issues 17 A user-level driver can be written to support only polling and provide no interrupt support. If you write a user-level driver of this type, you can use two methods to allow I/O requests to be sent to the driver: 1. Permit the application using the driver to send only one I/O request to the driver at a time. 2.
Device Driver Programming Overview of Synchronization Issues 17 During development of a user-level device driver, you must address a number of synchronization issues. These include synchronization of processes’ access to the device register region and the driver status region described in “Overview of Data Structures” on page 17-5 and synchronization of a user-level interrupt process’s access to the driver status region with other processes’ access to that region.
Writing a User-Level Device Driver overview of these system calls is provided in “Process Synchronization Tools” on page 17-19. Overview of Error Returns 17 User-level device driver routines return a successful completion code, or they return an error code directly instead of using errno. A set of standard error codes that can be used by user-level device drivers is defined in the file . An error message that corresponds to each error code is also defined.
Device Driver Programming Table 16-1. User-Level Device Driver Error Codes and Messages (Cont.
Writing a User-Level Device Driver Understanding Operating System Support for a User-Level Driver 17 Operating system support for writing and using a user-level device driver consists of system calls, library routines, and process synchronization tools. This section describes these forms of support and explains how they are used. The userdma(2) system call allows you to prepare a buffer for DMA transfers; it is described in “The userdma(2) System Call” on page 17-15.
Device Driver Programming • The application’s buffer must be locked in physical memory; that is, the buffer must be resident, and the virtual to physical mappings must not be allowed to change. • The application must know the physical location of the buffer. • CPU access and I/O access to the buffer must be coherent. • The virtual pages containing the buffer must be marked “used” and for DMA read operations, “modified.
Writing a User-Level Device Driver buffer a pointer to an I/O buffer in the user’s virtual address space size the size of the I/O buffer in bytes userdma_flags the control flags that specify the types of I/O operations to be performed using the buffer.
Device Driver Programming functions. The order in which the functions are executed is the reverse of the order in which they are registered with a call to atexit. You might want to use the atexit routine to ensure that a call is made to the driver routine that is responsible for cleaning up opened devices and freeing all allocated resources.
Writing a User-Level Device Driver is suggested that the string indicate the name of the routine that has produced the error. The uderror routine writes the following to the standard error: the specified string, followed by a colon, a space, a brief error message corresponding to the specified error code, and a newline.
Device Driver Programming exclusion mechanisms, and coordinating client-server interaction among processes. Descriptions of the tools that are pertinent to development of a user-level device driver are provided in the sections that follow. Busy-Wait Mutual Exclusion Tools 17 PowerUX busy-wait mutual exclusion tools include a low-overhead busy-wait mutual exclusion variable and a corresponding set of macros. The busy-wait mutual exclusion variable is a data structure known as a spin lock.
Writing a User-Level Device Driver able and re-enable rescheduling and to determine the number of rescheduling locks in effect. These macros are briefly described as follows: resched_lock increment the number of rescheduling locks held by the calling thread, and disable rescheduling resched_unlock decrement the number of rescheduling locks held by the calling thread. If the resulting number of rescheduling locks is zero, rescheduling is re-enabled.
Device Driver Programming Procedures for using the server_block and the server_wake1 system calls in a user-level driver’s interrupt routine are explained in “Developing the Driver’s Interrupt Service Routine” on page 17-34. The User-Level Interrupt Library Routines and Utility 17 The PowerUX and Secure/PowerUX operating systems provide the support necessary to allow a process to connect a routine to an interrupt vector for the interrupt generated by a selected device and to enable the connection.
Writing a User-Level Device Driver The vme_address(3C) Library Routine 17 The vme_address(3C) routine enables you to obtain a 32-bit physical address for an A16 or an A24 (H)VME address generated by a particular device. A 32-bit physical address is required when you use the shmbind(2) system call or the shmconfig(1M) command to bind a shared memory region to a section of physical (H)VME memory.
Device Driver Programming shmget(2) to obtain the shared memory identifier for the region shmat(2) to attach the shared memory region to the process’s virtual address space It is recommended that on the first call to the driver’s open routine, the atexit(3C) routine be called to register an internal driver routine to close open devices when a process exits. Procedures for using the atexit(3C) routine are explained in “The atexit(3C) Library Routine” on page 17-17.
Writing a User-Level Device Driver Return Value The driver’s open routine returns EUD_NOERROR if the device is successfully opened. Otherwise, it returns a user-level device driver error code (see “Overview of the Device Configuration Program” on page 17-14 for a listing of the error codes as defined in ).
Device Driver Programming For an I/O device that performs programmed I/O or a user-level device driver that does intermediate buffer copying, the user-level driver does not need to use physical addresses to describe the user’s I/O buffer. In such cases, the I/O routines of user-level drivers written by Concurrent Computer Corporation personnel are still required to accept a udbuf_t structure to describe the I/O buffer; however, only the virtual address portion of the structure is used.
Writing a User-Level Device Driver Return Value The driver’s aread routine returns EUD_NOERROR if the operation is successfully queued. It returns the appropriate user-level device driver error code if an error occurs (see “Overview of the Device Configuration Program” on page 17-14 for a listing of the error codes as defined in ).
Device Driver Programming Parameters dev_desc the identifier for the device to which data are to be written. This identifier is returned by the driver’s open routine. buff_desc a pointer to the user I/O buffer that describes the physical locations from which data are to be written count the number of bytes to be written req_id a pointer to the location to which the request identifier of the asynchronous write operation is returned.
Writing a User-Level Device Driver Return Value The driver’s acheck routine returns EUD_NOERROR if the specified asynchronous I/O operation has been completed. It returns EUD_INPROGRESS if the operation has not been completed (see “Overview of the Device Configuration Program” on page 17-14 for a listing of the error codes as defined in ).
Device Driver Programming Parameters dev_desc the identifier for the device to or from which the asynchronous I/O operation is being performed. This identifier is allocated on a call to the driver’s open routine. req_id the request identifier of the asynchronous I/O operation for which the process is waiting. This identifier is allocated by the driver if a pointer is supplied on a call to the driver’s aread or awrite routine.
Writing a User-Level Device Driver A general purpose control function similar to the ioctl routine used by kernel device drivers has not been defined. The control functions that are required for a user-level driver are specific to the device. If you are developing a user-level driver for use as an alternative to a kernel device driver, it is suggested that you derive the names of control functions from the names of the ioctl commands that have been defined in the kernel driver.
Device Driver Programming • Ensuring that all I/O operations have been completed This function is especially important for a device that uses DMA because the process might exit after the close and a pending DMA could overwrite the memory of a different process. The device identifier allocated by the driver should not be used after the close routine has been invoked.
Writing a User-Level Device Driver Example specification and pseudo code for a user-level driver’s close routine is presented as follows: int dev_close(dev_desc) int dev_desc; { Wait for all pending I/O operations to complete. Free the device descriptor. Detach the driver’s shared memory and device register regions. Mark the device closed. Return success status.
Device Driver Programming Developing the Driver’s Interrupt Service Routine 17 To develop a user-level driver routine that services interrupts generated by a device controlled by the driver, you must use the operating system’s support for user-level interrupt routines as described in “The User-Level Interrupt Library Routines and Utility” on page 17-22. Remember, the user-level interrupt routine facility is optional.
Writing a User-Level Device Driver 1. Provide for communication between the user-level interrupt process and other processes to which the driver is linked by attaching the driver status and device register regions and other shared memory regions as appropriate. 2. Determine the interrupt vector to which the user-level interrupt process connects.
Device Driver Programming the process is in this state, all signals are ignored. The process no longer executes at normal program level. Each time the connected interrupt becomes active, the CPU that is receiving the interrupt switches to the context of the connected interrupt process within the kernel. The kernel then jumps to the beginning of the interrupt-handling routine with the connected interrupt still active.
Writing a User-Level Device Driver For those user-level interrupt applications that want to bind some portion of their address space to local memory on a Series 6000 system that has more than one CPU board, the following steps must be taken in order to prevent data incoherences. 1. Determine which CPU is receiving the interrupt to which you want to connect the user-level interrupt process.
Device Driver Programming and the Secure/PowerUX kernels, the exception-handling code checks for interrupt-handling routines. • An interrupt-handling routine can make only two system calls: server_wake1(2) and server_wakevec(2). These calls enable the calling process to wake one or more processes that are blocked in the server_block(2) system call (see “The Server System Calls” on page 17-21 for a description of these calls). Certain limitations apply to an interrupt-handling routine’s use of these calls.
Writing a User-Level Device Driver -i create the user-level interrupt process -d display debug and status information -x remove the user-level device driver’s association with the device, and restore the device to its initial state These functions are performed for each device for which a valid device special file name is specified as an argument to the program. The -c option is required of all user-level drivers. The -i option is required of a user-level driver that supports interrupt-driven I/O.
Device Driver Programming 3. Initialize global data structures that contain information about a particular device, and initialize synchronization primitives. 4. Initialize and reset the device. For information on the use of ftok and the shmget, shmbind, and shmat system calls, refer to the PowerUX Programming Guide and to the stdipc(3C), shmget(2), shmbind(2), and shmat(2) system manual pages.
Writing a User-Level Device Driver Provide Debug and Status Information 17 You might want to provide the -d option to facilitate debugging. To support the -d option, the device configuration program displays the values that the device register region and the driver status region contain. The type of information that you choose to provide depends upon the nature of the device and the driver.
Device Driver Programming • Use printf throughout your code. • Maintain event statistics and trace information. Maintain a trace buffer in shared memory, and write a tool to display your trace buffer. • Use logic analyzers (for example, an oscilloscope, a VMEbus analyzer, a character communication analyzer) to determine whether or not data are being correctly transferred from the device.
A Appendix AExample PCI User-Level Device Driver 1 1 1 This appendix contains an example of a user-level device driver for a National Instruments PCI DIO-96 card. /* * * * * * * * * * * * * * * * * * * * * * * * * * * */ Copyright (C) 1999 Concurrent Computer Corporation All rights reserved PCIex.c Sample very simple user level driver for National Instruments PCI DIO-96 card. Turns a LED on and off at two second intervals for two minutes.
Device Driver Programming #include #include
Example PCI User-Level Device Driver int bus,dev; PCI_DWORD dev_vend_id; bus = PCITAG_BUSNUM(tag); dev = PCITAG_DEVNUM(tag)+1; for (; bus <= MAX_PCI_BUS; bus++) { for (; dev <= MAX_PCI_DEV; dev ++) { unsigned short devid,vendid; tag = PCI_MAKE_TAG(bus,dev,func); dev_vend_id = pci_cfg_read(tag, PCI_ID0_REG); vendid = dev_vend_id & 0x0000ffff; devid = dev_vend_id >> 16; if (vendid == 0xffff) { continue; } else { /* Is it the vendor id/dev id of this device? */ if( (vendid == vid) && (devid == did) ) { return
Device Driver Programming perror("PCIud - unable to alloc DIO Base address 0 (PCImite) "); goto hot_swap_only; } /* map base address 1 */ if (pci_cfgspc_alloc(tag, PCI_BASE_ADDR1, &bar1) != 0) { rc = errno; perror("PCIud - unable to alloc DIO Base address 1 "); goto hot_swap_only; } /* activate PCI IO and MEM decodes */ if (pci_cfg_cmd(tag, PCI_CMD_MEM , PCI_ENABLE) != 0) { rc = errno; perror("PCIud - unable to set cmd register "); goto hot_swap_only; } /* Base Address 0 ..
Example PCI User-Level Device Driver goto error_exit; } /* bind phys address of PCI dev to shm_id */ if (shmbind(bar1_shm_id, bar1.
Device Driver Programming } if (bar0_shm_id != NULL) {/* check if shmid valid */ shmctl(bar0_shm_id, IPC_RMID, NULL);/* yes, free it */ bar1_shm_id = NULL; } exit(rc); hot_swap_only: pci_cfg_cmd(tag, PCI_CMD_MEM, PCI_DISABLE); /* disable PCI device */ if (bar1.len) /* see */ if (pci_cfgspc_free(tag, PCI_BASE_ADDR1, &bar1) != 0) { perror("PCIud - unable to free DIO Base address 1 "); bar1.len = 0; } if (bar0.
Glossary 2 2 2 adapter A hardware set which connects one or more device controllers to the computer system. alignment The position in memory of a unit of data, such as a word or half-word, on an integral boundary. A data unit is properly aligned if its address is evenly divisible by the data unit's size in bytes. For example, a word is correctly aligned if its address is divisible by four. A half-word is aligned if its address is divisible by two.
Device Driver Programming block data transfer The method of transferring data in units (blocks) between a block device such as a magnetic tape drive or disk drive and a user program. block device A device, such as a magnetic tape drive or disk drive, that conveys data in blocks through the buffer management code. Compare character device.
Glossary cache A section of computer memory where the most recently used buffers, i-nodes, pages, and so on are stored for quick access. character device A device, such as a terminal or printer, that conveys data character by character. Compare block device. character driver The driver that conveys data character by character between the device and the user program.
Device Driver Programming device understands. For example, on a disk drive, the controller accepts a request to read a file and converts the request into hardware commands to have the reading apparatus move to the precise location and send the information until a delimiter is reached. critical code A section of code is critical if execution of arbitrary interrupt handlers could result in consistency problems.
Glossary device switch table The kernel table constructed during automatic configuration that contains the address of each driver entry point routine (for example, open(D2), close(D2), strategy(D2)). dev_t The C programming language data type declaration that is used to store the driver major and the minor device numbers. diagnostic A software routine for testing, identifying, and isolating a hardware error. A message is generated to notify the tester of the results.
Device Driver Programming FDDI Fiber Distributed Data Interface. function A kernel utility used in a driver. The term function is used interchangeably with the term kernel function. The use of functions in a driver is analogous to the use of system calls and library routines in a user-level program. initialization entry points Driver initialization routines that are executed during system initialization (for example, init(D2), start(D2)).
Glossary kernel buffer cache A set of buffers used to minimize the number of times a block-type device must be accessed. lightweight process A lightweight process or LWP is the set of data and interfaces at user level that provide support for the threads abstraction. loadable module A kernel module (such as a device driver) that can be added to a running system without rebooting the system or rebuilding the kernel.
Device Driver Programming module A STREAMS module consists of two related queue structures, one each for upstream and downstream messages. One or more modules may be pushed onto a stream between the stream head and the driver, usually to implement and isolate a line discipline or a communication protocol. virtual to physical memory.
Glossary raw I/O Movement of data directly between user address spaces and the device. Raw I/O is used primarily for administrative functions where the speed of a specific operation is more important than overall system performance. raw mode The method of transmitting data from a terminal to a user without processing. This mode is defined in the line discipline modules. read queue The half of a STREAMS module or driver that passes messages upstream.
Device Driver Programming small computer system interface (SCSI) The American National Standards Institute (ANSI) approved interface for supporting specific peripheral devices. special device file The file that identifies the device's access type (block or character), the external major and minor numbers of the device, the device name used by user-level programs, and security control (owner, group, and access permissions) for the device.
Glossary thread An abstraction of the concept of execution in a shared address space. A sequence of instructions that are executed as an independent entity and are scheduled by system software. unbuffered I/O I/O that bypasses the file system cache for the purpose of increasing I/O performance for some applications. upstream The direction of STREAMS messages flowing through a read queue from the driver to the user process.
Device Driver Programming Glossary-12
Index A acheck routine 17-28 adapter structure 9-9, 10-9 address assignment and configuration 4-8, 5-8, 6-8, 7-10 address management routines 9-15 address modifier 4-5, 5-6, 6-5, 7-7, 10-2 address types 4-5, 5-5, 6-5, 7-7 aread routine 17-26 asynchronous I/O support 17-25 atexit routine 17-17 await routine 17-29 awrite routine 17-27 B badaddr routine 9-15, 10-9 basic locks 9-17, 11-6 bdevsw table 2-3, 2-8-2-10 biodone routine 12-2 board installation 10-4 btop routine 9-15 btopr routine 9-16 building a new
Device Driver Programming DLM 13-2 DMA device 17-3 dma_pageio(D3) routine 12-3 DR11W user-level driver 17-30 Driver user-level 17-1 driver configuration 2-10, 9-2, 9-9, 10-9, 10-20, 14-614-22 data structures 10-7 DR11W 17-30 entry points 2-7 I/O 10-7 initialization 2-8, 10-7 interrupt 2-10, 10-7 header file 10-7 I/O service routines 10-10 initialization routines 10-8 installation 2-10, 14-6-14-22 interfaces 2-6 block and character interface 2-6 STREAMS interface 2-6 interrupt service routine 10-20 interrup
Index 10-20, 17-34, 17-40 interrupt-handling routine constraints 17-37 interrupts 2-3, 15-6 intr routine 10-21 iobus_err 6-8, 7-9 ioctl macros 9-12 ioctl routine 10-17 iomem_alloc routine 9-15 iovec structure 9-7 itimeout routine 9-19 ivec_alloc routine 9-20, 10-9 ivec_alloc_group routine 9-20 ivec_free routine 9-20 ivec_free_group routine 9-20 ivec_init routine 10-9 K kdb utility 13-14, 15-19 kernel I/O structure 9-1 kernel support routines 9-12 kmem_alloc routine 9-14, 10-9 kmem_alloc_physcontig(D3) rou
Device Driver Programming P parallel execution 2-3 physiock routine 12-2 physmap routine 10-9 physmap_alloc routine 9-15 physmap_free routine 9-15 phystoppid routine 10-20 pkgadd command 14-18 pkginfo files 14-15 pkgmap file 14-15 pkgmk command 14-15 pkgproto command 14-15 pkgrm command 14-19 pkgtrans command 14-15 pollhead structure 10-19 polling support 17-4 pollwakeup routine 10-19 postinstall script 14-15, 14-16 preremove script 14-17 process synchronization tools 17-19 processor board 4-2, 5-1, 6-1, 7
Index SV_ALLOC routine 9-18, 11-18 SV_BROADCAST routine 9-18 SV_DEALLOC routine 9-18, 11-22 SV_SIGNAL routine 9-18, 11-21 SV_WAIT routine 9-18, 11-19 SV_WAIT_SIG routine 9-18, 11-20 switch table entry points 2-8 synchronization issues 17-12 synchronization primitives 9-17-9-18, 11-3-11-4 synchronization tools 17-19 synchronization variables 9-18, 11-18 system buses 4-3, 5-3, 6-3, 7-4 system data structures 9-3 System file 2-12, 14-9, 15-4 system header files 2-12 T timeout routine 9-19 timing and timeout
Device Driver Programming Index-6