1.\" $NetBSD: pci_msi.9,v 1.10 2016/07/12 03:39:55 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 July 12, 2016 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_exect "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_exect "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. 162.Pp 163If a driver wishes to establish an MSI-X handler for the device, 164it is almost the same as MSI. 165The only differences is 166.Fn pci_msix_alloc_map . 167This function can assign separate handlers for each MSI-X table 168entry. 169I.e., if the driver wants to assign the handlers in the following way: 170.Bd -literal 171 msix_handler0 => MSI-X table index: 4 172 msix_handler1 => MSI-X table index: 5 173 msix_handler2 => MSI-X table index: 0 174.Ed 175the driver should set 176.Fa table_indexes 177this way: 178.Bd -literal 179 table_indexes[0] = 4; 180 table_indexes[1] = 5; 181 table_indexes[2] = 0; 182.Ed 183.Pp 184If the driver wants to fall back to INTx, the driver should use 185.Fn pci_intx_alloc 186and 187.Fn pci_intr_release 188instead of 189.Fn pci_intr_map 190to resolve contradiction of the interrupt handler ownership. 191I.e., 192.Fn pci_intr_map 193does not have the ownership (the function just calculates value), 194in contrast, 195.Fn pci_msi_alloc 196and 197.Fn pci_msix_alloc 198have (the functions allocate memory for interrupt handlers). 199.Pp 200.Fn pci_intr_alloc 201is wrapper function which select and automatically fallback 202allocation functions according to the argument 203.Fa counts . 204The elements of 205.Fa counts 206array means each required interrupt count for INTx, MSI, and MSI-X. 207The index count of 208.Fa counts 209must be 210.Dv PCI_INTR_TYPE_SIZE . 211.Fa max_type 212must be 213.Dv PCI_INTR_TYPE_MSIX , 214.Dv PCI_INTR_TYPE_MSI , 215or 216.Dv PCI_INTR_TYPE_INTX . 217The parameter does not mean array index counts of 218.Fa counts . 219The parameter means the interrupt type which 220.Fn pci_intr_alloc 221tries to allocate first. 222I.e., if the driver wants to allocate interrupts in the following way: 223.Bd -literal 224 5 MSI-X 225 1 MSI (if MSI-X allocation failed) 226 INTx (if MSI allocation failed either) 227.Ed 228the driver should call 229.Fn pci_intr_alloc 230in the following way: 231.Bd -literal 232 int counts[PCI_INTR_TYPE_SIZE]; 233 counts[PCI_INTR_TYPE_MSIX] = 5; 234 counts[PCI_INTR_TYPE_MSI] = 1; 235 counts[PCI_INTR_TYPE_INTX] = 1; 236 error = pci_intr_alloc(pa, ihps, counts, 237 PCI_INTR_TYPE_MSIX); 238.Ed 239If the driver wants to allocate interrupts in the following way: 240.Bd -literal 241 hardware max number MSI-X 242 1 MSI (if MSI-X allocation failed) 243.Ed 244that is, the driver does not use INTx, the driver should call 245.Fn pci_intr_alloc 246in the following way: 247.Bd -literal 248 int counts[PCI_INTR_TYPE_SIZE]; 249 counts[PCI_INTR_TYPE_MSIX] = -1; /* -1 means max */ 250 counts[PCI_INTR_TYPE_MSI] = 1; 251 counts[PCI_INTR_TYPE_INTX] = 0; /* 0 means not use */ 252 error = pci_intr_alloc(pa, ihps, counts, 253 PCI_INTR_TYPE_MSIX); 254.Ed 255If the driver wants to allocate interrupts in the following way: 256.Bd -literal 257 3 MSI 258 INTx (if MSI allocation failed) 259.Ed 260that is, the driver does not use MSI-X, the driver should call 261.Fn pci_intr_alloc 262in the following way: 263.Bd -literal 264 int counts[PCI_INTR_TYPE_SIZE]; 265 counts[PCI_INTR_TYPE_MSIX] = 0; /* 0 means not use */ 266 counts[PCI_INTR_TYPE_MSI] = 3; 267 counts[PCI_INTR_TYPE_INTX] = 1; 268 error = pci_intr_alloc(pa, ihps, counts, 269 PCI_INTR_TYPE_MSI); 270.Ed 271If the driver wants to allocate interrupts in the following way: 272.Bd -literal 273 1 MSI 274 INTx (if MSI allocation failed) 275.Ed 276that is, general usage, the driver should call simply 277.Fn pci_intr_alloc 278in the following way: 279.Bd -literal 280 error = pci_intr_alloc(pa, ihps, NULL, 0); 281.Ed 282.Fa max_type 283is ignored in this case. 284.Fn pci_intr_alloc 285returns zero on any allocation function success, and non-zero on 286all allocation function failures. 287On success, 288.Fa counts 289is overwritten by a really allocated count. 290I.e., if 5 MSI-X is allocated, 291.Fa counts 292is 293.Bd -literal 294 counts[PCI_INTR_TYPE_MSIX] == 5 295 counts[PCI_INTR_TYPE_MSI] == 0 296 counts[PCI_INTR_TYPE_INTX] == 0 297.Ed 298on return. 299.Pp 300.Fn pci_intr_type 301returns the interrupt type of 302.Fa ih . 303The return value is 304.Dv PCI_INTR_TYPE_MSIX 305for MSI-X, 306.Dv PCI_INTR_TYPE_MSI 307for MSI, and 308.Dv PCI_INTR_TYPE_INTX 309for others. 310.Sh SEE ALSO 311.Xr pci_intr 9 312