xref: /netbsd-src/share/man/man9/pci_msi.9 (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1.\" $NetBSD: pci_msi.9,v 1.17 2018/11/27 20:13:43 jdolecek Exp $
2.\"
3.\" Copyright (c) 2015 Internet Initiative Japan Inc.
4.\" All rights reserved.
5.\"
6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions
8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright
10.\"    notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\"    notice, this list of conditions and the following disclaimer in the
13.\"    documentation and/or other materials provided with the distribution.
14.\"
15.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25.\" POSSIBILITY OF SUCH DAMAGE.
26.\"
27.Dd November 27, 2018
28.Dt PCI_MSI 9
29.Os
30.Sh NAME
31.Nm pci_msi ,
32.Nm pci_msix ,
33.Nm pci_msi_count ,
34.Nm pci_msi_alloc ,
35.Nm pci_msi_alloc_exact ,
36.Nm pci_msix_count ,
37.Nm pci_msix_alloc ,
38.Nm pci_msix_alloc_exact ,
39.Nm pci_msix_alloc_map ,
40.Nm pci_intx_alloc ,
41.Nm pci_intr_alloc ,
42.Nm pci_intr_release ,
43.Nm pci_intr_type
44.Nd PCI MSI{,-X} manipulation functions
45.Sh SYNOPSIS
46.Ft int
47.Fn pci_msi_count "pci_chipset_tag_t pc" \
48"pcitag_t tag"
49.Ft int
50.Fn pci_msi_alloc  "const struct pci_attach_args *pa" \
51"pci_intr_handle_t **ihps" "int *count"
52.Ft int
53.Fn pci_msi_alloc_exact "const struct pci_attach_args *pa" \
54"pci_intr_handle_t **ihps" "int count"
55.Ft int
56.Fn pci_msix_count "pci_chipset_tag_t pc" \
57"pcitag_t tag"
58.Ft int
59.Fn pci_msix_alloc  "const struct pci_attach_args *pa" \
60"pci_intr_handle_t **ihps" "int *count"
61.Ft int
62.Fn pci_msix_alloc_exact "const struct pci_attach_args *pa" \
63"pci_intr_handle_t **ihps" "int count"
64.Ft int
65.Fn pci_msix_alloc_map "const struct pci_attach_args *pa" \
66"pci_intr_handle_t **ihps" "u_int *table_indexes" "int count"
67.Ft int
68.Fn pci_intx_alloc  "const struct pci_attach_args *pa" \
69"pci_intr_handle_t **ihp"
70.Ft int
71.Fn pci_intr_alloc  "const struct pci_attach_args *pa" \
72"pci_intr_handle_t **ihp" "int *counts" \
73"pci_intr_type_t max_type"
74.Ft void
75.Fn pci_intr_release "pci_chipset_tag_t pc" \
76"pci_intr_handle_t *pih" "int count"
77.Ft pci_intr_type_t
78.Fn pci_intr_type "pci_chipset_tag_t pc" \
79"pci_intr_handle_t ih"
80.Sh DESCRIPTION
81The
82.Nm
83functions exist to allow device drivers to use MSI/MSI-X.
84When the system uses MSI/MSI-X, it must define the
85.Dv __HAVE_PCI_MSI_MSIX
86build option.
87.Pp
88Each driver has an
89.Fn attach
90function which has a bus-specific
91.Ft attach_args
92structure.
93Each driver for a PCI device is passed a pointer to an object of type
94.Ft struct pci_attach_args
95which contains, among other things, information about the location
96of the device in the PCI bus topology sufficient to allow interrupts
97from the device to be handled.
98.Pp
99If a driver wishes to establish an MSI handler for the device,
100it should pass the
101.Ft struct pci_attach_args *
102and
103.Fa count
104.Fn pci_msi_alloc
105or
106.Fn pci_msi_alloc_exact
107functions, which return zero on success, and nonzero on failure.
108When the functions are successful, they return the pointer to the
109allocated handle array in
110.Ft pihs
111whose size is
112.Ft count
113or less.
114The difference between
115.Fn pci_msi_alloc
116and
117.Fn pci_msi_alloc_exact
118is whether
119.Fa count
120can be decremented or not.
121.Fn pci_msi_alloc
122can decrement
123.Fa count ,
124and which is similar to
125.Fx Ap s
126.Fn pci_alloc_msi .
127In contrast,
128.Fn pci_msi_alloc_exact
129can not decrement
130.Ft count .
131.Pp
132If the driver wishes to refer to the MSI source in an attach or
133error message, it should use the value returned by
134.Fn pci_intr_string
135the same as INTx.
136The buffer passed to
137.Fn pci_intr_string
138should be at least
139.Dv PCI_INTRSTR_LEN
140bytes long.
141.Pp
142Subsequently, when the driver is prepared to receive MSIs, it
143should call
144.Fn pci_intr_establish
145the same as INTx to actually establish the handler;
146when the device interrupts,
147.Fa intrhand
148will be called with a single argument
149.Fa intrarg ,
150and will run at the interrupt priority level
151.Fa ipl .
152.Pp
153The return value of
154.Fn pci_intr_establish
155may be saved and passed to
156.Fn pci_intr_disestablish
157to disable the interrupt handler the same as INTx
158when the driver is no longer interested in MSIs from the device.
159After that, the driver should also call
160.Fn pci_intr_release
161to free resources about MSI as well as INTx and MSI-X.
162If
163.Fa pih
164is NULL,
165.Fn pci_intr_release
166does nothing.
167.Pp
168If a driver wishes to establish an MSI-X handler for the device,
169it is almost the same as MSI.
170The only differences is
171.Fn pci_msix_alloc_map .
172This function can assign separate handlers for each MSI-X table
173entry.
174I.e., if the driver wants to assign the handlers in the following way:
175.Bd -literal
176	msix_handler0 => MSI-X table index: 4
177	msix_handler1 => MSI-X table index: 5
178	msix_handler2 => MSI-X table index: 0
179.Ed
180the driver should set
181.Fa table_indexes
182this way:
183.Bd -literal
184	table_indexes[0] = 4;
185	table_indexes[1] = 5;
186	table_indexes[2] = 0;
187.Ed
188.Pp
189If the driver wants to fall back to INTx, the driver should use
190.Fn pci_intx_alloc
191and
192.Fn pci_intr_release
193instead of
194.Fn pci_intr_map
195to resolve contradiction of the interrupt handler ownership.
196I.e.,
197.Fn pci_intr_map
198does not have the ownership (the function just calculates value),
199in contrast,
200.Fn pci_msi_alloc
201and
202.Fn pci_msix_alloc
203have (the functions allocate memory for interrupt handlers).
204.Pp
205.Fn pci_intr_alloc
206is wrapper function which select and automatically fallback
207allocation functions according to the argument
208.Fa counts .
209The elements of
210.Fa counts
211array means each required interrupt count for INTx, MSI, and MSI-X.
212The index count of
213.Fa counts
214must be
215.Dv PCI_INTR_TYPE_SIZE .
216.Fa max_type
217must be
218.Dv PCI_INTR_TYPE_MSIX ,
219.Dv PCI_INTR_TYPE_MSI ,
220or
221.Dv PCI_INTR_TYPE_INTX .
222The parameter does not mean array index counts of
223.Fa counts .
224The parameter means the interrupt type which
225.Fn pci_intr_alloc
226tries to allocate first.
227I.e., if the driver wants to allocate interrupts in the following way:
228.Bd -literal
229	5 MSI-X
230	1 MSI (if MSI-X allocation failed)
231	INTx (if MSI allocation failed either)
232.Ed
233the driver should call
234.Fn pci_intr_alloc
235in the following way:
236.Bd -literal
237	int counts[PCI_INTR_TYPE_SIZE];
238	counts[PCI_INTR_TYPE_MSIX] = 5;
239	counts[PCI_INTR_TYPE_MSI] = 1;
240	counts[PCI_INTR_TYPE_INTX] = 1;
241	error = pci_intr_alloc(pa, ihps, counts,
242			       PCI_INTR_TYPE_MSIX);
243.Ed
244If the driver wants to allocate interrupts in the following way:
245.Bd -literal
246	hardware max number MSI-X
247	1 MSI (if MSI-X allocation failed)
248.Ed
249that is, the driver does not use INTx, the driver should call
250.Fn pci_intr_alloc
251in the following way:
252.Bd -literal
253	int counts[PCI_INTR_TYPE_SIZE];
254	counts[PCI_INTR_TYPE_MSIX] = -1; /* -1 means max */
255	counts[PCI_INTR_TYPE_MSI] = 1;
256	counts[PCI_INTR_TYPE_INTX] = 0; /* 0 means not use */
257	error = pci_intr_alloc(pa, ihps, counts,
258			       PCI_INTR_TYPE_MSIX);
259.Ed
260If the driver wants to allocate interrupts in the following way:
261.Bd -literal
262	3 MSI
263	INTx (if MSI allocation failed)
264.Ed
265that is, the driver does not use MSI-X, the driver should call
266.Fn pci_intr_alloc
267in the following way:
268.Bd -literal
269	int counts[PCI_INTR_TYPE_SIZE];
270	counts[PCI_INTR_TYPE_MSIX] = 0; /* 0 means not use */
271	counts[PCI_INTR_TYPE_MSI] = 3;
272	counts[PCI_INTR_TYPE_INTX] = 1;
273	error = pci_intr_alloc(pa, ihps, counts,
274			       PCI_INTR_TYPE_MSI);
275.Ed
276If the driver wants to allocate interrupts in the following way:
277.Bd -literal
278	1 MSI-X
279	1 MSI
280	INTx (if MSI/MSI-X allocation failed)
281.Ed
282that is, general usage, the driver should call simply
283.Fn pci_intr_alloc
284in the following way:
285.Bd -literal
286	error = pci_intr_alloc(pa, ihps, NULL, 0);
287.Ed
288.Fa max_type
289is ignored in this case.
290.Fn pci_intr_alloc
291returns zero on any allocation function success, and non-zero on
292all allocation function failures.
293On success,
294.Fa counts
295is overwritten by a really allocated count.
296I.e., if 5 MSI-X is allocated,
297.Fa counts
298is
299.Bd -literal
300	counts[PCI_INTR_TYPE_MSIX] == 5
301	counts[PCI_INTR_TYPE_MSI] == 0
302	counts[PCI_INTR_TYPE_INTX] == 0
303.Ed
304on return.
305.Pp
306.Fn pci_intr_type
307returns the interrupt type of
308.Fa ih .
309The return value is
310.Dv PCI_INTR_TYPE_MSIX
311for MSI-X,
312.Dv PCI_INTR_TYPE_MSI
313for MSI, and
314.Dv PCI_INTR_TYPE_INTX
315for others.
316.Sh SEE ALSO
317.Xr pci_intr 9
318.Sh HISTORY
319.Nm
320support first appeared in
321.Nx 8.0 .
322Support is present on
323.Em i386 ,
324.Em amd64
325and
326.Em aarch64
327architectures.
328.Sh AUTHORS
329The
330.Nm
331interfaces were designed and implemented by
332.An Kengo Nakahara
333.Aq Mt knakahara@NetBSD.org .
334