| PCI_MSI(9) | Kernel Developer's Manual | PCI_MSI(9) | 
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_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);
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
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)
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);
hardware max number MSI-X 1 MSI (if MSI-X allocation failed)
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);
3 MSI INTx (if MSI allocation failed)
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);
1 MSI-X 1 MSI INTx (if MSI/MSI-X allocation failed)
pci_intr_alloc() in the following way:
error = pci_intr_alloc(pa, ihps, NULL, 0);
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
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.
pci_msi support first appeared in
  NetBSD 8.0. Support is present on
  i386, amd64 and aarch64
  architectures.
pci_msi interfaces were designed and implemented by
  Kengo Nakahara
  <knakahara@NetBSD.org>.
| January 12, 2021 | NetBSD 10.0 |