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 de‐
       vice, the driver could alias the 2 interrupts it received to the 30 re‐
       maining 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_al‐
       loc(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.  In‐
                      complete  checking for failure codes could result in in‐
                      consistent 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-in‐
       terrupt 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