Updated: 2022/Sep/29

Please read Privacy Policy. It's for your privacy.


PCI_MSI(9)                 Kernel Developer's Manual                PCI_MSI(9)

NAME
     pci_msi, pci_msix, pci_msi_count, pci_msi_alloc, pci_msi_alloc_exact,
     pci_msix_count, pci_msix_alloc, pci_msix_alloc_exact, pci_msix_alloc_map,
     pci_intx_alloc, pci_intr_alloc, pci_intr_release, pci_intr_type - PCI
     MSI{,-X} manipulation functions

SYNOPSIS
     int
     pci_msi_count(pci_chipset_tag_t pc, pcitag_t tag);

     int
     pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
         int *count);

     int
     pci_msi_alloc_exact(const struct pci_attach_args *pa,
         pci_intr_handle_t **ihps, int count);

     int
     pci_msix_count(pci_chipset_tag_t pc, pcitag_t tag);

     int
     pci_msix_alloc(const struct pci_attach_args *pa,
         pci_intr_handle_t **ihps, int *count);

     int
     pci_msix_alloc_exact(const struct pci_attach_args *pa,
         pci_intr_handle_t **ihps, int count);

     int
     pci_msix_alloc_map(const struct pci_attach_args *pa,
         pci_intr_handle_t **ihps, u_int *table_indexes, int count);

     int
     pci_intx_alloc(const struct pci_attach_args *pa,
         pci_intr_handle_t **ihp);

     int
     pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihp,
         int *counts, pci_intr_type_t max_type);

     void
     pci_intr_release(pci_chipset_tag_t pc, pci_intr_handle_t *pih,
         int count);

     pci_intr_type_t
     pci_intr_type(pci_chipset_tag_t pc, pci_intr_handle_t ih);

DESCRIPTION
     The pci_msi functions exist to allow device drivers to use MSI/MSI-X.
     When the system uses MSI/MSI-X, it must define the __HAVE_PCI_MSI_MSIX
     build option.

     Each driver has an attach() function which has a bus-specific attach_args
     structure.  Each driver for a PCI device is passed a pointer to an object
     of type struct pci_attach_args which contains, among other things,
     information about the location of the device in the PCI bus topology
     sufficient to allow interrupts from the device to be handled.

     pci_msi_count() returns the max number of the device's MSI.  If the
     device can not use MSI, pci_msi_count() returns zero.  pci_msix_count()
     works in the same manner for MSI-X.

     If a driver wishes to establish an MSI handler for the device, it should
     pass the struct pci_attach_args * and count pci_msi_alloc() or
     pci_msi_alloc_exact() functions, which return zero on success, and
     nonzero on failure.  When the functions are successful, they return the
     pointer to the allocated handle array in pihs whose size is count or
     less.  The difference between pci_msi_alloc() and pci_msi_alloc_exact()
     is whether count can be decremented or not.  pci_msi_alloc() can
     decrement count, and which is similar to FreeBSD's pci_alloc_msi().  In
     contrast, pci_msi_alloc_exact() can not decrement count.

     If the driver wishes to refer to the MSI source in an attach or error
     message, it should use the value returned by pci_intr_string() the same
     as INTx.  The buffer passed to pci_intr_string() should be at least
     PCI_INTRSTR_LEN bytes long.

     Subsequently, when the driver is prepared to receive MSIs, it should call
     pci_intr_establish() the same as INTx to actually establish the handler;
     when the device interrupts, intrhand will be called with a single
     argument intrarg, and will run at the interrupt priority level ipl.

     The return value of pci_intr_establish() may be saved and passed to
     pci_intr_disestablish() to disable the interrupt handler the same as INTx
     when the driver is no longer interested in MSIs from the device.  After
     that, the driver should also call pci_intr_release() to free resources
     about MSI as well as INTx and MSI-X.  If pih is NULL, pci_intr_release()
     does nothing.

     If a driver wishes to establish an MSI-X handler for the device, it is
     almost the same as MSI.  The only differences is pci_msix_alloc_map().
     This function can assign separate handlers for each MSI-X table entry.
     I.e., if the driver wants to assign the handlers in the following way:

             msix_handler0 => MSI-X table index: 4
             msix_handler1 => MSI-X table index: 5
             msix_handler2 => MSI-X table index: 0
     the driver should set table_indexes this way:

             table_indexes[0] = 4;
             table_indexes[1] = 5;
             table_indexes[2] = 0;

     If the driver wants to fall back to INTx, the driver should use
     pci_intx_alloc() and pci_intr_release() instead of pci_intr_map() to
     resolve contradiction of the interrupt handler ownership.  I.e.,
     pci_intr_map() does not have the ownership (the function just calculates
     value), in contrast, pci_msi_alloc() and pci_msix_alloc() have (the
     functions allocate memory for interrupt handlers).

     pci_intr_alloc() is wrapper function which select and automatically
     fallback allocation functions according to the argument counts.  The
     elements of counts array means each required interrupt count for INTx,
     MSI, and MSI-X.  The index count of counts must be PCI_INTR_TYPE_SIZE.
     max_type must be PCI_INTR_TYPE_MSIX, PCI_INTR_TYPE_MSI, or
     PCI_INTR_TYPE_INTX.  The parameter does not mean array index counts of
     counts.  The parameter means the interrupt type which pci_intr_alloc()
     tries to allocate first.  I.e., if the driver wants to allocate
     interrupts in the following way:

             5 MSI-X
             1 MSI (if MSI-X allocation failed)
             INTx (if MSI allocation failed either)
     the driver should call pci_intr_alloc() in the following way:

             int counts[PCI_INTR_TYPE_SIZE];
             counts[PCI_INTR_TYPE_MSIX] = 5;
             counts[PCI_INTR_TYPE_MSI] = 1;
             counts[PCI_INTR_TYPE_INTX] = 1;
             error = pci_intr_alloc(pa, ihps, counts,
                                    PCI_INTR_TYPE_MSIX);
     If the driver wants to allocate interrupts in the following way:

             hardware max number MSI-X
             1 MSI (if MSI-X allocation failed)
     that is, the driver does not use INTx, the driver should call
     pci_intr_alloc() in the following way:

             int counts[PCI_INTR_TYPE_SIZE];
             counts[PCI_INTR_TYPE_MSIX] = -1; /* -1 means max */
             counts[PCI_INTR_TYPE_MSI] = 1;
             counts[PCI_INTR_TYPE_INTX] = 0; /* 0 means not use */
             error = pci_intr_alloc(pa, ihps, counts,
                                    PCI_INTR_TYPE_MSIX);
     If the driver wants to allocate interrupts in the following way:

             3 MSI
             INTx (if MSI allocation failed)
     that is, the driver does not use MSI-X, the driver should call
     pci_intr_alloc() in the following way:

             int counts[PCI_INTR_TYPE_SIZE];
             counts[PCI_INTR_TYPE_MSIX] = 0; /* 0 means not use */
             counts[PCI_INTR_TYPE_MSI] = 3;
             counts[PCI_INTR_TYPE_INTX] = 1;
             error = pci_intr_alloc(pa, ihps, counts,
                                    PCI_INTR_TYPE_MSI);
     If the driver wants to allocate interrupts in the following way:

             1 MSI-X
             1 MSI
             INTx (if MSI/MSI-X allocation failed)
     that is, general usage, the driver should call simply pci_intr_alloc() in
     the following way:

             error = pci_intr_alloc(pa, ihps, NULL, 0);
     max_type is ignored in this case.  pci_intr_alloc() returns zero on any
     allocation function success, and non-zero on all allocation function
     failures.  On success, counts is overwritten by a really allocated count.
     I.e., if 5 MSI-X is allocated, counts is

             counts[PCI_INTR_TYPE_MSIX] == 5
             counts[PCI_INTR_TYPE_MSI] == 0
             counts[PCI_INTR_TYPE_INTX] == 0
     on return.

     pci_intr_type() returns the interrupt type of ih.  The return value is
     PCI_INTR_TYPE_MSIX for MSI-X, PCI_INTR_TYPE_MSI for MSI, and
     PCI_INTR_TYPE_INTX for others.

SEE ALSO
     pci_intr(9)

HISTORY
     pci_msi support first appeared in NetBSD 8.0.  Support is present on
     i386, amd64 and aarch64 architectures.

AUTHORS
     The pci_msi interfaces were designed and implemented by Kengo Nakahara
     <knakahara@NetBSD.org>.

NetBSD 10.99                   January 12, 2021                   NetBSD 10.99