interrupt_management(3K) SDK R4.11 interrupt_management(3K)
NAME
interrupt_management: io_mask_interrupt_variety,
io_unmask_interrupt_variety, nk_jp_are_my_interrupts_disabled,
nk_jp_disable_my_interrupts, nk_jp_enable_my_interrupts - handle
kernel interrupts
SYNOPSIS
#include "/usr/src/uts/aviion/ii/i_io.h"
#include "/usr/src/uts/aviion/ii/i_nk.h"
void io_mask_interrupt_variety (interrupt_variety)
uc_interrupt_enum_type interrupt_variety; /*READ ONLY*/
void io_unmask_interrupt_variety (interrupt_variety)
uc_interrupt_enum_type interrupt_variety; /*READ ONLY*/
#include "/usr/src/uts/aviion/ii/i_vp.h"
boolean_type nk_jp_are_my_interrupts_disabled ()
void nk_jp_disable_my_interrupts ()
void nk_jp_enable_my_interrupts ()
where:
interrupt_variety The type of interrupt to be masked or unmasked.
DESCRIPTION
The following routines are described in this man page:
io_mask_interrupt_variety Mask a specified variety of interrupt
io_unmask_interrupt_variety Unmask a specified variety of interrupt
nk_jp_are_my_interrupts_disabled
Check whether interrupts are disabled
nk_jp_disable_my_interrupts Disable interrupts
nk_jp_enable_my_interrupts Enable interrupts
The kernel provides routines to mask and unmask device interrupts and
processor interrupts. The routines to mask and unmask interrupts are
architecturally independent, allowing applications that use these
routines to be unaware of the processor they are currently executing
on.
Disabling Interrupts on a Single Processor
You use nk_jp_disable_my_interrupts to disable all interrupts on the
processor on which your LWP is executing. The call keeps that pro
cessor from receiving interrupts. When you disable interrupts on
your home processor, your LWP cannot be preempted or interrupted; in
a certain sense your LWP now "owns" that processor. For this reason,
you should use great care when disabling processor interrupts.
In nonsymmetric systems, LWPs often disable processor interrupts for
locking purposes--in order to have exclusive access to a resource,
such as a data structure. This does not work under symmetric pro
cessing because disabling interrupts on one processor does not pre
vent another LWP executing on a different processor from accessing
the resource.
Processor interrupts are enabled using the routine
nk_jp_enable_my_interrupts. Any interrupt that occurred while inter
rupts were disabled was saved and will occur immediately when inter
rupts are enabled.
The disabling of interrupts on a processor is nested, such that for
every disable an enable is required before interrupts are actually
enabled on the processor. This prevents premature enabling of inter
rupts. You can use nk_jp_are_my_interrupts_disabled to determine if
the processor's interrupts are already disabled.
Masking Interrupts for a Particular Device
In addition to enabling/disabling interrupts for the entire proces
sor, you can use io_mask_interrupt_variety and
io_unmask_interrupt_variety to mask and unmask interrupts for a par
ticular device. Masking device interrupts stops the device from in
terrupting on all processors.
The device mask and unmask routines take a parameter called inter
rupt_variety of type uc_interrupt_enum_type that allows drivers to
maintain architectural independence. There are
uc_interrupt_enum_type constants defined for every interrupt type for
all hardware architectures the DG/UX system supports, for example,
Uc_Keyboard_Interrupt, Uc_SCSI_Interrupt, Uc_Duart_Interrupt. Using
these pre-defined values means your code can be used by all Data Gen
eral machines that use the DG/UX system. For example, code to mask
the duart interrupt would operate unchanged on all Data General ma
chines that have duarts and the DG/UX system.
The masking of a device interrupt is nested, such that for every mask
an unmask is required to actually unmask the interrupt.
Device drivers must mask device interrupts as part of the procedure
to gain exclusive access to device registers. Because of the DG/UX
kernel's symmetric multiprocessing, it is possible for one processor
to be issuing commands to a device while another processor is han
dling a completion interrupt for the device. In both cases, the code
must access the device registers. The following standard locking
procedure keeps two sets of code from attempting access simultaneous
ly:
NOT_INTERRUPT_HANDLER: | INTERRUPT_HANDLER:
|
io_mask_interrupt_variety( | if(!obtain_lock_no_wait(
Uc_Some_Interrupt); | &controller_lock)
obtain_lock(&controller_lock); | return;
. | .
(manipulate registers) | (manipulate registers)
. | .
release_lock(&controller_lock); | .
io_unmask_interrupt_variety( | release_lock(
Uc_Some_Interrupt); | &controller_lock);
Non-interrupt handler code (let's call it completion code) must mask
the device's interrupts before it obtains a lock on the device's reg
isters. This is done to prevent the device from interrupting and in
voking interrupt handler code on a processor other than the comple
tion code's home processor. Such masking of the device interrupts
prevents a potential deadlock situation that can occur if interrupt
handler and completion code are executing on the same processor.
Consider the scenario of completion code executing on Processor A and
accessing device X without masking device interrupts. First, the
completion code obtains a lock on the device registers. If the de
vice interrupts Processor A while the lock was held, we would enter
interrupt handler code. The interrupt handler code would try to ob
tain the lock but would fail and return. However, the interrupt
would still be high on the processor because the interrupt handler
could not access the device registers to acknowledge the interrupt.
The processor would therefore return immediately to the interrupt
handler code to service the interrupt, which would return because it
could not obtain the lock, etc. This cycle would continue forever,
deadlocking the system. Now, consider the same scenario with the
completion code masking the device interrupts before acquiring the
device register lock. In this case the device cannot interrupt the
processor while the controller lock is held, thus avoiding the dead
lock scenario.
In the above scenario, the deadlock could also be avoided by having
completion code disable all processor interrupts instead of just the
device interrupts. However, under symmetric multiprocessing, dis
abling processor interrupts is not sufficient.
Consider the scenario of completion code executing on Processor A
that simply disables all processor interrupts. This prevents the de
vice from interrupting Processor A, thus avoiding the deadlock de
scribed earlier. However, under symmetric multiprocessing the device
may still interrupt another processor, say Processor B. In this
case, Processor B would execute interrupt handler code, try to obtain
the lock held by Processor A, fail and return. As before, the inter
rupt would remain high, causing Processor B to repeat the procedure.
This would continue until the completion code on Processor A released
the lock.
Although this situation would not cause the system to deadlock, it is
inefficient to have Processor B sit in a loop trying to service the
interrupt until the lock is released by Processor A. Now consider
the same scenario where completion code masks the device interrupt
before obtaining the lock. The masking prevents the interrupt from
being generated to ANY processor, thereby avoiding the situation just
described.
The two scenarios described show the necessity for a driver to mask
device interrupts. The routine io_unmask_interrupt_variety is used
to unmask the interrupts. If a device generates an interrupt while
it is masked by the processor, the interrupt is not lost. When the
interrupt is unmasked, it will occur immediately.
Constants and Data Structures
This subsection describes constants and data structures defined in
the include files cited in the SYNOPSIS section and used by the rou
tines documented in this man page.
Try to avoid dependencies on the specifics of these structures, such
as size or location of fields, because these specifics may change in
later releases of the software. You can verify exact variable defi
nitions in the appropriate include file. The best way to avoid such
dependencies is to use kernel-supplied routines to manipulate these
structures.
uc_interrupt_enum_type
typedef enum
{
Uc_System_Alarm_Clock_Interrupt = 0,
Uc_Keyboard_Interrupt = 1,
Uc_Parallel_Port_Interrupt = 2,
Uc_Ethernet_Interrupt = 3,
Uc_SCSI_Interrupt = 4,
Uc_Duart_Interrupt= 5,
Uc_Graphics_Device_Interrupt = 6,
Uc_Level_1_VME_Interrupt = 7,
Uc_Level_2_VME_Interrupt = 8,
Uc_Level_3_VME_Interrupt = 9,
Uc_Level_4_VME_Interrupt = 10,
Uc_Level_5_VME_Interrupt = 11,
Uc_Level_6_VME_Interrupt = 12,
Uc_Level_7_VME_Interrupt = 13,
Uc_Dma_Terminal_Count_Interrupt = 14,
Uc_System_Console_Interrupt = 15,
Uc_Zbuffer_Interrupt = 16,
Uc_Sync_Interrupt = 17,
Uc_Fdc_Interrupt = 18,
Uc_Soft_Memory_Error_Interrupt = 19,
Uc_Vme_Channel_0_Interrupt = 20,
Uc_Vme_Channel_1_Interrupt = 21,
Uc_Vme_Channel_2_Interrupt = 22,
Uc_Vme_Channel_3_Interrupt = 23,
Uc_Vme_Channel_4_Interrupt = 24,
Uc_Vme_Channel_5_Interrupt = 25,
Uc_Audio_Interrupt = 26,
Uc_Kmi_Interrupt = 27,
Uc_Autolut_Interrupt = 28,
Uc_EISA_Irq_0_Interrupt = 29,
Uc_EISA_Irq_1_Interrupt = 30,
Uc_EISA_Irq_2_Interrupt = 31,
Uc_EISA_Irq_3_Interrupt = 32,
Uc_EISA_Irq_4_Interrupt = 33,
Uc_EISA_Irq_5_Interrupt = 34,
Uc_EISA_Irq_6_Interrupt = 35,
Uc_EISA_Irq_7_Interrupt = 36,
Uc_EISA_Irq_8_Interrupt = 37,
Uc_EISA_Irq_9_Interrupt = 38,
Uc_EISA_Irq_A_Interrupt = 39,
Uc_EISA_Irq_B_Interrupt = 40,
Uc_EISA_Irq_C_Interrupt = 41,
Uc_EISA_Irq_D_Interrupt = 42,
Uc_EISA_Irq_E_Interrupt = 43,
Uc_EISA_Irq_F_Interrupt = 44,
Uc_Gg_Pci_Dev0_IntA_Interrupt = 45,
Uc_Gg_Pci_Dev1_IntA_Interrupt = 46,
Uc_Gg_Pci_Dev2_IntA_Interrupt = 47,
Uc_Gg_Pci_Dev2_IntB_Interrupt = 48,
Uc_Gg_Pci_Dev2_IntC_Interrupt = 49,
Uc_Gg_Pci_Dev2_IntD_Interrupt = 50,
Uc_Tango_Pci_Dev1_IntA_Interrupt = 51,
Uc_Tango_Pci_Dev2_IntA_Interrupt = 52,
Uc_Tango_Pci_Dev3_IntA_Interrupt = 53,
Uc_Tango_Pci_Dev4_Interrupt = 54,
Uc_Tango_Pci_Dev5_Interrupt = 55,
Uc_Tango_Pci_Dev6_Interrupt = 56,
Uc_Interrupt_Enum_Last = 57
} uc_interrupt_enum_type ;
This type is used to describe the type (or variety) of interrupt to
be masked or unmasked.
io_mask_interrupt_variety
This routine masks interrupts for a device with the specified inter
rupt type. Any devices that use the interrupt variety to interrupt
the system are effectively masked. If there are multiple processors,
the interrupt is disabled for all processors. The routine nests mask
and unmask requests.
The routine uses a mask depth associated with the specified device to
nest interrupts. This routine increments the mask depth, and if the
new value is one, the hardware is updated to reflect a change in the
mask.
You may call this routine from base level or from interrupt level.
It remembers and correctly restores the state of the interrupt enable
flag.
io_unmask_interrupt_variety
This routine unmasks interrupts for a device with the specified in
terrupt type. Any devices that use the interrupt variety to inter
rupt the system are effectively unmasked. If there are multiple pro
cessors, the interrupt is enabled for all processors. The routine
nests mask and unmask requests.
The routine uses a mask depth associated with the specified device to
nest interrupts. This routine decrements the mask depth, and if the
new value is 0, the hardware is updated to reflect a change in the
mask.
You can call this routine from base level or from interrupt level.
It remembers and correctly restores the state of the interrupt enable
flag.
nk_jp_are_my_interrupts_disabled
This routine returns TRUE if interrupts are disabled in the calling
processor.
nk_jp_disable_my_interrupts
This routine disables interrupts in the calling processor.
Interrupts are disabled and the interrupt disable depth count is in
cremented. An interrupt disable depth count is maintained so that
calls to this routine and nk_jp_enable_my_interrupts will nest prop
erly.
nk_jp_enable_my_interrupts
This routine counters a previous call to disable interrupts in the
calling processor. Interrupts are enabled if the disable depth is
returned to zero.
Multiple disable interrupt calls are tracked by the disable count
depth. This routine counteracts one disable call by decrementing the
disable depth count. If this decrement restores the count to its
initial value, interrupts are enabled.
DIAGNOSTICS
Return Value
For nk_jp_are_my_interrupts_disabled:
TRUE Interrupts are disabled in the calling processor.
FALSE Interrupts are enabled in the calling processor.
For the other routines: none.
Errors
None.
Abort Conditions
The io_mask_interrupt_variety routine may invoke the sc_panic routine
with the following error code:
IO_PANIC_ILLEGAL_MASK_INTERRUPT
The mask depth associated with the specified device has
become larger than it should. This must be due to in
correct pairing of the mask and unmask functions by the
caller.
The io_unmask_interrupt_variety routine may invoke the sc_panic rou
tine with the following error code:
IO_PANIC_ILLEGAL_UNMASK_INTERRUPT
The device's mask depth is equal to zero. This must be
due to incorrect pairing of the mask and unmask func
tion calls.
SEE ALSO
device_driver(3K), sc_panic(3K).
Programming in the DG/UX Kernel Environment.
Licensed material--property of copyright holder(s)