|
|
The operating systems' Interrupt Priority Level (IPL) is a software-only scheme that assigns a priority level to every driver/device combination configured in any given system, and also supports hardware interrupts. This is distinct from the built-in hardware priority level used for the 8259 interrupt controller, where the highest priority devices are attached to lower numbered pins on the 8259 chip. The priority decreases from pin-0 to pin-7, with the timer chip using pin-0 and the parallel port using pin-7. In effect, the IPL overcomes limitations imposed on interrupt priorities by the underlying priority interrupt controller system.
The IPL value of a device is defined when the driver is installed. The driver's DSP files can define the IPL for devices on an ISA bus; for most other bus types, the IPL is autoconfigured by reading the IPL value directly from the board. If necessary, the IPL value can be modified with the dcu utility.
The IPL value of a configured device can be directly obtained from the System(DSP/4dsp) file and often reflects the critical nature of the device, and therefore the need to service the interrupt quickly. The timer interrupt, critical to the functioning of the system, has the highest priority, while the printer driver (parallel port driver) has one of the lowest. There are certain exceptions to this rule, such as a serial port with limited on-board FIFOs that has an IPL of 7.
Often systems are equipped with UARTS (a serial port driver), which contain a 1-byte FIFO. Under high line speeds or when the system is very busy, the latency between successive invocations of the serial port interrupt handler could be high, resulting in overruns and lost data. To minimize this data loss, serial port drivers are also often given an IPL of 7.
Standard Intel x86-based systems contain a combination of Programmable Interrupt Controllers (PICs, a pair of master/slave 8259s) with the capability of providing and servicing interrupts over 15 different interrupt lines. In addition, PICs provide the capability of masking any group of interrupts by appropriately downloading a mask to the Interrupt Mask Register (IMR). In other words, if a particular bit in the mask is set, the PIC will not service any interrupts from that hardware device.
The IPL of a driver has a unique role in providing interrupt masking and hence limited ``locking'' capability.
At this time it might be worth
understanding how IPLs are implemented.
When drivers are configured,
a special table called iplmask[]
is set up and contains an entry each for every
possible hardware interrupt.
The contents of each iplmask
entry is a function
of the IPL value of the driver/device combination that owns
the interrupt line, and is sufficient to mask out all interrupts
from devices whose IPL values are
equal to or less than the combination in question.
Before an interrupt can invoke the handler and be serviced, the kernel automatically downloads the mask that corresponds to the device before issuing an End-of-Interrupt (EOI) signal. The net effect is that no interrupts of equal (including interrupts from the same device) or less priority can interrupt the system for the duration of execution of a interrupt handler. However, at the same time the higher/critical interrupts corresponding to devices with higher IPLs can interrupt the system.
This effectively modifies the fifth step of the interrupt handling sequence. The operating system, with the help of the CPU, translates the PIC request into an index into the ivect[] table as follows:
As before, the operating system, with CPU help, still translates the PIC's request to an index into the ivect[] table. Furthermore, it uses the same index to retrieve the corresponding entry from the iplmask[] table and programs the PIC effectively to block out all interrupts with priority levels equal to or less than the interrupt being serviced.
The kernel issues an End-of-Interrupt (EOI) signal, indicating that the interrupt handling sequence is completed. The operating system then indexes into the ivect[] table and invokes the handler to service the interrupt.
IPLs play an important role in supporting the locking primitives discussed in ``Synchronization primitives''. Assume a driver-defined lock is used to protect critical regions of code that can be acquired by both a base context and the interrupt handler. One example would be code that manipulates a device specific job list. As long as the base context and interrupt handler are executed on different processors, data structures are completely protected and serial access to the shared resource is ensured. However, if the interrupt handler is invoked on the same processor where the currently executing base context is holding the lock in question, the system will become deadlocked. The interrupt context is busy-waiting for the spin lock, and the processor cannot schedule the base context, which alone can release the lock.
This leads to the definition of an important attribute of a spin lock, the minimum IPL, which is specified as an argument to the lock allocation routines from the priorities defined on the pl(D5) manual page. The minimum IPL is the greater of the following two IPLs:
For example, all the locks acquired by a disk driver will have a minimum IPL of pldisk, which corresponds to the priority level at which the disk interrupt handler executes. Consider the case of a multiprocessor system where the processors are numbered in sequence 1 to n and both base and interrupt contexts of the disk driver acquire the same set of locks to protect critical regions of code. If a base context acquires a lock at its minimum IPL (pldisk in this example) on processor 1, the disk interrupt handler is effectively locked out and cannot be executed on the same processor. However, the handler can be executed on any other processor whose current IPL is less than pldisk, and since the interrupt handler will contend for the lock held by the base context, it will be forced to spin until it is granted exclusive access to the critical region.
itimeout(D3) and dtimeout(D3) routines are considered types of interrupts, and the minimum IPL should be high enough to block out the highest level callback routine that can contest for the critical regions.
All DDI entry points that allocate or initialize spin locks allow the calling code to specify the minimum IPL to be associated with the lock. In addition, all the contexts trying to acquire a given lock should specify an IPL greater than or equal to the minimum IPL. The current implementation of spin locks raises the IPL to the value suggested by the calling context before trying to acquire the lock. If unsuccessful, the IPL is dropped to its old value and the contexts spins until the lock is released, at which time it starts the acquisition process over again.
See ``Spin locks (DDI)'' for guidelines about selecting an IPL scheme for spin locks.