ddi_intr_dup_handler man page on SmartOS

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

DDI_INTR_DUP_HANDLER(9F)			      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(5) for descriptions of the following attributes:

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

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

				 May 09, 2006	      DDI_INTR_DUP_HANDLER(9F)
[top]

List of man pages available for SmartOS

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