1.\" $NetBSD: pci_msi.9,v 1.18 2021/01/12 05:08:50 knakahara 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 January 12, 2021 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 99.Fn pci_msi_count 100returns the max number of the device's MSI. 101If the device can not use MSI, 102.Fn pci_msi_count 103returns zero. 104.Fn pci_msix_count 105works in the same manner for MSI-X. 106.Pp 107If a driver wishes to establish an MSI handler for the device, 108it should pass the 109.Ft struct pci_attach_args * 110and 111.Fa count 112.Fn pci_msi_alloc 113or 114.Fn pci_msi_alloc_exact 115functions, which return zero on success, and nonzero on failure. 116When the functions are successful, they return the pointer to the 117allocated handle array in 118.Ft pihs 119whose size is 120.Ft count 121or less. 122The difference between 123.Fn pci_msi_alloc 124and 125.Fn pci_msi_alloc_exact 126is whether 127.Fa count 128can be decremented or not. 129.Fn pci_msi_alloc 130can decrement 131.Fa count , 132and which is similar to 133.Fx Ap s 134.Fn pci_alloc_msi . 135In contrast, 136.Fn pci_msi_alloc_exact 137can not decrement 138.Ft count . 139.Pp 140If the driver wishes to refer to the MSI source in an attach or 141error message, it should use the value returned by 142.Fn pci_intr_string 143the same as INTx. 144The buffer passed to 145.Fn pci_intr_string 146should be at least 147.Dv PCI_INTRSTR_LEN 148bytes long. 149.Pp 150Subsequently, when the driver is prepared to receive MSIs, it 151should call 152.Fn pci_intr_establish 153the same as INTx to actually establish the handler; 154when the device interrupts, 155.Fa intrhand 156will be called with a single argument 157.Fa intrarg , 158and will run at the interrupt priority level 159.Fa ipl . 160.Pp 161The return value of 162.Fn pci_intr_establish 163may be saved and passed to 164.Fn pci_intr_disestablish 165to disable the interrupt handler the same as INTx 166when the driver is no longer interested in MSIs from the device. 167After that, the driver should also call 168.Fn pci_intr_release 169to free resources about MSI as well as INTx and MSI-X. 170If 171.Fa pih 172is NULL, 173.Fn pci_intr_release 174does nothing. 175.Pp 176If a driver wishes to establish an MSI-X handler for the device, 177it is almost the same as MSI. 178The only differences is 179.Fn pci_msix_alloc_map . 180This function can assign separate handlers for each MSI-X table 181entry. 182I.e., if the driver wants to assign the handlers in the following way: 183.Bd -literal 184 msix_handler0 => MSI-X table index: 4 185 msix_handler1 => MSI-X table index: 5 186 msix_handler2 => MSI-X table index: 0 187.Ed 188the driver should set 189.Fa table_indexes 190this way: 191.Bd -literal 192 table_indexes[0] = 4; 193 table_indexes[1] = 5; 194 table_indexes[2] = 0; 195.Ed 196.Pp 197If the driver wants to fall back to INTx, the driver should use 198.Fn pci_intx_alloc 199and 200.Fn pci_intr_release 201instead of 202.Fn pci_intr_map 203to resolve contradiction of the interrupt handler ownership. 204I.e., 205.Fn pci_intr_map 206does not have the ownership (the function just calculates value), 207in contrast, 208.Fn pci_msi_alloc 209and 210.Fn pci_msix_alloc 211have (the functions allocate memory for interrupt handlers). 212.Pp 213.Fn pci_intr_alloc 214is wrapper function which select and automatically fallback 215allocation functions according to the argument 216.Fa counts . 217The elements of 218.Fa counts 219array means each required interrupt count for INTx, MSI, and MSI-X. 220The index count of 221.Fa counts 222must be 223.Dv PCI_INTR_TYPE_SIZE . 224.Fa max_type 225must be 226.Dv PCI_INTR_TYPE_MSIX , 227.Dv PCI_INTR_TYPE_MSI , 228or 229.Dv PCI_INTR_TYPE_INTX . 230The parameter does not mean array index counts of 231.Fa counts . 232The parameter means the interrupt type which 233.Fn pci_intr_alloc 234tries to allocate first. 235I.e., if the driver wants to allocate interrupts in the following way: 236.Bd -literal 237 5 MSI-X 238 1 MSI (if MSI-X allocation failed) 239 INTx (if MSI allocation failed either) 240.Ed 241the driver should call 242.Fn pci_intr_alloc 243in the following way: 244.Bd -literal 245 int counts[PCI_INTR_TYPE_SIZE]; 246 counts[PCI_INTR_TYPE_MSIX] = 5; 247 counts[PCI_INTR_TYPE_MSI] = 1; 248 counts[PCI_INTR_TYPE_INTX] = 1; 249 error = pci_intr_alloc(pa, ihps, counts, 250 PCI_INTR_TYPE_MSIX); 251.Ed 252If the driver wants to allocate interrupts in the following way: 253.Bd -literal 254 hardware max number MSI-X 255 1 MSI (if MSI-X allocation failed) 256.Ed 257that is, the driver does not use INTx, the driver should call 258.Fn pci_intr_alloc 259in the following way: 260.Bd -literal 261 int counts[PCI_INTR_TYPE_SIZE]; 262 counts[PCI_INTR_TYPE_MSIX] = -1; /* -1 means max */ 263 counts[PCI_INTR_TYPE_MSI] = 1; 264 counts[PCI_INTR_TYPE_INTX] = 0; /* 0 means not use */ 265 error = pci_intr_alloc(pa, ihps, counts, 266 PCI_INTR_TYPE_MSIX); 267.Ed 268If the driver wants to allocate interrupts in the following way: 269.Bd -literal 270 3 MSI 271 INTx (if MSI allocation failed) 272.Ed 273that is, the driver does not use MSI-X, the driver should call 274.Fn pci_intr_alloc 275in the following way: 276.Bd -literal 277 int counts[PCI_INTR_TYPE_SIZE]; 278 counts[PCI_INTR_TYPE_MSIX] = 0; /* 0 means not use */ 279 counts[PCI_INTR_TYPE_MSI] = 3; 280 counts[PCI_INTR_TYPE_INTX] = 1; 281 error = pci_intr_alloc(pa, ihps, counts, 282 PCI_INTR_TYPE_MSI); 283.Ed 284If the driver wants to allocate interrupts in the following way: 285.Bd -literal 286 1 MSI-X 287 1 MSI 288 INTx (if MSI/MSI-X allocation failed) 289.Ed 290that is, general usage, the driver should call simply 291.Fn pci_intr_alloc 292in the following way: 293.Bd -literal 294 error = pci_intr_alloc(pa, ihps, NULL, 0); 295.Ed 296.Fa max_type 297is ignored in this case. 298.Fn pci_intr_alloc 299returns zero on any allocation function success, and non-zero on 300all allocation function failures. 301On success, 302.Fa counts 303is overwritten by a really allocated count. 304I.e., if 5 MSI-X is allocated, 305.Fa counts 306is 307.Bd -literal 308 counts[PCI_INTR_TYPE_MSIX] == 5 309 counts[PCI_INTR_TYPE_MSI] == 0 310 counts[PCI_INTR_TYPE_INTX] == 0 311.Ed 312on return. 313.Pp 314.Fn pci_intr_type 315returns the interrupt type of 316.Fa ih . 317The return value is 318.Dv PCI_INTR_TYPE_MSIX 319for MSI-X, 320.Dv PCI_INTR_TYPE_MSI 321for MSI, and 322.Dv PCI_INTR_TYPE_INTX 323for others. 324.Sh SEE ALSO 325.Xr pci_intr 9 326.Sh HISTORY 327.Nm 328support first appeared in 329.Nx 8.0 . 330Support is present on 331.Em i386 , 332.Em amd64 333and 334.Em aarch64 335architectures. 336.Sh AUTHORS 337The 338.Nm 339interfaces were designed and implemented by 340.An Kengo Nakahara 341.Aq Mt knakahara@NetBSD.org . 342