2016-09-17 20:10:21 +03:00
|
|
|
.\" $NetBSD: pci_msi.9,v 1.14 2016/09/17 17:10:21 jdolecek Exp $
|
2015-04-27 10:03:57 +03:00
|
|
|
.\"
|
|
|
|
.\" Copyright (c) 2015 Internet Initiative Japan Inc.
|
|
|
|
.\" All rights reserved.
|
|
|
|
.\"
|
|
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
|
|
.\" modification, are permitted provided that the following conditions
|
|
|
|
.\" are met:
|
|
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
|
|
.\"
|
|
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
.\"
|
2016-09-17 20:10:21 +03:00
|
|
|
.Dd September 17, 2016
|
2015-04-27 13:37:20 +03:00
|
|
|
.Dt PCI_MSI 9
|
2015-04-27 10:03:57 +03:00
|
|
|
.Os
|
2015-04-27 13:37:20 +03:00
|
|
|
.Sh NAME
|
2015-04-27 10:03:57 +03:00
|
|
|
.Nm pci_msi ,
|
2015-04-27 13:37:20 +03:00
|
|
|
.Nm pci_msix ,
|
2015-04-27 10:03:57 +03:00
|
|
|
.Nm pci_msi_count ,
|
|
|
|
.Nm pci_msi_alloc ,
|
|
|
|
.Nm pci_msi_alloc_exact ,
|
|
|
|
.Nm pci_msix_count ,
|
|
|
|
.Nm pci_msix_alloc ,
|
|
|
|
.Nm pci_msix_alloc_exact ,
|
|
|
|
.Nm pci_msix_alloc_map ,
|
|
|
|
.Nm pci_intx_alloc ,
|
2015-07-21 06:12:50 +03:00
|
|
|
.Nm pci_intr_alloc ,
|
2015-07-21 15:05:02 +03:00
|
|
|
.Nm pci_intr_release ,
|
2015-07-21 06:12:50 +03:00
|
|
|
.Nm pci_intr_type
|
2015-04-27 10:03:57 +03:00
|
|
|
.Nd PCI MSI{,-X} manipulation functions
|
|
|
|
.Sh SYNOPSIS
|
|
|
|
.Ft int
|
2015-08-13 08:01:04 +03:00
|
|
|
.Fn pci_msi_count "pci_chipset_tag_t pc" \
|
|
|
|
"pcitag_t tag"
|
2015-04-27 10:03:57 +03:00
|
|
|
.Ft int
|
2016-07-12 06:39:55 +03:00
|
|
|
.Fn pci_msi_alloc "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihps" "int *count"
|
|
|
|
.Ft int
|
2016-09-15 12:41:33 +03:00
|
|
|
.Fn pci_msi_alloc_exact "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihps" "int count"
|
|
|
|
.Ft int
|
2015-08-13 08:01:04 +03:00
|
|
|
.Fn pci_msix_count "pci_chipset_tag_t pc" \
|
|
|
|
"pcitag_t tag"
|
2015-04-27 10:03:57 +03:00
|
|
|
.Ft int
|
2016-07-12 06:39:55 +03:00
|
|
|
.Fn pci_msix_alloc "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihps" "int *count"
|
|
|
|
.Ft int
|
2016-09-15 12:41:33 +03:00
|
|
|
.Fn pci_msix_alloc_exact "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihps" "int count"
|
|
|
|
.Ft int
|
2016-07-12 06:39:55 +03:00
|
|
|
.Fn pci_msix_alloc_map "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihps" "u_int *table_indexes" "int count"
|
|
|
|
.Ft int
|
2016-07-12 06:39:55 +03:00
|
|
|
.Fn pci_intx_alloc "const struct pci_attach_args *pa" \
|
2015-04-27 10:03:57 +03:00
|
|
|
"pci_intr_handle_t **ihp"
|
2015-07-21 06:12:50 +03:00
|
|
|
.Ft int
|
2016-07-12 06:39:55 +03:00
|
|
|
.Fn pci_intr_alloc "const struct pci_attach_args *pa" \
|
2015-07-21 06:12:50 +03:00
|
|
|
"pci_intr_handle_t **ihp" "int *counts" \
|
|
|
|
"pci_intr_type_t max_type"
|
2015-04-27 10:03:57 +03:00
|
|
|
.Ft void
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_release "pci_chipset_tag_t pc" \
|
|
|
|
"pci_intr_handle_t *pih" "int count"
|
2015-07-21 06:12:50 +03:00
|
|
|
.Ft pci_intr_type_t
|
2016-07-11 09:14:51 +03:00
|
|
|
.Fn pci_intr_type "pci_chipset_tag_t pc" \
|
|
|
|
"pci_intr_handle_t ih"
|
2015-04-27 10:03:57 +03:00
|
|
|
.Sh DESCRIPTION
|
|
|
|
The
|
|
|
|
.Nm
|
|
|
|
functions exist to allow device drivers to use MSI/MSI-X.
|
2015-04-27 13:37:20 +03:00
|
|
|
When the system uses MSI/MSI-X, it must define the
|
|
|
|
.Dv __HAVE_PCI_MSI_MSIX
|
2015-04-27 10:03:57 +03:00
|
|
|
build option.
|
|
|
|
.Pp
|
|
|
|
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.
|
|
|
|
.Pp
|
|
|
|
If a driver wishes to establish an MSI handler for the device,
|
|
|
|
it should pass the
|
|
|
|
.Ft struct pci_attach_args *
|
|
|
|
and
|
2015-04-27 13:37:20 +03:00
|
|
|
.Fa count
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fn pci_msi_alloc
|
|
|
|
or
|
|
|
|
.Fn pci_msi_alloc_exact
|
2015-04-27 13:37:20 +03:00
|
|
|
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
|
2015-04-27 10:03:57 +03:00
|
|
|
.Ft pihs
|
|
|
|
whose size is
|
|
|
|
.Ft count
|
2015-04-27 13:37:20 +03:00
|
|
|
or less.
|
|
|
|
The difference between
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fn pci_msi_alloc
|
|
|
|
and
|
|
|
|
.Fn pci_msi_alloc_exact
|
2015-04-27 13:37:20 +03:00
|
|
|
is whether
|
|
|
|
.Fa count
|
2015-04-27 10:03:57 +03:00
|
|
|
can be decremented or not.
|
|
|
|
.Fn pci_msi_alloc
|
|
|
|
can decrement
|
2015-04-27 13:37:20 +03:00
|
|
|
.Fa count ,
|
|
|
|
and which is similar to
|
|
|
|
.Fx Ap s
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fn pci_alloc_msi .
|
|
|
|
In contrast,
|
|
|
|
.Fn pci_msi_alloc_exact
|
|
|
|
can not decrement
|
|
|
|
.Ft count .
|
|
|
|
.Pp
|
|
|
|
If the driver wishes to refer to the MSI source in an attach or
|
|
|
|
error message, it should use the value returned by
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_string
|
|
|
|
the same as INTx.
|
2015-04-27 10:03:57 +03:00
|
|
|
The buffer passed to
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_string
|
2015-04-27 10:03:57 +03:00
|
|
|
should be at least
|
|
|
|
.Dv PCI_INTRSTR_LEN
|
2015-04-27 13:37:20 +03:00
|
|
|
bytes long.
|
2015-04-27 10:03:57 +03:00
|
|
|
.Pp
|
|
|
|
Subsequently, when the driver is prepared to receive MSIs, it
|
|
|
|
should call
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_establish
|
|
|
|
the same as INTx to actually establish the handler;
|
|
|
|
when the device interrupts,
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fa intrhand
|
|
|
|
will be called with a single argument
|
|
|
|
.Fa intrarg ,
|
|
|
|
and will run at the interrupt priority level
|
|
|
|
.Fa ipl .
|
|
|
|
.Pp
|
|
|
|
The return value of
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_establish
|
2015-04-27 10:03:57 +03:00
|
|
|
may be saved and passed to
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_disestablish
|
|
|
|
to disable the interrupt handler the same as INTx
|
2015-04-27 10:03:57 +03:00
|
|
|
when the driver is no longer interested in MSIs from the device.
|
2015-04-27 13:37:20 +03:00
|
|
|
After that, the driver should also call
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_release
|
|
|
|
to free resources about MSI as well as INTx and MSI-X.
|
2016-08-29 05:48:56 +03:00
|
|
|
If
|
|
|
|
.Fa pih
|
|
|
|
is NULL,
|
|
|
|
.Fn pci_intr_release
|
|
|
|
does nothing.
|
2015-04-27 10:03:57 +03:00
|
|
|
.Pp
|
|
|
|
If a driver wishes to establish an MSI-X handler for the device,
|
2015-04-27 13:37:20 +03:00
|
|
|
it is almost the same as MSI.
|
2015-04-27 10:03:57 +03:00
|
|
|
The only differences is
|
|
|
|
.Fn pci_msix_alloc_map .
|
2015-04-27 13:37:20 +03:00
|
|
|
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:
|
2015-04-27 10:03:57 +03:00
|
|
|
.Bd -literal
|
|
|
|
msix_handler0 => MSI-X table index: 4
|
|
|
|
msix_handler1 => MSI-X table index: 5
|
|
|
|
msix_handler2 => MSI-X table index: 0
|
|
|
|
.Ed
|
2015-04-27 13:37:20 +03:00
|
|
|
the driver should set
|
|
|
|
.Fa table_indexes
|
|
|
|
this way:
|
2015-04-27 10:03:57 +03:00
|
|
|
.Bd -literal
|
|
|
|
table_indexes[0] = 4;
|
|
|
|
table_indexes[1] = 5;
|
|
|
|
table_indexes[2] = 0;
|
|
|
|
.Ed
|
|
|
|
.Pp
|
2015-04-27 13:37:20 +03:00
|
|
|
If the driver wants to fall back to INTx, the driver should use
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fn pci_intx_alloc
|
|
|
|
and
|
2015-05-15 11:39:14 +03:00
|
|
|
.Fn pci_intr_release
|
2015-04-27 10:03:57 +03:00
|
|
|
instead of
|
|
|
|
.Fn pci_intr_map
|
|
|
|
to resolve contradiction of the interrupt handler ownership.
|
2015-04-27 13:37:20 +03:00
|
|
|
I.e.,
|
2015-04-27 10:03:57 +03:00
|
|
|
.Fn pci_intr_map
|
2015-04-27 13:37:20 +03:00
|
|
|
does not have the ownership (the function just calculates value),
|
2015-04-27 10:03:57 +03:00
|
|
|
in contrast,
|
|
|
|
.Fn pci_msi_alloc
|
|
|
|
and
|
|
|
|
.Fn pci_msix_alloc
|
2015-04-27 13:37:20 +03:00
|
|
|
have (the functions allocate memory for interrupt handlers).
|
2015-07-21 06:12:50 +03:00
|
|
|
.Pp
|
|
|
|
.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
|
2015-07-21 15:05:02 +03:00
|
|
|
must be
|
|
|
|
.Dv PCI_INTR_TYPE_MSIX ,
|
|
|
|
.Dv PCI_INTR_TYPE_MSI ,
|
|
|
|
or
|
|
|
|
.Dv PCI_INTR_TYPE_INTX .
|
2015-07-21 06:12:50 +03:00
|
|
|
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.
|
2015-07-21 15:05:02 +03:00
|
|
|
I.e., if the driver wants to allocate interrupts in the following way:
|
2015-07-21 06:12:50 +03:00
|
|
|
.Bd -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:
|
|
|
|
.Bd -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
|
2015-07-21 15:05:02 +03:00
|
|
|
If the driver wants to allocate interrupts in the following way:
|
2015-07-21 06:12:50 +03:00
|
|
|
.Bd -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:
|
|
|
|
.Bd -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
|
2015-07-21 15:05:02 +03:00
|
|
|
If the driver wants to allocate interrupts in the following way:
|
2015-07-21 06:12:50 +03:00
|
|
|
.Bd -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:
|
|
|
|
.Bd -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
|
2015-07-21 15:05:02 +03:00
|
|
|
If the driver wants to allocate interrupts in the following way:
|
2015-07-21 06:12:50 +03:00
|
|
|
.Bd -literal
|
|
|
|
1 MSI
|
|
|
|
INTx (if MSI allocation failed)
|
|
|
|
.Ed
|
|
|
|
that is, general usage, the driver should call simply
|
|
|
|
.Fn pci_intr_alloc
|
|
|
|
in the following way:
|
|
|
|
.Bd -literal
|
|
|
|
error = pci_intr_alloc(pa, ihps, NULL, 0);
|
|
|
|
.Ed
|
|
|
|
.Fa max_type
|
|
|
|
is ignored in this case.
|
|
|
|
.Fn pci_intr_alloc
|
2015-07-21 15:05:02 +03:00
|
|
|
returns zero on any allocation function success, and non-zero on
|
|
|
|
all allocation function failures.
|
|
|
|
On success,
|
2015-07-21 06:12:50 +03:00
|
|
|
.Fa counts
|
|
|
|
is overwritten by a really allocated count.
|
2015-07-21 15:05:02 +03:00
|
|
|
I.e., if 5 MSI-X is allocated,
|
2015-07-21 06:12:50 +03:00
|
|
|
.Fa counts
|
|
|
|
is
|
|
|
|
.Bd -literal
|
|
|
|
counts[PCI_INTR_TYPE_MSIX] == 5
|
|
|
|
counts[PCI_INTR_TYPE_MSI] == 0
|
|
|
|
counts[PCI_INTR_TYPE_INTX] == 0
|
|
|
|
.Ed
|
|
|
|
on return.
|
|
|
|
.Pp
|
2015-07-24 10:40:58 +03:00
|
|
|
.Fn pci_intr_type
|
2015-07-21 15:05:02 +03:00
|
|
|
returns the interrupt type of
|
2015-07-21 06:12:50 +03:00
|
|
|
.Fa ih .
|
|
|
|
The return value is
|
|
|
|
.Dv PCI_INTR_TYPE_MSIX
|
|
|
|
for MSI-X,
|
|
|
|
.Dv PCI_INTR_TYPE_MSI
|
2015-07-21 15:05:02 +03:00
|
|
|
for MSI, and
|
2015-07-21 06:12:50 +03:00
|
|
|
.Dv PCI_INTR_TYPE_INTX
|
|
|
|
for others.
|
2015-05-15 11:39:14 +03:00
|
|
|
.Sh SEE ALSO
|
|
|
|
.Xr pci_intr 9
|
2016-09-17 20:10:21 +03:00
|
|
|
.Sh HISTORY
|
|
|
|
.Nm
|
|
|
|
support first appeared in
|
|
|
|
.Nx 8.0 .
|
|
|
|
Support is present on
|
|
|
|
.Em i386
|
|
|
|
and
|
|
|
|
.Em amd64
|
|
|
|
architectures.
|
|
|
|
.Sh AUTHORS
|
|
|
|
The
|
|
|
|
.Nm
|
|
|
|
interfaces were designed and implemented by
|
|
|
|
.An Kengo Nakahara .
|