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

개요

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

ddi_intr_dup_handler(9f)

ddi_intr_dup_handler(9F)       Kernel Functions       ddi_intr_dup_handler(9F)



NAME
       ddi_intr_dup_handler  - reuse interrupt handler and arguments for MSI-X
       interrupts

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

       int ddi_intr_dup_handler(ddi_intr_handle_t primary, int vector,
            ddi_intr_handle_t *new);

INTERFACE LEVEL
       Solaris DDI specific (Solaris DDI).

PARAMETERS
       primary    Original DDI interrupt handle


       vector     Interrupt number to duplicate


       new        Pointer to new DDI interrupt handle


DESCRIPTION
       The ddi_intr_dup_handler() function is a feature for  MSI-X  interrupts
       that allows an unallocated interrupt vector of a device to use a previ‐
       ously initialized or added primary MSI-X interrupt vector in  order  to
       share the same vector address, vector data, interrupt handler, and han‐
       dler arguments. This feature allows a driver  to  alias  the  resources
       provided  by  the Solaris Operating System to the unallocated interrupt
       vectors on an associated device. For example,  if  2  MSI-X  interrupts
       were  allocated  to  a  driver  and 32 interrupts were supported on the
       device, the driver could alias the 2 interrupts it received to  the  30
       remaining on the device.


       The  ddi_intr_dup_handler()  function  must be called after the primary
       interrupt  handle  has  been  added  to  the  system  or   enabled   by
       ddi_intr_add_handler(9F)  and  ddi_intr_enable(9F) calls, respectively.
       If successful, the function returns the  new  interrupt  handle  for  a
       given vector in the new argument passed to the function. The new inter‐
       rupt  handle   must   not   have   been   previously   allocated   with
       ddi_intr_alloc(9F).  Otherwise,  the  ddi_intr_dup_handler()  call will
       fail.


       The  only   supported   calls   on   dup-ed   interrupt   handles   are
       ddi_intr_set_mask(9F), ddi_intr_clr_mask(9F), ddi_intr_get_pending(9F),
       ddi_intr_enable(9F), ddi_intr_disable(9F), and ddi_intr_free(9F).


       A call to ddi_intr_dup_handler() does  not  imply  that  the  interrupt
       source is automatically enabled. Initially, the dup-ed handle is in the
       disabled state and must be enabled before it can  be  used  by  calling
       ddi_intr_enable().  Likewise, ddi_intr_disable() must be called to dis‐
       able the enabled dup-ed interrupt source.


       A dup-ed interrupt is removed by calling ddi_intr_free() after  it  has
       been disabled. The ddi_intr_remove_handler(9F) call is not required for
       a dup-ed handle.


       Before removing the original MSI-X interrupt handler, all dup-ed inter‐
       rupt  handlers associated with this MSI-X interrupt must have been dis‐
       abled and freed. Otherwise,  calls  to  ddi_intr_remove_handler()  will
       fail with DDI_FAILURE.


       See  the  EXAMPLES  section  for  code  that illustrates the use of the
       ddi_intr_dup_handler() function.

RETURN VALUES
       The ddi_intr_dup_handler() function returns:

       DDI_SUCCESS    On success.

                      Note that the interface should  be  verified  to  ensure
                      that  the  return  value  is  not  equal to DDI_SUCCESS.
                      Incomplete checking for failure codes  could  result  in
                      inconsistent behavior among platforms.


       DDI_EINVAL     On  encountering invalid input parameters. DDI_EINVAL is
                      also returned if a dup is attempted from a dup-ed inter‐
                      rupt  or  if the hardware device is found not to support
                      MSI-X interrupts.


       DDI_FAILURE    On any implementation specific failure.


EXAMPLES
       Example 1 Using the ddi_intr_dup_handler() function


         int
         add_msix_interrupts(intr_state_t *state)
         {
           int x, y;

           /*
            * For this example, assume the device supports multiple
            * interrupt vectors, but only request to be allocated
            * 1 MSI-X to use and then dup the rest.
            */
           if (ddi_intr_get_nintrs(state->dip, DDI_INTR_TYPE_MSIX,
              &state->intr_count) != DDI_SUCCESS) {
                   cmn_err(CE_WARN, "Failed to retrieve the MSI-X interrupt count");
                   return (DDI_FAILURE);
           }

           state->intr_size = state->intr_count * sizeof (ddi_intr_handle_t);
           state->intr_htable = kmem_zalloc(state->intr_size, KM_SLEEP);

           /* Allocate one MSI-X interrupt handle */
           if (ddi_intr_alloc(state->dip, state->intr_htable,
               DDI_INTR_TYPE_MSIX, state->inum, 1, &state->actual,
               DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
                   cmn_err(CE_WARN, "Failed to allocate MSI-X interrupt");
                   kmem_free(state->intr_htable, state->intr_size);
                   return (DDI_FAILURE);
           }

           /* Get the count of how many MSI-X interrupts we dup */
           state->dup_cnt = state->intr_count - state->actual;

           if (ddi_intr_get_pri(state->intr_htable[0],
               &state->intr_pri) != DDI_SUCCESS) {
                   cmn_err(CE_WARN, "Failed to get interrupt priority");
                   goto error1;
           }

           /* Make sure the MSI-X priority is below 'high level' */
           if (state->intr_pri >= ddi_intr_get_hilevel_pri()) {
                  cmn_err(CE_WARN, "Interrupt PRI is too high");
                   goto error1;
           }

           /*
            * Add the handler for the interrupt
            */
           if (ddi_intr_add_handler(state->intr_htable[0],
               (ddi_intr_handler_t *)intr_isr, (caddr_t)state,
               NULL) != DDI_SUCCESS) {
                   cmn_err(CE_WARN, "Failed to add interrupt handler");
                   goto error1;
           }

           /* Enable the main MSI-X handle first */
           if (ddi_intr_enable(state->intr_htable[0]) != DDI_SUCCESS) {
                   cmn_err(CE_WARN, "Failed to enable interrupt");
                   goto error2;
           }

           /*
            * Create and enable dups of the original MSI-X handler, note
            * that the inum we are using starts at 0.
            */
           for (x = 1; x < state->dup_cnt; x++) {
               if (ddi_intr_dup_handler(state->intr_htable[0],
                   state->inum + x, &state->intr_htable[x]) != DDI_SUCCESS) {
                       for (y = x - 1; y > 0; y--) {
                           (void) ddi_intr_disable(state->intr_htable[y]);
                           (void) ddi_intr_free(state->intr_htable[y]);
                       }

                   goto error2;
               }
               if (ddi_intr_enable(state->intr_htable[x]) != DDI_SUCCESS) {
                   for (y = x; y > 0; y--) {
                       (void) ddi_intr_disable(state->intr_htable[y]);
                       (void) ddi_intr_free(state->intr_htable[y]);
                   }

                   goto error2;
               }
           }

           return (DDI_SUCCESS);

         error2:
             (void) ddi_intr_remove_handler(state->intr_htable[0]);
         error1:
             (void) ddi_intr_free(state->intr_htable[0]);

             kmem_free(state->intr_htable, state->intr_size);
             return (DDI_FAILURE);
         }

         void
         remove_msix_interrupts(intr_state_t *state)
         {
             int x;

             /*
              * Disable all the handles and free the dup-ed handles
              * before we can remove the main MSI-X interrupt handle.
              */
             for (x = 1; x < state->dup_cnt; x++) {
                 (void) ddi_intr_disable(state->intr_htable[x]);
                 (void) ddi_intr_free(state->intr_htable[x]);
             }

             /*
              * We can remove and free the main MSI-X handler now
              * that all the dups have been freed.
              */
             (void) ddi_intr_disable(state->intr_htable[0]);
             (void) ddi_intr_remove_handler(state->intr_htable[0]);
             (void) ddi_intr_free(state->intr_htable[0]);

             kmem_free(state->intr_htable, state->intr_size);
         }



CONTEXT
       The ddi_intr_dup_handler() function can  be  called  from  kernel  non-
       interrupt context.

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 StabilityCommitted


SEE ALSO
       attributes(7),      ddi_intr_add_handler(9F),       ddi_intr_alloc(9F),
       ddi_intr_clr_mask(9F),    ddi_intr_disable(9F),    ddi_intr_enable(9F),
       ddi_intr_free(9F),     ddi_intr_get_pending(9F),      ddi_intr_get_sup‐
       ported_types(9F), ddi_intr_set_mask(9F)


       Writing Device Drivers in Oracle Solaris 11.4



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