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.
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
INTx (if MSI 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 and
amd64 architectures.
AUTHORS
The
pci_msi interfaces were designed and implemented by
Kengo Nakahara
<
knakahara@NetBSD.org>.