1.\" $NetBSD: pci_msi.9,v 1.7 2015/08/13 05:01:04 msaitoh 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 August 13, 2015 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 "struct pci_attach_args *pa" \ 51"pci_intr_handle_t **ihps" "int *count" 52.Ft int 53.Fn pci_msi_alloc_exect "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 "struct pci_attach_args *pa" \ 60"pci_intr_handle_t **ihps" "int *count" 61.Ft int 62.Fn pci_msix_alloc_exect "struct pci_attach_args *pa" \ 63"pci_intr_handle_t **ihps" "int count" 64.Ft int 65.Fn pci_msix_alloc_map "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 "struct pci_attach_args *pa" \ 69"pci_intr_handle_t **ihp" 70.Ft int 71.Fn pci_intr_alloc "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_intr_handle_t ih" 79.Sh DESCRIPTION 80The 81.Nm 82functions exist to allow device drivers to use MSI/MSI-X. 83When the system uses MSI/MSI-X, it must define the 84.Dv __HAVE_PCI_MSI_MSIX 85build option. 86.Pp 87Each driver has an 88.Fn attach 89function which has a bus-specific 90.Ft attach_args 91structure. 92Each driver for a PCI device is passed a pointer to an object of type 93.Ft struct pci_attach_args 94which contains, among other things, information about the location 95of the device in the PCI bus topology sufficient to allow interrupts 96from the device to be handled. 97.Pp 98If a driver wishes to establish an MSI handler for the device, 99it should pass the 100.Ft struct pci_attach_args * 101and 102.Fa count 103.Fn pci_msi_alloc 104or 105.Fn pci_msi_alloc_exact 106functions, which return zero on success, and nonzero on failure. 107When the functions are successful, they return the pointer to the 108allocated handle array in 109.Ft pihs 110whose size is 111.Ft count 112or less. 113The difference between 114.Fn pci_msi_alloc 115and 116.Fn pci_msi_alloc_exact 117is whether 118.Fa count 119can be decremented or not. 120.Fn pci_msi_alloc 121can decrement 122.Fa count , 123and which is similar to 124.Fx Ap s 125.Fn pci_alloc_msi . 126In contrast, 127.Fn pci_msi_alloc_exact 128can not decrement 129.Ft count . 130.Pp 131If the driver wishes to refer to the MSI source in an attach or 132error message, it should use the value returned by 133.Fn pci_intr_string 134the same as INTx. 135The buffer passed to 136.Fn pci_intr_string 137should be at least 138.Dv PCI_INTRSTR_LEN 139bytes long. 140.Pp 141Subsequently, when the driver is prepared to receive MSIs, it 142should call 143.Fn pci_intr_establish 144the same as INTx to actually establish the handler; 145when the device interrupts, 146.Fa intrhand 147will be called with a single argument 148.Fa intrarg , 149and will run at the interrupt priority level 150.Fa ipl . 151.Pp 152The return value of 153.Fn pci_intr_establish 154may be saved and passed to 155.Fn pci_intr_disestablish 156to disable the interrupt handler the same as INTx 157when the driver is no longer interested in MSIs from the device. 158After that, the driver should also call 159.Fn pci_intr_release 160to free resources about MSI as well as INTx and MSI-X. 161.Pp 162If a driver wishes to establish an MSI-X handler for the device, 163it is almost the same as MSI. 164The only differences is 165.Fn pci_msix_alloc_map . 166This function can assign separate handlers for each MSI-X table 167entry. 168I.e., if the driver wants to assign the handlers in the following way: 169.Bd -literal 170 msix_handler0 => MSI-X table index: 4 171 msix_handler1 => MSI-X table index: 5 172 msix_handler2 => MSI-X table index: 0 173.Ed 174the driver should set 175.Fa table_indexes 176this way: 177.Bd -literal 178 table_indexes[0] = 4; 179 table_indexes[1] = 5; 180 table_indexes[2] = 0; 181.Ed 182.Pp 183If the driver wants to fall back to INTx, the driver should use 184.Fn pci_intx_alloc 185and 186.Fn pci_intr_release 187instead of 188.Fn pci_intr_map 189to resolve contradiction of the interrupt handler ownership. 190I.e., 191.Fn pci_intr_map 192does not have the ownership (the function just calculates value), 193in contrast, 194.Fn pci_msi_alloc 195and 196.Fn pci_msix_alloc 197have (the functions allocate memory for interrupt handlers). 198.Pp 199.Fn pci_intr_alloc 200is wrapper function which select and automatically fallback 201allocation functions according to the argument 202.Fa counts . 203The elements of 204.Fa counts 205array means each required interrupt count for INTx, MSI, and MSI-X. 206The index count of 207.Fa counts 208must be 209.Dv PCI_INTR_TYPE_SIZE . 210.Fa max_type 211must be 212.Dv PCI_INTR_TYPE_MSIX , 213.Dv PCI_INTR_TYPE_MSI , 214or 215.Dv PCI_INTR_TYPE_INTX . 216The parameter does not mean array index counts of 217.Fa counts . 218The parameter means the interrupt type which 219.Fn pci_intr_alloc 220tries to allocate first. 221I.e., if the driver wants to allocate interrupts in the following way: 222.Bd -literal 223 5 MSI-X 224 1 MSI (if MSI-X allocation failed) 225 INTx (if MSI allocation failed either) 226.Ed 227the driver should call 228.Fn pci_intr_alloc 229in the following way: 230.Bd -literal 231 int counts[PCI_INTR_TYPE_SIZE]; 232 counts[PCI_INTR_TYPE_MSIX] = 5; 233 counts[PCI_INTR_TYPE_MSI] = 1; 234 counts[PCI_INTR_TYPE_INTX] = 1; 235 error = pci_intr_alloc(pa, ihps, counts, 236 PCI_INTR_TYPE_MSIX); 237.Ed 238If the driver wants to allocate interrupts in the following way: 239.Bd -literal 240 hardware max number MSI-X 241 1 MSI (if MSI-X allocation failed) 242.Ed 243that is, the driver does not use INTx, the driver should call 244.Fn pci_intr_alloc 245in the following way: 246.Bd -literal 247 int counts[PCI_INTR_TYPE_SIZE]; 248 counts[PCI_INTR_TYPE_MSIX] = -1; /* -1 means max */ 249 counts[PCI_INTR_TYPE_MSI] = 1; 250 counts[PCI_INTR_TYPE_INTX] = 0; /* 0 means not use */ 251 error = pci_intr_alloc(pa, ihps, counts, 252 PCI_INTR_TYPE_MSIX); 253.Ed 254If the driver wants to allocate interrupts in the following way: 255.Bd -literal 256 3 MSI 257 INTx (if MSI allocation failed) 258.Ed 259that is, the driver does not use MSI-X, the driver should call 260.Fn pci_intr_alloc 261in the following way: 262.Bd -literal 263 int counts[PCI_INTR_TYPE_SIZE]; 264 counts[PCI_INTR_TYPE_MSIX] = 0; /* 0 means not use */ 265 counts[PCI_INTR_TYPE_MSI] = 3; 266 counts[PCI_INTR_TYPE_INTX] = 1; 267 error = pci_intr_alloc(pa, ihps, counts, 268 PCI_INTR_TYPE_MSI); 269.Ed 270If the driver wants to allocate interrupts in the following way: 271.Bd -literal 272 1 MSI 273 INTx (if MSI allocation failed) 274.Ed 275that is, general usage, the driver should call simply 276.Fn pci_intr_alloc 277in the following way: 278.Bd -literal 279 error = pci_intr_alloc(pa, ihps, NULL, 0); 280.Ed 281.Fa max_type 282is ignored in this case. 283.Fn pci_intr_alloc 284returns zero on any allocation function success, and non-zero on 285all allocation function failures. 286On success, 287.Fa counts 288is overwritten by a really allocated count. 289I.e., if 5 MSI-X is allocated, 290.Fa counts 291is 292.Bd -literal 293 counts[PCI_INTR_TYPE_MSIX] == 5 294 counts[PCI_INTR_TYPE_MSI] == 0 295 counts[PCI_INTR_TYPE_INTX] == 0 296.Ed 297on return. 298.Pp 299.Fn pci_intr_type 300returns the interrupt type of 301.Fa ih . 302The return value is 303.Dv PCI_INTR_TYPE_MSIX 304for MSI-X, 305.Dv PCI_INTR_TYPE_MSI 306for MSI, and 307.Dv PCI_INTR_TYPE_INTX 308for others. 309.Sh SEE ALSO 310.Xr pci_intr 9 311