ddi_cb_register man page on SunOS

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

ddi_cb_register(9F)	 Kernel Functions for Drivers	   ddi_cb_register(9F)

NAME
       ddi_cb_register,	 ddi_cb_unregister  - register and unregister a device
       driver callback handler

SYNOPSIS
       #include <sys/sunddi.h>

       int ddi_cb_register(dev_info_t *dip, ddi_cb_flags_t flags,
	     ddi_cb_func_t cbfunc, void *arg1, void *arg2,
	     ddi_cb_handle_t * ret_hdlp);

       int ddi_cb_unregister(ddi_cb_handle_t hdl);

INTERFACE LEVEL
       Solaris DDI specific (Solaris DDI).

PARAMETERS
       ddi_cb_register()

       dip	   Pointer to the dev_info structure.

       flags	   Flags to determine which callback events can be handled.

       cbfunc	   Callback handler function.

       arg1	   First argument to the callback handler.

       arg2	   Second (optional) argument to the callback handler.

       ret_hdlp	   Pointer to return a handle to the registered callback.

       ddi_cb_unregister()

       hdl    Handle to the registered callback handler that is to be unregis‐
	      tered.

DESCRIPTION
       The  ddi_cb_register()  function installs a callback handler which pro‐
       cesses various actions that require the driver's attention while it  is
       attached.  The  driver  specifies  which callback actions it can handle
       through the flags parameter. With each relevant action,	the  specified
       callback	 function  passes  the	arg1 and arg2 arguments along with the
       description of each callback event to the driver.

       The ddi_cb_unregister() function removes a previously  installed	 call‐
       back handler and prevents future processing of actions.

       The flags parameter consists of the following:

       DDI_CB_FLAG_INTR	    The	  device   driver  participates	 in  interrupt
			    resource management. The device driver may receive
			    additional	interrupt  resources  from the system,
			    but only because it can  accept  callback  notices
			    informing  it  when	 it has more or less resources
			    available. Callback notices can occur  at  anytime
			    after the driver is attached. Interrupt availabil‐
			    ity varies based on the overall needs of the  sys‐
			    tem.

       DDI_CB_FLAG_SRIOV    Indicates  to  the	DDI  framework that the device
			    driver is IOV capable. Normally IOV device drivers
			    are	 expected  to call pciv_vf_config(9F)) to con‐
			    figure the VFs during attach  and  register	 call‐
			    backs  with	 this  flag  set  so  that they can be
			    informed through callback  notices	when  VFs  are
			    unconfigured by the DDI framework.

			    If	the  driver  does not explicitly configure the
			    VFs using pciv_vf_config() during attach then  the
			    PCIE  framework  will configure the VFs as part of
			    the post-attach processing if this flag is set.

			    The callback notices while configuring/unconfigur‐
			    ing	 is  performed	with two separate callbacks to
			    the driver PRE and POST. This helps the drivers to
			    prepare for the event during PRE and do the neces‐
			    sary initializations/cleanup during POST notices.

       DDI_CB_FLAG_COMM	    The device driver uses pciv_send(9F) interfaces to
			    communicate across different domains or within the
			    same  domain.  The	driver	may  receive  callback
			    notices that incoming data has been received.

       The cdfunc is a callback handler with the following prototype:

	 typedef int (*ddi_cb_func_t)(dev_info_t *dip,
		       ddi_cb_action_t action, void *cbarg,
		       void *arg1, void *arg2);

       The cbfunc routine with the arguments dip, action, cbarg, arg1 and arg2
       is called upon receipt of any callbacks for which the driver is	regis‐
       tered.	The  callback  handler returns DDI_SUCCESS if the callback was
       handled successfully, DDI_ENOTSUP if it received a callback action that
       it  did	not  know how to process, or DDI_FAILURE if it has an internal
       failure while processing an action.

       The action parameter can be one of the following:

       DDI_CB_INTR_ADD	     For interrupt resource management, the driver has
			     more  available  interrupts. The driver can allo‐
			     cate more interrupt vectors and then set up  more
			     interrupt	  handling    functions	   by	 using
			     ddi_intr_alloc(9F).

       DDI_CB_INTR_REMOVE    For interrupt resource management, the driver has
			     fewer   available	interrupts.  The  driver  must
			     release any previously  allocated	interrupts  in
			     excess   of   what	 is  now  available  by	 using
			     ddi_intr_free(9F).

       The cbarg parameter points to an action-specific argument.  Each	 class
       of  registered actions specifies its own data structure that a callback
       handler should dereference when it receives those actions.

       The  cbarg  parameter  is  defined  as  an  integer  in	the  case   of
       DDI_CB_INTR_ADD	and  DDI_CB_INTR_REMOVE	 actions. The callback handler
       should cast the cbarg parameter to an integer. The  integer  represents
       how  many  interrupts  have been added or removed from the total number
       available to the device driver.

       If a driver participates in interrupt resource management, it must reg‐
       ister  a	 callback  with	 the  DDI_CB_FLAG_INTR	flag.  The driver then
       receives the actions DDI_CB_INTR_ADD  and  DDI_CB_INTR_REMOVE  whenever
       its interrupt availability has changed. The callback handler should use
       the interrupt functions ddi_intr_alloc(9F) and ddi_intr_free(9F)	 func‐
       tions  to respond accordingly. A driver is not required to allocate all
       interrupts that are available to it, but it is required to  manage  its
       allocations  so	that  it never uses more interrupts than are currently
       available.

       DDI_CB_PCIV_CONFIG_VF

	   The PF driver is being notified of its  VF  configuration  request.
	   The pciv_config_vf_t structure is being passed as cbarg to describe
	   the configuration. The cmd field in pciv_config_vf_t	 indicates  if
	   the VFs are about to or have just been enabled or disabled.

	 cbarg (when action is set to DDI_CB_PCIV_CONFIG_VF)
	    pciv_config_vf_t

	 typedef enum {
	    PCIV_VFCFG_PARAM,	    /* Retrieve VF configuration parameters */
	    PCIV_VF_ENABLE,	    /* Request to enable VFs synchronously */
	    PCIV_VF_DISABLE,	    /* Request to disable VFs synchronously */
	    PCIV_EVT_VFENABLE_PRE,  /* VFs are just about to be enabled */
	    PCIV_EVT_VFENABLE_POST, /* VFs have just been enabled */
	    PCIV_EVT_VFDISABLE_PRE, /* VFs are just about to be disabled */
	    PCIV_EVT_VFDISABLE_POST /* VFs have just been disabled */
	 } pciv_vf_config_cmd_t;

	 typedef struct pciv_config_vf {
	    int			    version;
	    pciv_vf_config_cmd_t    cmd; /* pre/post VF enable/disable */
	    uint16_t		    num_vf; /* number of VFs to be used */
	    uint16_t		    first_vf_offset; /* offset between 1st VF & PF */
	    uint16_t		    vf_stride; /* distance between VFs */
	    boolean_t		    ari_cap; /* ARI capable hierarchy */
	    uint32_t		    page_size; /* system page size */
	 } pciv_config_vf_t;

       The cmd field in the pciv_config_vf_t informs the driver the reason for
       the callback execution. The driver can  return  one  of	the  following
       codes back to the caller.

       DDI_SUCCESS

	   The request was accepted and resources are properly configured.

       DDI_NOTAPPLICABLE

	   The requested configuration is not applicable.

       DDI_REQRESET

	   The requested configuration cannot be applied until device is reset
	   (for (example, the PF hardware cannot dynamically adjust its inter‐
	   nal resources to satisfy the request.)

       DDI_REQREATTACH

	   The	requested  configuration  cannot  be applied unless the driver
	   itself is reattached.

       DDI_CB_COMM_RECV

	   Drivers   are   notified   of   incoming    data    described    by
	   pciv_recv_event_t,  which  is  passed  as the cbarg argument to the
	   callback handler.

	 cbarg (when action is set to DDI_CB_COMM_RECV)
	    pciv_recv_event_t

	 typedef enum {
	    PCIV_EVT_READY = 0x1,   /* peer side has registered the recv cb */
	    PCIV_EVT_NOT_READY,	    /* peer side has unregistered the recv cb */
	    PCIV_EVT_DRV_DATA,	    /* private driver data event */
	    PCIV_EVT_FABRIC	    /* PCIv framework and fabric admin event */
	 } pciv_event_type_t;

	 typedef struct pciv_recv_event {
	    pciv_event_type_t event;	      /* event type */
	    caddr_t	      buf;	      /* buffer address */
	    size_t	      nbyte;	      /* size of buffer */
	    uint32_t	      src_func;	      /* source function */
	    dom_id_t	      src_domain;     /* source domain */
	 } pciv_recv_event_t;

       PCIV_EVT_READY

	   Both local and remote end has registered its event handler. The buf
	   and nbyte fields should be ignored

       PCIV_EVT_NOT_READY

	   Remote  end has not registered its event handler. The buf and nbyte
	   fields should be ignored

       PCIV_EVT_DRV_DATA

	   Data in buf with nbyte size has been received  or  sent.  Data  can
	   only be interpreted by the transmitter and receiver.

       PCIV_EVT_FABRIC

	   Framework  VF  administration  event, used between framework and PF
	   drivers for VF  administration  purposes.  Administration  data  is
	   stored in buf with nbyte size.

       buf, nbyte

	   Incoming  data  is stored in a buffer of address buf with length of
	   nbyte. Not used for certain event types.

       src_func

	   The source function number of the transmission. It is used  by  the
	   PF driver to identify the transmission source virtual function num‐
	   ber. Besides source VF number, it can also be:

	   PCIV_PF     Transmitter is the PF of the receiver.

	   PCIV_FRM    Transmitter is the PCI Express framework rather than  a
		       driver.

       src_domain

	   The	source	domain of the transmission. It is used by PF driver to
	   identify the domain the transmission is from.

RETURN VALUES
       The ddi_cb_register() and ddi_cb_unregister() functions return:

       DDI_SUCCESS     on success

       DDI_EINVAL      An invalid parameter was given when registering a call‐
		       back  handler,  or  an  invalid	handle	was given when
		       unregistering.

       DDI_EALREADY    An attempt was made  to	register  a  callback  handler
		       while a previous registration still exists.

       The cbfunc routine must return:

       DDI_SUCCESS    on success

       DDI_ENOTSUP    The device does not support the operation

       DDI_FAILURE    Implementation specific failure

CONTEXT
       These functions can be called from kernel, non-interrupt context.

EXAMPLES
       Example 1 ddi_cb_register

	 /*
	     * attach(9F) routine.
	     *
	     * Creates soft state, registers callback handler, initializes
	     * hardware, and sets up interrupt handling for the driver.
	     */
	     xx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
	     {
		 xx_state_t		 *statep = NULL;
		 xx_intr_t		 *intrs = NULL;
		 ddi_intr_handle_t	 *hdls;
		 ddi_cb_handle_t	 cb_hdl;
		 int			 instance;
		 int			 type;
		 int			 types;
		 int			 nintrs;
		 int			 nactual;
		 int			 inum;

		 /* Get device instance */
		 instance = ddi_get_instance(dip);

		 switch (cmd) {
		 case DDI_ATTACH:

		      /* Get soft state */
		      if (ddi_soft_state_zalloc(state_list, instance) != 0)
			      return (DDI_FAILURE);
		      statep = ddi_get_soft_state(state_list, instance);
		      ddi_set_driver_private(dip, (caddr_t)statep);
		      statep->dip = dip;

		      /* Initialize hardware */
		      xx_initialize(statep);

		      /* Register callback handler */
		      if (ddi_cb_register(dip, DDI_CB_FLAG_INTR, xx_cbfunc,
			  statep, NULL, &cb_hdl) != 0) {
			      ddi_soft_state_free(state_list, instance);
			      return (DDI_FAILURE);
		      }
		      statep->cb_hdl = cb_hdl;

		      /* Select interrupt type */
		      ddi_intr_get_supported_types(dip, &types);
		      if (types & DDI_INTR_TYPE_MSIX) {
			      type = DDI_INTR_TYPE_MSIX;
		      } else if (types & DDI_INTR_TYPE_MSI) {
			      type = DDI_INTR_TYPE_MSI;
		      } else {
			      type = DDI_INTR_TYPE_FIXED;
		      }
		      statep->type = type;

		      /* Get number of supported interrupts */

		      ddi_intr_get_nintrs(dip, type, &nintrs);

		      /* Allocate interrupt handle array */
		      statep->hdls_size = nintrs * sizeof (ddi_intr_handle_t);
		      hdls = kmem_zalloc(statep->hdls_size, KMEM_SLEEP);

		      /* Allocate interrupt setup array */
		      statep->intrs_size = nintrs * sizeof (xx_intr_t);
		      statep->intrs = kmem_zalloc(statep->intrs_size, KMEM_SLEEP);

		      /* Allocate interrupt vectors */
		      ddi_intr_alloc(dip, hdls, type, 0, nintrs, &nactual, 0);
		      statep->nactual = nactual;

		      /* Configure interrupt handling */
		      xx_setup_interrupts(statep, nactual, statep->intrs);

		      /* Install and enable interrupt handlers */
		      for (inum = 0; inum < nactual; inum++) {
			      ddi_intr_add_handler(&statep->hdls[inum],
				  statep->intrs[inum].inthandler,
				  statep->intrs[inum].arg1,
				  statep->intrs[inum].arg2);
			      ddi_intr_enable(statep->hdls[inum]);
		      }

		      break;

		 case DDI_RESUME:

			 /* Get soft state */
			 statep = ddi_get_soft_state(state_list, instance);
			 if (statep == NULL)
				 return (DDI_FAILURE);

			 /* Resume hardware */
			 xx_resume(statep);

			 break;
		 }

		 return (DDI_SUCESS);
	     }

	     /*
	      * detach(9F) routine.
	      *
	      * Stops the hardware, disables interrupt handling, unregisters
	      * a callback handler, and destroys the soft state for the driver.
	      */
	     xx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
	     {
		 xx_state_t	 *statep = NULL;
		 int		 instance;
		 int		 inum;

		 /* Get device instance */
		 instance = ddi_get_instance(dip);

		 switch (cmd) {
		 case DDI_DETACH:

			 /* Get soft state */
			 statep = ddi_get_soft_state(state_list, instance);
			 if (statep == NULL)
				 return (DDI_FAILURE);

			 /* Stop device */
			 xx_uninitialize(statep);

			 /* Disable and free interrupts */
			 for (inum = 0; inum < statep->nactual; inum++) {
				 ddi_intr_disable(statep->hdls[inum]);
				 ddi_intr_remove_handler(statep->hdls[inum]);
				 ddi_intr_free(statep->hdls[inum]);
			 }

			 /* Unregister callback handler */
			 ddi_cb_unregister(statep->cb_hdl);

			 /* Free interrupt handle array */
			 kmem_free(statep->hdls, statep->hdls_size);

			 /* Free interrupt setup array */
			 kmem_free(statep->intrs, statep->intrs_size);

			 /* Free soft state */
			 ddi_soft_state_free(state_list, instance);

			 break;

		 case DDI_SUSPEND:

			 /* Get soft state */
			 statep = ddi_get_soft_state(state_list, instance);
			 if (statep == NULL)
				 return (DDI_FAILURE);

			 /* Suspend hardware */
			 xx_quiesce(statep);

			 break;
		 }

		 return (DDI_SUCCESS);
	     }

	     /*
	      * (*ddi_cbfunc)() routine.
	      *
	      * Adapt interrupt usage when availability changes.
	      */
	     int
	     xx_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
		 void *arg1, void *arg2)
	     {
		 xx_state_t	 *statep = (xx_state_t *)arg1;
		 int		 count;
		 int		 inum;
		 int		 nactual;

		 switch (cbaction) {
		 case DDI_CB_INTR_ADD:
		 case DDI_CB_INTR_REMOVE:

		      /* Get change in availability */
		      count = (int)(uintptr_t)cbarg;

		      /* Suspend hardware */
		      xx_quiesce(statep);

		      /* Tear down previous interrupt handling */
		      for (inum = 0; inum < statep->nactual; inum++) {
			      ddi_intr_disable(statep->hdls[inum]);
			      ddi_intr_remove_handler(statep->hdls[inum]);
		      }

		      /* Adjust interrupt vector allocations */
		      if (cbaction == DDI_CB_INTR_ADD) {

			      /* Allocate additional interrupt vectors */
			      ddi_intr_alloc(dip, statep->hdls, statep->type,
				  statep->nactual, count, &nactual, 0);

			      /* Update actual count of available interrupts */
			      statep->nactual += nactual;

		      } else {

			      /* Free removed interrupt vectors */
			      for (inum = statep->nactual - count;
				  inum < statep->nactual; inum++) {
				      ddi_intr_free(statep->hdls[inum]);
			      }

			      /* Update actual count of available interrupts */
			      statep->nactual -= count;
		      }

		      /* Configure interrupt handling */
		      xx_setup_interrupts(statep, statep->nactual, statep->intrs);

		      /* Install and enable interrupt handlers */
		      for (inum = 0; inum < statep->nactual; inum++) {
			      ddi_intr_add_handler(&statep->hdls[inum],
				  statep->intrs[inum].inthandler,
				  statep->intrs[inum].arg1,
				  statep->intrs[inum].arg2);
			      ddi_intr_enable(statep->hdls[inum]);
		      }

		      /* Resume hardware */
		      xx_resume(statep);

		      break;

	      default:
		      return (DDI_ENOTSUP);
	      }

	      return (DDI_SUCCESS);
	  }

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

       ┌─────────────────────────────┬─────────────────────────────┐
       │      ATTRIBUTE TYPE	     │	    ATTRIBUTE VALUE	   │
       ├─────────────────────────────┼─────────────────────────────┤
       │Interface Stability	     │Private			   │
       ├─────────────────────────────┼─────────────────────────────┤
       │MT-Level		     │Unsafe			   │
       └─────────────────────────────┴─────────────────────────────┘

SEE ALSO
       attributes(5),	       ddi_intr_alloc(9F),	    ddi_intr_free(9F),
       ddi_intr_set_nreq(9F), pciv_send(9F), pciv_vf_config(9F)

NOTES
       Users of these interfaces that  register	 for  DDI_CB_FLAG_INTR	become
       participants  in interrupt resource management. With that participation
       comes a responsibility to properly adjust interrupt usage. In the  case
       of  a  DDI_CB_INTR_ADD  action, the system guarantees that a driver can
       allocate a total number of interrupt resources up to its new number  of
       available  interrupts.  The  total number of interrupt resources is the
       sum of all resources  allocated	by  the	 function  ddi_intr_alloc(9F),
       minus all previously released by the function ddi_intr_free(9F). In the
       case of a DDI_CB_INTR_REMOVE action, the driver might have more	inter‐
       rupts  allocated	 than are now currently available. It is necessary for
       the driver to release the excess interrupts, or it will have a negative
       impact on the interrupt availability for other drivers in the system.

       A  failure  to  release	interrupts in response to a DDI_CB_INTR_REMOVE
       callback generates the following warning on the system console:

	 WARNING: <driver><instance>: failed to release interrupts for
		 IRM (nintrs = ##, navail=##).

       Participation in interrupt resource management ends when a driver  uses
       the  ddi_cb_unregister()	 function to unregister its callback function.
       The callback function must still operate properly until after the  call
       to  the	ddi_cb_unregister()  function completes. If addinterrupts were
       given to the driver because of its participation, then a final  use  of
       the  callback function occurs to release the additional interrupts. The
       call to the ddi_cb_unregister() function blocks until the final	use of
       the registered callback function is finished.

SunOS 5.10			  13 Jun 2011		   ddi_cb_register(9F)
[top]

List of man pages available for SunOS

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