ddi_intr_dup_handler man page on Solaris

Man page or keyword search:  
man Server   20652 pages
apropos Keyword Search (all sections)
Output format
Solaris logo
[printable version]

ddi_intr_dup_handler(9F) Kernel Functions for Drivers 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  interrupt 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(5) for descriptions of the following attributes:

       ┌─────────────────────────────┬─────────────────────────────┐
       │      ATTRIBUTE TYPE	     │	    ATTRIBUTE VALUE	   │
       ├─────────────────────────────┼─────────────────────────────┤
       │Interface Stability	     │Evolving			   │
       └─────────────────────────────┴─────────────────────────────┘

SEE ALSO
       attributes(5),	   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

SunOS 5.10			  09 May 2006	      ddi_intr_dup_handler(9F)
[top]

List of man pages available for Solaris

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net