p Each driver has an .Fn attach function which has a bus-specific .Ft attach_args structure. Each driver for a PCI device is passed a pointer to an object of type .Ft 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.
p .Fn pci_msi_count returns the max number of the device's MSI. If the device can not use MSI, .Fn pci_msi_count returns zero. .Fn pci_msix_count works in the same manner for MSI-X.
p If a driver wishes to establish an MSI handler for the device, it should pass the .Ft struct pci_attach_args * and .Fa count .Fn pci_msi_alloc or .Fn 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 .Ft pihs whose size is .Ft count or less. The difference between .Fn pci_msi_alloc and .Fn pci_msi_alloc_exact is whether .Fa count can be decremented or not. .Fn pci_msi_alloc can decrement .Fa count , and which is similar to .Fx Ap s .Fn pci_alloc_msi . In contrast, .Fn pci_msi_alloc_exact can not decrement .Ft count .
p If the driver wishes to refer to the MSI source in an attach or error message, it should use the value returned by .Fn pci_intr_string the same as INTx. The buffer passed to .Fn pci_intr_string should be at least .Dv PCI_INTRSTR_LEN bytes long.
p Subsequently, when the driver is prepared to receive MSIs, it should call .Fn pci_intr_establish the same as INTx to actually establish the handler; when the device interrupts, .Fa intrhand will be called with a single argument .Fa intrarg , and will run at the interrupt priority level .Fa ipl .
p The return value of .Fn pci_intr_establish may be saved and passed to .Fn 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 .Fn pci_intr_release to free resources about MSI as well as INTx and MSI-X. If .Fa pih is NULL, .Fn pci_intr_release does nothing.
p If a driver wishes to establish an MSI-X handler for the device, it is almost the same as MSI. The only differences is .Fn 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: d -literal msix_handler0 => MSI-X table index: 4 msix_handler1 => MSI-X table index: 5 msix_handler2 => MSI-X table index: 0 .Ed the driver should set .Fa table_indexes this way: d -literal table_indexes[0] = 4; table_indexes[1] = 5; table_indexes[2] = 0; .Ed
p If the driver wants to fall back to INTx, the driver should use .Fn pci_intx_alloc and .Fn pci_intr_release instead of .Fn pci_intr_map to resolve contradiction of the interrupt handler ownership. I.e., .Fn pci_intr_map does not have the ownership (the function just calculates value), in contrast, .Fn pci_msi_alloc and .Fn pci_msix_alloc have (the functions allocate memory for interrupt handlers).
p .Fn pci_intr_alloc is wrapper function which select and automatically fallback allocation functions according to the argument .Fa counts . The elements of .Fa counts array means each required interrupt count for INTx, MSI, and MSI-X. The index count of .Fa counts must be .Dv PCI_INTR_TYPE_SIZE . .Fa max_type must be .Dv PCI_INTR_TYPE_MSIX , .Dv PCI_INTR_TYPE_MSI , or .Dv PCI_INTR_TYPE_INTX . The parameter does not mean array index counts of .Fa counts . The parameter means the interrupt type which .Fn pci_intr_alloc tries to allocate first. I.e., if the driver wants to allocate interrupts in the following way: d -literal 5 MSI-X 1 MSI (if MSI-X allocation failed) INTx (if MSI allocation failed either) .Ed the driver should call .Fn pci_intr_alloc in the following way: d -literal 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); .Ed If the driver wants to allocate interrupts in the following way: d -literal hardware max number MSI-X 1 MSI (if MSI-X allocation failed) .Ed that is, the driver does not use INTx, the driver should call .Fn pci_intr_alloc in the following way: d -literal 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); .Ed If the driver wants to allocate interrupts in the following way: d -literal 3 MSI INTx (if MSI allocation failed) .Ed that is, the driver does not use MSI-X, the driver should call .Fn pci_intr_alloc in the following way: d -literal 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); .Ed If the driver wants to allocate interrupts in the following way: d -literal 1 MSI-X 1 MSI INTx (if MSI/MSI-X allocation failed) .Ed that is, general usage, the driver should call simply .Fn pci_intr_alloc in the following way: d -literal error = pci_intr_alloc(pa, ihps, NULL, 0); .Ed .Fa max_type is ignored in this case. .Fn pci_intr_alloc returns zero on any allocation function success, and non-zero on all allocation function failures. On success, .Fa counts is overwritten by a really allocated count. I.e., if 5 MSI-X is allocated, .Fa counts is d -literal counts[PCI_INTR_TYPE_MSIX] == 5 counts[PCI_INTR_TYPE_MSI] == 0 counts[PCI_INTR_TYPE_INTX] == 0 .Ed on return.
p .Fn pci_intr_type returns the interrupt type of .Fa ih . The return value is .Dv PCI_INTR_TYPE_MSIX for MSI-X, .Dv PCI_INTR_TYPE_MSI for MSI, and .Dv PCI_INTR_TYPE_INTX for others. .Sh SEE ALSO .Xr pci_intr 9 .Sh HISTORY .Nm support first appeared in .Nx 8.0 . Support is present on .Em i386 , .Em amd64 and .Em aarch64 architectures. .Sh AUTHORS The .Nm interfaces were designed and implemented by .An Kengo Nakahara .Aq Mt knakahara (at] NetBSD.org .