Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

device_driver(3K)

sc_panic(3K)



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)

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026