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