ddi_add_softintr(9f) 맨 페이지 - 윈디하나의 솔라나라

개요

섹션
맨 페이지 이름
검색(S)

ddi_add_softintr(9f)

ddi_add_softintr(9F)           Kernel Functions           ddi_add_softintr(9F)



NAME
       ddi_add_softintr,    ddi_get_soft_iblock_cookie,   ddi_remove_softintr,
       ddi_trigger_softintr - software interrupt handling routines

SYNOPSIS
       #include <sys/types.h>
       #include <sys/conf.h>
       #include <sys/ddi.h>
       #include <sys/sunddi.h>

       int ddi_get_soft_iblock_cookie(dev_info_t *dip,
       int preference, ddi_iblock_cookie_t *iblock_cookiep);


       int ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
            ddi_iblock_cookie_t *iblock_cookiep, ddi_idevice_cookie_t *
            idevice_cookiep,
            uint_t(*int_handler) (caddr_t int_handler_arg), caddr_t
       int_handler_arg);


       void ddi_remove_softintr(ddi_softintr_t id);


       void ddi_trigger_softintr(ddi_softintr_t id);

INTERFACE LEVEL
       Solaris DDI specific (Solaris DDI). These interfaces are obsolete.  Use
       the  new interrupt interfaces referenced in Intro(9F). Refer to Writing
       Device Drivers in Oracle Solaris 11.4 for more information.

PARAMETERS
       ddi_get_soft_iblock_cookie()

       dip               Pointer to a dev_info structure.


       preference        The type of soft interrupt  to  retrieve  the  cookie
                         for.


       iblock_cookiep    Pointer  to  a  location to store the interrupt block
                         cookie.



       ddi_add_softintr()

       dip                Pointer to dev_info structure.


       preference         A hint value describing the type of  soft  interrupt
                          to generate.


       idp                Pointer  to  a  soft  interrupt  identifier  where a
                          returned soft interrupt identifier is stored.


       iblock_cookiep     Optional pointer to an interrupt block cookie  where
                          a returned interrupt block cookie is stored.


       idevice_cookiep    Optional pointer to an interrupt device cookie where
                          a returned interrupt device cookie  is  stored  (not
                          used).


       int_handler        Pointer to interrupt handler.


       int_handler_arg    Argument for interrupt handler.



       ddi_remove_softintr()

       id    The identifier specifying which soft interrupt handler to remove.



       ddi_trigger_softintr()

       id    The  identifier  specifying  which  soft interrupt to trigger and
             which soft interrupt handler will be called.


DESCRIPTION
       For ddi_get_soft_iblock_cookie():


       ddi_get_soft_iblock_cookie() retrieves the interrupt block cookie asso‐
       ciated  with a particular soft interrupt preference level. This routine
       should be called before ddi_add_softintr() to  retrieve  the  interrupt
       block cookie needed to initialize locks (mutex(9F), rwlock(9F)) used by
       the software interrupt routine. preference  determines  which  type  of
       soft  interrupt  to  retrieve  the  cookie for. The possible values for
       preference are:

       DDI_SOFTINT_LOW     Low priority soft interrupt.


       DDI_SOFTINT_MED     Medium priority soft interrupt.


       DDI_SOFTINT_HIGH    High priority soft interrupt.



       On a successful return, iblock_cookiep contains information needed  for
       initializing   locks   associated   with   this   soft  interrupt  (see
       mutex_init(9F) and rw_init(9F)). The driver can then initialize mutexes
       acquired  by  the  interrupt  routine before calling ddi_add_softintr()
       which prevents a possible race condition where the driver's soft inter‐
       rupt  handler  is  called  immediately  after  the  driver  has  called
       ddi_add_softintr() but before the driver has initialized  the  mutexes.
       This  can happen when a soft interrupt for a different device occurs on
       the same soft interrupt priority level. If the soft  interrupt  routine
       acquires  the  mutex before it has been initialized, undefined behavior
       may result.


       For ddi_add_softintr():


       ddi_add_softintr() adds a soft interrupt to the system. The user speci‐
       fied  hint  preference identifies three suggested levels for the system
       to attempt to allocate the soft interrupt priority at.  The  value  for
       preference should be the same as that used in the corresponding call to
       ddi_get_soft_iblock_cookie().   Refer    to    the    description    of
       ddi_get_soft_iblock_cookie() above.


       The value returned in the location pointed at by idp is the soft inter‐
       rupt identifier. This value is used in later calls to  ddi_remove_soft‐
       intr()  and  ddi_trigger_softintr()  to identify the soft interrupt and
       the soft interrupt handler.


       The value returned in the location pointed at by iblock_cookiep  is  an
       interrupt block cookie which contains information used for initializing
       mutexes associated with this soft  interrupt  (see  mutex_init(9F)  and
       rw_init(9F)). Note that the interrupt block cookie is normally obtained
       using  ddi_get_soft_iblock_cookie()  to  avoid  the   race   conditions
       described      above      (refer      to     the     description     of
       ddi_get_soft_iblock_cookie() above). For this reason, iblock_cookiep is
       no longer useful and should be set to NULL.


       idevice_cookiep is not used and should be set to NULL.


       The  routine  int_handler, with its argument int_handler_arg, is called
       upon receipt of a software interrupt. Software interrupt handlers  must
       not  assume  that they have work to do when they run, since (like hard‐
       ware interrupt handlers) they may run because a soft interrupt occurred
       for some other reason. For example, another driver may have triggered a
       soft interrupt at the same level. For this  reason,  before  triggering
       the soft interrupt, the driver must indicate to its soft interrupt han‐
       dler that it should do work. This is usually done by setting a flag  in
       the  state  structure. The routine int_handler checks this flag, reach‐
       able through int_handler_arg, to  determine  if  it  should  claim  the
       interrupt and do its work.


       The interrupt handler must return DDI_INTR_CLAIMED if the interrupt was
       claimed, DDI_INTR_UNCLAIMED otherwise.


       If successful,  ddi_add_softintr()  will  return  DDI_SUCCESS;  if  the
       interrupt information cannot be found, it will return DDI_FAILURE.


       For ddi_remove_softintr():


       ddi_remove_softintr()  removes  a  soft  interrupt from the system. The
       soft interrupt identifier  id,  which  was  returned  from  a  call  to
       ddi_add_softintr(), is used to determine which soft interrupt and which
       soft interrupt handler to remove. Drivers must remove any  soft  inter‐
       rupt handlers before allowing the system to unload the driver.


       For ddi_trigger_softintr():


       ddi_trigger_softintr()  triggers  a  soft interrupt. The soft interrupt
       identifier id is used to determine which  soft  interrupt  to  trigger.
       This  function  is  used  by device drivers when they wish to trigger a
       soft interrupt which has been set up using ddi_add_softintr().

RETURN VALUES
       ddi_add_softintr() and ddi_get_soft_iblock_cookie() return:

       DDI_SUCCESS    on success


       DDI_FAILURE    on failure


CONTEXT
       These functions can be called from user or  kernel  context.  ddi_trig‐
       ger_softintr() may be called from high-level interrupt context as well.

EXAMPLES
       Example 1 device using high-level interrupts



       In  the following example, the device uses high-level interrupts. High-
       level interrupts are those that interrupt at the level of the scheduler
       and  above.  High level interrupts must be handled without using system
       services that manipulate thread or process states, because these inter‐
       rupts  are not blocked by the scheduler. In addition, high level inter‐
       rupt handlers must take care to do a minimum of work because  they  are
       not preemptable. See ddi_intr_hilevel(9F).



       In the example, the high-level interrupt routine minimally services the
       device, and enqueues the data for later processing by the  soft  inter‐
       rupt  handler.  If the soft interrupt handler is not currently running,
       the high-level interrupt routine triggers a soft interrupt so the  soft
       interrupt  handler  can process the data. Once running, the soft inter‐
       rupt handler processes all the enqueued data before returning.



       The state structure contains two mutexes. The high-level mutex is  used
       to protect data shared between the high-level interrupt handler and the
       soft interrupt handler. The low-level mutex is used to protect the rest
       of the driver from the soft interrupt handler.


         struct xxstate {
               ...
               ddi_softintr_t             id;
                  ddi_iblock_cookie_t     high_iblock_cookie;
                  kmutex_t                      high_mutex;
                  ddi_iblock_cookie_t     low_iblock_cookie;
                  kmutex_t                      low_mutex;
                  int                              softint_running;
               ...
         };
         struct xxstate *xsp;
         static uint_t xxsoftintr(caddr_t);
         static uint_t xxhighintr(caddr_t);
         ...


       Example 2 sample attach() routine



       The  following  code  fragment  would  usually  appear  in the driver's
       attach(9E) routine. ddi_add_intr(9F) is  used  to  add  the  high-level
       interrupt  handler  and ddi_add_softintr() is used to add the low-level
       interrupt routine.


         static uint_t
         xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
         {
                  struct xxstate *xsp;
                  ...
               /* get high-level iblock cookie */
                  if (ddi_get_iblock_cookie(dip, inumber,
                         &xsp->high_iblock_cookie) != DDI_SUCCESS)  {
                               /* clean up */
                               return (DDI_FAILURE); /* fail attach */
                  }

                  /* initialize high-level mutex */
                  mutex_init(&xsp->high_mutex, "xx high mutex", MUTEX_DRIVER,
                        (void *)xsp->high_iblock_cookie);

                  /* add high-level routine - xxhighintr() */
                  if (ddi_add_intr(dip, inumber, NULL, NULL,
                         xxhighintr, (caddr_t) xsp) != DDI_SUCCESS)  {
                               /* clean up */
                               return (DDI_FAILURE); /* fail attach */
                  }

                  /* get soft iblock cookie */
                  if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
                         &xsp->low_iblock_cookie) != DDI_SUCCESS)  {
                               /* clean up */
                               return (DDI_FAILURE); /* fail attach */
                  }

                  /* initialize low-level mutex */
                  mutex_init(&xsp->low_mutex, "xx low mutex", MUTEX_DRIVER,
                         (void *)xsp->low_iblock_cookie);

                  /* add low level routine - xxsoftintr() */
                  if (ddi_add_softintr(dip, DDI_SOFTINT_MED, &xsp->id,
                         NULL, NULL, xxsoftintr, (caddr_t) xsp) != DDI_SUCCESS) {
                               /* clean up */
                               return (DDI_FAILURE);  /* fail attach */
                  }

                  ...
         }


       Example 3 High-level interrupt routine



       The next code fragment represents the high-level interrupt routine. The
       high-level   interrupt  routine  minimally  services  the  device,  and
       enqueues the data for later processing by the soft  interrupt  routine.
       If the soft interrupt routine is not already running, ddi_trigger_soft‐
       intr() is called to start the routine. The soft interrupt routine  will
       run until there is no more data on the queue.


         static uint_t
         xxhighintr(caddr_t arg)
         {
               struct xxstate *xsp = (struct xxstate *) arg;
               int need_softint;
                  ...
               mutex_enter(&xsp->high_mutex);
               /*
                * Verify this device generated the interrupt
                * and disable the device interrupt.
                * Enqueue data for xxsoftintr() processing.
                */

               /* is xxsoftintr() already running ? */
               if (xsp->softint_running)
                         need_softint = 0;
               else
                         need_softint = 1;
               mutex_exit(&xsp->high_mutex);

               /* read-only access to xsp->id, no mutex needed */
               if (need_softint)
                         ddi_trigger_softintr(xsp->id);
                  ...
               return (DDI_INTR_CLAIMED);
         }

         static uint_t
         xxsoftintr(caddr_t arg)
         {
               struct xxstate *xsp = (struct xxstate *) arg;
               ...
                  mutex_enter(&xsp->low_mutex);
               mutex_enter(&xsp->high_mutex);

               /* verify there is work to do */
               if (work queue empty || xsp->softint_running )  {
                         mutex_exit(&xsp->high_mutex);
                         mutex_exit(&xsp->low_mutex);
                         return (DDI_INTR_UNCLAIMED);
               }

               xsp->softint_running = 1;

               while ( data on queue )  {
                         ASSERT(mutex_owned(&xsp->high_mutex));

                         /* de-queue data */

                         mutex_exit(&xsp->high_mutex);

                         /* Process data on queue */

                         mutex_enter(&xsp->high_mutex);
               }

               xsp->softint_running = 0;
               mutex_exit(&xsp->high_mutex);
               mutex_exit(&xsp->low_mutex);

               return (DDI_INTR_CLAIMED);
         }


ATTRIBUTES
       See attributes(7) for descriptions of the following attributes:


       tab()  box; cw(2.75i) |cw(2.75i) lw(2.75i) |lw(2.75i) ATTRIBUTE TYPEAT‐
       TRIBUTE VALUE _ Interface StabilityObsolete


SEE ALSO
       Intro(9F),  ddi_add_intr(9F),  ddi_in_panic(9F),  ddi_intr_hilevel(9F),
       ddi_remove_intr(9F), mutex_init(9F)


       Writing Device Drivers in Oracle Solaris 11.4

NOTES
       ddi_add_softintr()  may  not be used to add the same software interrupt
       handler more than once. This is true even if a different value is  used
       for  int_handler_arg  in  each  of  the  calls  to  ddi_add_softintr().
       Instead, the argument passed to the interrupt handler  should  indicate
       what  service(s) the interrupt handler should perform. For example, the
       argument could be a pointer to the device's soft state structure, which
       could  contain  a  'which_service' field that the handler examines. The
       driver must set this field to  the  appropriate  value  before  calling
       ddi_trigger_softintr().



Oracle Solaris 11.4               11 May 2021             ddi_add_softintr(9F)
맨 페이지 내용의 저작권은 맨 페이지 작성자에게 있습니다.
RSS ATOM XHTML 5 CSS3