1 1.19 gutterid /* $NetBSD: pci_msi_machdep.c,v 1.19 2023/11/21 23:22:23 gutteridge Exp $ */ 2 1.1 knakahar 3 1.1 knakahar /* 4 1.1 knakahar * Copyright (c) 2015 Internet Initiative Japan Inc. 5 1.1 knakahar * All rights reserved. 6 1.1 knakahar * 7 1.1 knakahar * Redistribution and use in source and binary forms, with or without 8 1.1 knakahar * modification, are permitted provided that the following conditions 9 1.1 knakahar * are met: 10 1.1 knakahar * 1. Redistributions of source code must retain the above copyright 11 1.1 knakahar * notice, this list of conditions and the following disclaimer. 12 1.1 knakahar * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 knakahar * notice, this list of conditions and the following disclaimer in the 14 1.1 knakahar * documentation and/or other materials provided with the distribution. 15 1.1 knakahar * 16 1.1 knakahar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 knakahar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 knakahar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 knakahar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 knakahar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 knakahar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 knakahar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 knakahar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 knakahar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 knakahar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 knakahar * POSSIBILITY OF SUCH DAMAGE. 27 1.1 knakahar */ 28 1.1 knakahar 29 1.1 knakahar /* 30 1.1 knakahar * TODO 31 1.1 knakahar * 32 1.1 knakahar * - PBA (Pending Bit Array) support 33 1.1 knakahar * - HyperTransport mapping support 34 1.1 knakahar */ 35 1.1 knakahar 36 1.1 knakahar #include <sys/cdefs.h> 37 1.19 gutterid __KERNEL_RCSID(0, "$NetBSD: pci_msi_machdep.c,v 1.19 2023/11/21 23:22:23 gutteridge Exp $"); 38 1.7 msaitoh 39 1.7 msaitoh #include "opt_intrdebug.h" 40 1.11 knakahar #include "ioapic.h" 41 1.1 knakahar 42 1.1 knakahar #include <sys/types.h> 43 1.1 knakahar #include <sys/param.h> 44 1.1 knakahar #include <sys/time.h> 45 1.1 knakahar #include <sys/systm.h> 46 1.1 knakahar #include <sys/cpu.h> 47 1.1 knakahar #include <sys/errno.h> 48 1.1 knakahar #include <sys/device.h> 49 1.1 knakahar #include <sys/intr.h> 50 1.1 knakahar #include <sys/kmem.h> 51 1.1 knakahar 52 1.1 knakahar #include <dev/pci/pcivar.h> 53 1.1 knakahar 54 1.1 knakahar #include <machine/i82093var.h> 55 1.1 knakahar #include <machine/pic.h> 56 1.1 knakahar 57 1.1 knakahar #include <x86/pci/msipic.h> 58 1.3 knakahar #include <x86/pci/pci_msi_machdep.h> 59 1.1 knakahar 60 1.1 knakahar #ifdef INTRDEBUG 61 1.1 knakahar #define MSIDEBUG 62 1.1 knakahar #endif 63 1.1 knakahar 64 1.1 knakahar #ifdef MSIDEBUG 65 1.1 knakahar #define DPRINTF(msg) printf msg 66 1.1 knakahar #else 67 1.1 knakahar #define DPRINTF(msg) 68 1.1 knakahar #endif 69 1.1 knakahar 70 1.1 knakahar static pci_intr_handle_t 71 1.1 knakahar pci_msi_calculate_handle(struct pic *msi_pic, int vector) 72 1.1 knakahar { 73 1.1 knakahar pci_intr_handle_t pih; 74 1.1 knakahar 75 1.1 knakahar KASSERT(msipic_is_msi_pic(msi_pic)); 76 1.1 knakahar 77 1.1 knakahar pih = __SHIFTIN((uint64_t)msipic_get_devid(msi_pic), MSI_INT_DEV_MASK) 78 1.1 knakahar | __SHIFTIN((uint64_t)vector, MSI_INT_VEC_MASK) 79 1.1 knakahar | APIC_INT_VIA_MSI; 80 1.1 knakahar if (msi_pic->pic_type == PIC_MSI) 81 1.1 knakahar MSI_INT_MAKE_MSI(pih); 82 1.1 knakahar else if (msi_pic->pic_type == PIC_MSIX) 83 1.1 knakahar MSI_INT_MAKE_MSIX(pih); 84 1.1 knakahar else 85 1.1 knakahar panic("%s: Unexpected pic_type: %d\n", __func__, 86 1.1 knakahar msi_pic->pic_type); 87 1.1 knakahar 88 1.1 knakahar return pih; 89 1.1 knakahar } 90 1.1 knakahar 91 1.10 knakahar #ifdef __HAVE_PCI_MSI_MSIX 92 1.1 knakahar static pci_intr_handle_t * 93 1.1 knakahar pci_msi_alloc_vectors(struct pic *msi_pic, uint *table_indexes, int *count) 94 1.1 knakahar { 95 1.1 knakahar struct intrsource *isp; 96 1.1 knakahar pci_intr_handle_t *vectors, pih; 97 1.1 knakahar int i; 98 1.1 knakahar const char *intrstr; 99 1.1 knakahar char intrstr_buf[INTRIDBUF]; 100 1.1 knakahar 101 1.1 knakahar vectors = kmem_zalloc(sizeof(vectors[0]) * (*count), KM_SLEEP); 102 1.1 knakahar mutex_enter(&cpu_lock); 103 1.1 knakahar for (i = 0; i < *count; i++) { 104 1.1 knakahar u_int table_index; 105 1.1 knakahar 106 1.1 knakahar if (table_indexes == NULL) 107 1.1 knakahar table_index = i; 108 1.1 knakahar else 109 1.1 knakahar table_index = table_indexes[i]; 110 1.1 knakahar 111 1.1 knakahar pih = pci_msi_calculate_handle(msi_pic, table_index); 112 1.1 knakahar 113 1.5 knakahar intrstr = x86_pci_msi_string(NULL, pih, intrstr_buf, 114 1.1 knakahar sizeof(intrstr_buf)); 115 1.1 knakahar isp = intr_allocate_io_intrsource(intrstr); 116 1.1 knakahar if (isp == NULL) { 117 1.1 knakahar mutex_exit(&cpu_lock); 118 1.1 knakahar DPRINTF(("can't allocate io_intersource\n")); 119 1.1 knakahar kmem_free(vectors, sizeof(vectors[0]) * (*count)); 120 1.1 knakahar return NULL; 121 1.1 knakahar } 122 1.1 knakahar 123 1.1 knakahar vectors[i] = pih; 124 1.1 knakahar } 125 1.1 knakahar mutex_exit(&cpu_lock); 126 1.1 knakahar 127 1.1 knakahar return vectors; 128 1.1 knakahar } 129 1.10 knakahar #endif /* __HAVE_PCI_MSI_MSIX */ 130 1.1 knakahar 131 1.1 knakahar static void 132 1.1 knakahar pci_msi_free_vectors(struct pic *msi_pic, pci_intr_handle_t *pihs, int count) 133 1.1 knakahar { 134 1.1 knakahar pci_intr_handle_t pih; 135 1.1 knakahar int i; 136 1.1 knakahar const char *intrstr; 137 1.1 knakahar char intrstr_buf[INTRIDBUF]; 138 1.1 knakahar 139 1.1 knakahar mutex_enter(&cpu_lock); 140 1.1 knakahar for (i = 0; i < count; i++) { 141 1.1 knakahar pih = pci_msi_calculate_handle(msi_pic, i); 142 1.5 knakahar intrstr = x86_pci_msi_string(NULL, pih, intrstr_buf, 143 1.1 knakahar sizeof(intrstr_buf)); 144 1.1 knakahar intr_free_io_intrsource(intrstr); 145 1.1 knakahar } 146 1.1 knakahar mutex_exit(&cpu_lock); 147 1.1 knakahar 148 1.1 knakahar kmem_free(pihs, sizeof(pihs[0]) * count); 149 1.1 knakahar } 150 1.1 knakahar 151 1.10 knakahar #ifdef __HAVE_PCI_MSI_MSIX 152 1.1 knakahar static int 153 1.4 knakahar pci_msi_alloc_common(pci_intr_handle_t **ihps, int *count, 154 1.2 knakahar const struct pci_attach_args *pa, bool exact) 155 1.1 knakahar { 156 1.1 knakahar struct pic *msi_pic; 157 1.1 knakahar pci_intr_handle_t *vectors; 158 1.1 knakahar int error, i; 159 1.1 knakahar 160 1.11 knakahar #if NIOAPIC > 0 161 1.11 knakahar if (nioapics == 0) { 162 1.11 knakahar DPRINTF(("no IOAPIC.\n")); 163 1.11 knakahar return ENODEV; 164 1.11 knakahar } 165 1.11 knakahar #endif 166 1.11 knakahar 167 1.1 knakahar if ((pa->pa_flags & PCI_FLAGS_MSI_OKAY) == 0) { 168 1.1 knakahar DPRINTF(("PCI host bridge does not support MSI.\n")); 169 1.1 knakahar return ENODEV; 170 1.1 knakahar } 171 1.1 knakahar 172 1.1 knakahar msi_pic = msipic_construct_msi_pic(pa); 173 1.1 knakahar if (msi_pic == NULL) { 174 1.1 knakahar DPRINTF(("cannot allocate MSI pic.\n")); 175 1.1 knakahar return EINVAL; 176 1.1 knakahar } 177 1.1 knakahar 178 1.1 knakahar vectors = NULL; 179 1.1 knakahar while (*count > 0) { 180 1.1 knakahar vectors = pci_msi_alloc_vectors(msi_pic, NULL, count); 181 1.1 knakahar if (vectors != NULL) 182 1.1 knakahar break; 183 1.1 knakahar 184 1.1 knakahar if (exact) { 185 1.1 knakahar DPRINTF(("cannot allocate MSI vectors.\n")); 186 1.1 knakahar msipic_destruct_msi_pic(msi_pic); 187 1.1 knakahar return ENOMEM; 188 1.1 knakahar } else { 189 1.1 knakahar (*count) >>= 1; /* must be power of 2. */ 190 1.1 knakahar continue; 191 1.1 knakahar } 192 1.1 knakahar } 193 1.1 knakahar if (vectors == NULL) { 194 1.1 knakahar DPRINTF(("cannot allocate MSI vectors.\n")); 195 1.1 knakahar msipic_destruct_msi_pic(msi_pic); 196 1.1 knakahar return ENOMEM; 197 1.1 knakahar } 198 1.1 knakahar 199 1.1 knakahar for (i = 0; i < *count; i++) { 200 1.1 knakahar MSI_INT_MAKE_MSI(vectors[i]); 201 1.1 knakahar } 202 1.1 knakahar 203 1.1 knakahar error = msipic_set_msi_vectors(msi_pic, NULL, *count); 204 1.1 knakahar if (error) { 205 1.1 knakahar pci_msi_free_vectors(msi_pic, vectors, *count); 206 1.1 knakahar msipic_destruct_msi_pic(msi_pic); 207 1.1 knakahar return error; 208 1.1 knakahar } 209 1.1 knakahar 210 1.1 knakahar *ihps = vectors; 211 1.17 bouyer #ifdef XENPV 212 1.17 bouyer if (xen_map_msi_pirq(msi_pic, *count)) { 213 1.17 bouyer DPRINTF(("xen_map_msi_pirq() failed\n")); 214 1.17 bouyer pci_msi_free_vectors(msi_pic, vectors, *count); 215 1.17 bouyer msipic_destruct_msi_pic(msi_pic); 216 1.17 bouyer return EINVAL; 217 1.17 bouyer } 218 1.17 bouyer #endif 219 1.17 bouyer 220 1.1 knakahar return 0; 221 1.1 knakahar } 222 1.10 knakahar #endif /* __HAVE_PCI_MSI_MSIX */ 223 1.1 knakahar 224 1.1 knakahar static void * 225 1.1 knakahar pci_msi_common_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 226 1.9 knakahar int level, int (*func)(void *), void *arg, struct pic *pic, 227 1.9 knakahar const char *xname) 228 1.1 knakahar { 229 1.1 knakahar int irq, pin; 230 1.1 knakahar bool mpsafe; 231 1.1 knakahar 232 1.1 knakahar KASSERT(INT_VIA_MSI(ih)); 233 1.1 knakahar 234 1.1 knakahar irq = -1; 235 1.1 knakahar pin = MSI_INT_VEC(ih); 236 1.1 knakahar mpsafe = ((ih & MPSAFE_MASK) != 0); 237 1.1 knakahar 238 1.9 knakahar return intr_establish_xname(irq, pic, pin, IST_EDGE, level, func, arg, 239 1.9 knakahar mpsafe, xname); 240 1.1 knakahar } 241 1.1 knakahar 242 1.1 knakahar static void 243 1.1 knakahar pci_msi_common_disestablish(pci_chipset_tag_t pc, void *cookie) 244 1.1 knakahar { 245 1.1 knakahar 246 1.1 knakahar intr_disestablish(cookie); 247 1.1 knakahar } 248 1.1 knakahar 249 1.10 knakahar #ifdef __HAVE_PCI_MSI_MSIX 250 1.1 knakahar static int 251 1.4 knakahar pci_msix_alloc_common(pci_intr_handle_t **ihps, u_int *table_indexes, 252 1.2 knakahar int *count, const struct pci_attach_args *pa, bool exact) 253 1.1 knakahar { 254 1.1 knakahar struct pic *msix_pic; 255 1.1 knakahar pci_intr_handle_t *vectors; 256 1.1 knakahar int error, i; 257 1.1 knakahar 258 1.11 knakahar #if NIOAPIC > 0 259 1.11 knakahar if (nioapics == 0) { 260 1.11 knakahar DPRINTF(("no IOAPIC.\n")); 261 1.11 knakahar return ENODEV; 262 1.11 knakahar } 263 1.11 knakahar #endif 264 1.11 knakahar 265 1.6 msaitoh if ((pa->pa_flags & PCI_FLAGS_MSIX_OKAY) == 0) { 266 1.1 knakahar DPRINTF(("PCI host bridge does not support MSI-X.\n")); 267 1.1 knakahar return ENODEV; 268 1.1 knakahar } 269 1.1 knakahar 270 1.1 knakahar msix_pic = msipic_construct_msix_pic(pa); 271 1.1 knakahar if (msix_pic == NULL) 272 1.1 knakahar return EINVAL; 273 1.1 knakahar 274 1.1 knakahar vectors = NULL; 275 1.1 knakahar while (*count > 0) { 276 1.1 knakahar vectors = pci_msi_alloc_vectors(msix_pic, table_indexes, count); 277 1.1 knakahar if (vectors != NULL) 278 1.1 knakahar break; 279 1.1 knakahar 280 1.1 knakahar if (exact) { 281 1.1 knakahar DPRINTF(("cannot allocate MSI-X vectors.\n")); 282 1.1 knakahar msipic_destruct_msix_pic(msix_pic); 283 1.1 knakahar return ENOMEM; 284 1.1 knakahar } else { 285 1.1 knakahar (*count)--; 286 1.1 knakahar continue; 287 1.1 knakahar } 288 1.1 knakahar } 289 1.1 knakahar if (vectors == NULL) { 290 1.1 knakahar DPRINTF(("cannot allocate MSI-X vectors.\n")); 291 1.1 knakahar msipic_destruct_msix_pic(msix_pic); 292 1.1 knakahar return ENOMEM; 293 1.1 knakahar } 294 1.1 knakahar 295 1.1 knakahar for (i = 0; i < *count; i++) { 296 1.1 knakahar MSI_INT_MAKE_MSIX(vectors[i]); 297 1.1 knakahar } 298 1.1 knakahar 299 1.1 knakahar error = msipic_set_msi_vectors(msix_pic, vectors, *count); 300 1.1 knakahar if (error) { 301 1.1 knakahar pci_msi_free_vectors(msix_pic, vectors, *count); 302 1.1 knakahar msipic_destruct_msix_pic(msix_pic); 303 1.1 knakahar return error; 304 1.1 knakahar } 305 1.1 knakahar 306 1.1 knakahar *ihps = vectors; 307 1.17 bouyer 308 1.17 bouyer #ifdef XENPV 309 1.17 bouyer if (xen_map_msix_pirq(msix_pic, *count)) { 310 1.17 bouyer DPRINTF(("xen_map_msi_pirq() failed\n")); 311 1.17 bouyer pci_msi_free_vectors(msix_pic, vectors, *count); 312 1.17 bouyer msipic_destruct_msix_pic(msix_pic); 313 1.17 bouyer return EINVAL; 314 1.17 bouyer } 315 1.17 bouyer #endif 316 1.1 knakahar return 0; 317 1.1 knakahar } 318 1.1 knakahar 319 1.1 knakahar static int 320 1.4 knakahar x86_pci_msi_alloc(pci_intr_handle_t **ihps, int *count, 321 1.2 knakahar const struct pci_attach_args *pa) 322 1.1 knakahar { 323 1.1 knakahar 324 1.4 knakahar return pci_msi_alloc_common(ihps, count, pa, false); 325 1.1 knakahar } 326 1.1 knakahar 327 1.1 knakahar static int 328 1.4 knakahar x86_pci_msi_alloc_exact(pci_intr_handle_t **ihps, int count, 329 1.2 knakahar const struct pci_attach_args *pa) 330 1.1 knakahar { 331 1.1 knakahar 332 1.4 knakahar return pci_msi_alloc_common(ihps, &count, pa, true); 333 1.4 knakahar } 334 1.10 knakahar #endif /* __HAVE_PCI_MSI_MSIX */ 335 1.4 knakahar 336 1.4 knakahar static void 337 1.4 knakahar x86_pci_msi_release_internal(pci_intr_handle_t *pihs, int count) 338 1.4 knakahar { 339 1.4 knakahar struct pic *pic; 340 1.4 knakahar 341 1.4 knakahar pic = msipic_find_msi_pic(MSI_INT_DEV(pihs[0])); 342 1.4 knakahar if (pic == NULL) 343 1.4 knakahar return; 344 1.4 knakahar 345 1.17 bouyer #ifdef XENPV 346 1.17 bouyer xen_pci_msi_release(pic, count); 347 1.17 bouyer #endif 348 1.4 knakahar pci_msi_free_vectors(pic, pihs, count); 349 1.4 knakahar msipic_destruct_msi_pic(pic); 350 1.1 knakahar } 351 1.1 knakahar 352 1.10 knakahar #ifdef __HAVE_PCI_MSI_MSIX 353 1.1 knakahar static int 354 1.4 knakahar x86_pci_msix_alloc(pci_intr_handle_t **ihps, int *count, 355 1.2 knakahar const struct pci_attach_args *pa) 356 1.1 knakahar { 357 1.1 knakahar 358 1.4 knakahar return pci_msix_alloc_common(ihps, NULL, count, pa, false); 359 1.4 knakahar } 360 1.4 knakahar 361 1.4 knakahar static int 362 1.4 knakahar x86_pci_msix_alloc_exact(pci_intr_handle_t **ihps, int count, 363 1.4 knakahar const struct pci_attach_args *pa) 364 1.4 knakahar { 365 1.4 knakahar 366 1.4 knakahar return pci_msix_alloc_common(ihps, NULL, &count, pa, true); 367 1.4 knakahar } 368 1.4 knakahar 369 1.4 knakahar static int 370 1.4 knakahar x86_pci_msix_alloc_map(pci_intr_handle_t **ihps, u_int *table_indexes, 371 1.4 knakahar int count, const struct pci_attach_args *pa) 372 1.4 knakahar { 373 1.4 knakahar 374 1.4 knakahar return pci_msix_alloc_common(ihps, table_indexes, &count, pa, true); 375 1.1 knakahar } 376 1.10 knakahar #endif /* __HAVE_PCI_MSI_MSIX */ 377 1.1 knakahar 378 1.1 knakahar static void 379 1.4 knakahar x86_pci_msix_release_internal(pci_intr_handle_t *pihs, int count) 380 1.1 knakahar { 381 1.1 knakahar struct pic *pic; 382 1.1 knakahar 383 1.3 knakahar pic = msipic_find_msi_pic(MSI_INT_DEV(pihs[0])); 384 1.1 knakahar if (pic == NULL) 385 1.1 knakahar return; 386 1.1 knakahar 387 1.17 bouyer #ifdef XENPV 388 1.17 bouyer xen_pci_msi_release(pic, count); 389 1.17 bouyer #endif 390 1.3 knakahar pci_msi_free_vectors(pic, pihs, count); 391 1.1 knakahar msipic_destruct_msix_pic(pic); 392 1.1 knakahar } 393 1.1 knakahar 394 1.1 knakahar /*****************************************************************************/ 395 1.1 knakahar /* 396 1.5 knakahar * extern for MD code. 397 1.4 knakahar */ 398 1.4 knakahar 399 1.4 knakahar /* 400 1.19 gutterid * Return intrid for an MSI/MSI-X device. 401 1.5 knakahar * "buf" must be allocated by caller. 402 1.5 knakahar */ 403 1.5 knakahar const char * 404 1.5 knakahar x86_pci_msi_string(pci_chipset_tag_t pc, pci_intr_handle_t ih, char *buf, 405 1.5 knakahar size_t len) 406 1.5 knakahar { 407 1.5 knakahar int dev, vec; 408 1.5 knakahar 409 1.5 knakahar KASSERT(INT_VIA_MSI(ih)); 410 1.5 knakahar 411 1.5 knakahar dev = MSI_INT_DEV(ih); 412 1.5 knakahar vec = MSI_INT_VEC(ih); 413 1.5 knakahar if (MSI_INT_IS_MSIX(ih)) 414 1.5 knakahar snprintf(buf, len, "msix%d vec %d", dev, vec); 415 1.5 knakahar else 416 1.5 knakahar snprintf(buf, len, "msi%d vec %d", dev, vec); 417 1.5 knakahar 418 1.5 knakahar return buf; 419 1.5 knakahar } 420 1.5 knakahar 421 1.5 knakahar /* 422 1.4 knakahar * Release MSI handles. 423 1.4 knakahar */ 424 1.4 knakahar void 425 1.4 knakahar x86_pci_msi_release(pci_chipset_tag_t pc, pci_intr_handle_t *pihs, int count) 426 1.4 knakahar { 427 1.4 knakahar 428 1.4 knakahar if (count < 1) 429 1.4 knakahar return; 430 1.4 knakahar 431 1.4 knakahar return x86_pci_msi_release_internal(pihs, count); 432 1.4 knakahar } 433 1.4 knakahar 434 1.4 knakahar /* 435 1.19 gutterid * Establish an MSI handle. 436 1.19 gutterid * If multiple MSI handles are required to be established, a device driver 437 1.19 gutterid * must call this function for each handle. 438 1.4 knakahar */ 439 1.4 knakahar void * 440 1.4 knakahar x86_pci_msi_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 441 1.9 knakahar int level, int (*func)(void *), void *arg, const char *xname) 442 1.4 knakahar { 443 1.4 knakahar struct pic *pic; 444 1.4 knakahar 445 1.4 knakahar pic = msipic_find_msi_pic(MSI_INT_DEV(ih)); 446 1.4 knakahar if (pic == NULL) { 447 1.4 knakahar DPRINTF(("pci_intr_handler has no msi_pic\n")); 448 1.4 knakahar return NULL; 449 1.4 knakahar } 450 1.4 knakahar 451 1.9 knakahar return pci_msi_common_establish(pc, ih, level, func, arg, pic, xname); 452 1.4 knakahar } 453 1.4 knakahar 454 1.4 knakahar /* 455 1.19 gutterid * Disestablish an MSI handle. 456 1.19 gutterid * If multiple MSI handles are required to be disestablished, a device driver 457 1.19 gutterid * must call this function for each handle. 458 1.4 knakahar */ 459 1.4 knakahar void 460 1.4 knakahar x86_pci_msi_disestablish(pci_chipset_tag_t pc, void *cookie) 461 1.4 knakahar { 462 1.4 knakahar 463 1.4 knakahar pci_msi_common_disestablish(pc, cookie); 464 1.4 knakahar } 465 1.4 knakahar 466 1.4 knakahar /* 467 1.4 knakahar * Release MSI-X handles. 468 1.4 knakahar */ 469 1.4 knakahar void 470 1.4 knakahar x86_pci_msix_release(pci_chipset_tag_t pc, pci_intr_handle_t *pihs, int count) 471 1.4 knakahar { 472 1.4 knakahar 473 1.4 knakahar if (count < 1) 474 1.4 knakahar return; 475 1.4 knakahar 476 1.4 knakahar return x86_pci_msix_release_internal(pihs, count); 477 1.4 knakahar } 478 1.4 knakahar 479 1.4 knakahar /* 480 1.19 gutterid * Establish an MSI-X handle. 481 1.19 gutterid * If multiple MSI-X handles are required to be established, a device driver 482 1.19 gutterid * must call this function for each handle. 483 1.4 knakahar */ 484 1.4 knakahar void * 485 1.4 knakahar x86_pci_msix_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 486 1.9 knakahar int level, int (*func)(void *), void *arg, const char *xname) 487 1.4 knakahar { 488 1.4 knakahar struct pic *pic; 489 1.4 knakahar 490 1.4 knakahar pic = msipic_find_msi_pic(MSI_INT_DEV(ih)); 491 1.4 knakahar if (pic == NULL) { 492 1.4 knakahar DPRINTF(("pci_intr_handler has no msi_pic\n")); 493 1.4 knakahar return NULL; 494 1.4 knakahar } 495 1.4 knakahar 496 1.9 knakahar return pci_msi_common_establish(pc, ih, level, func, arg, pic, xname); 497 1.4 knakahar } 498 1.4 knakahar 499 1.4 knakahar /* 500 1.19 gutterid * Disestablish an MSI-X handle. 501 1.19 gutterid * If multiple MSI-X handles are required to be disestablished, a device driver 502 1.19 gutterid * must call this function for each handle. 503 1.4 knakahar */ 504 1.4 knakahar void 505 1.4 knakahar x86_pci_msix_disestablish(pci_chipset_tag_t pc, void *cookie) 506 1.4 knakahar { 507 1.4 knakahar 508 1.4 knakahar pci_msi_common_disestablish(pc, cookie); 509 1.4 knakahar } 510 1.4 knakahar 511 1.10 knakahar #ifdef __HAVE_PCI_MSI_MSIX 512 1.4 knakahar /*****************************************************************************/ 513 1.4 knakahar /* 514 1.5 knakahar * extern for MI code. 515 1.1 knakahar */ 516 1.1 knakahar 517 1.1 knakahar /* 518 1.1 knakahar * This function is used by device drivers like pci_intr_map(). 519 1.1 knakahar * 520 1.15 skrll * "ihps" is the array of vector numbers which MSI used instead of IRQ number. 521 1.1 knakahar * "count" must be power of 2. 522 1.1 knakahar * "count" can decrease if struct intrsource cannot be allocated. 523 1.1 knakahar * if count == 0, return non-zero value. 524 1.1 knakahar */ 525 1.1 knakahar int 526 1.2 knakahar pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps, 527 1.2 knakahar int *count) 528 1.1 knakahar { 529 1.1 knakahar int hw_max; 530 1.1 knakahar 531 1.1 knakahar /* MSI vector count must be power of 2. */ 532 1.1 knakahar KASSERT(*count > 0); 533 1.1 knakahar KASSERT(((*count - 1) & *count) == 0); 534 1.1 knakahar 535 1.8 msaitoh hw_max = pci_msi_count(pa->pa_pc, pa->pa_tag); 536 1.1 knakahar if (hw_max == 0) 537 1.1 knakahar return ENODEV; 538 1.1 knakahar 539 1.1 knakahar if (*count > hw_max) { 540 1.1 knakahar DPRINTF(("cut off MSI count to %d\n", hw_max)); 541 1.1 knakahar *count = hw_max; /* cut off hw_max */ 542 1.1 knakahar } 543 1.1 knakahar 544 1.4 knakahar return x86_pci_msi_alloc(ihps, count, pa); 545 1.1 knakahar } 546 1.1 knakahar 547 1.1 knakahar /* 548 1.1 knakahar * This function is used by device drivers like pci_intr_map(). 549 1.1 knakahar * 550 1.1 knakahar * "ihps" is the array of vector numbers which MSI used instead of IRQ number. 551 1.1 knakahar * "count" must be power of 2. 552 1.1 knakahar * "count" can not decrease. 553 1.1 knakahar * If "count" struct intrsources cannot be allocated, return non-zero value. 554 1.1 knakahar */ 555 1.1 knakahar int 556 1.2 knakahar pci_msi_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps, 557 1.1 knakahar int count) 558 1.1 knakahar { 559 1.1 knakahar int hw_max; 560 1.1 knakahar 561 1.1 knakahar /* MSI vector count must be power of 2. */ 562 1.1 knakahar KASSERT(count > 0); 563 1.1 knakahar KASSERT(((count - 1) & count) == 0); 564 1.1 knakahar 565 1.8 msaitoh hw_max = pci_msi_count(pa->pa_pc, pa->pa_tag); 566 1.1 knakahar if (hw_max == 0) 567 1.1 knakahar return ENODEV; 568 1.1 knakahar 569 1.1 knakahar if (count > hw_max) { 570 1.1 knakahar DPRINTF(("over hardware max MSI count %d\n", hw_max)); 571 1.1 knakahar return EINVAL; 572 1.1 knakahar } 573 1.1 knakahar 574 1.4 knakahar return x86_pci_msi_alloc_exact(ihps, count, pa); 575 1.1 knakahar } 576 1.1 knakahar 577 1.1 knakahar /* 578 1.1 knakahar * This function is used by device drivers like pci_intr_map(). 579 1.1 knakahar * 580 1.19 gutterid * "ihps" is the array of vector numbers which MSI-X used instead of IRQ number. 581 1.1 knakahar * "count" can decrease if enough struct intrsources cannot be allocated. 582 1.1 knakahar * if count == 0, return non-zero value. 583 1.1 knakahar */ 584 1.1 knakahar int 585 1.2 knakahar pci_msix_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps, 586 1.2 knakahar int *count) 587 1.1 knakahar { 588 1.1 knakahar int hw_max; 589 1.1 knakahar 590 1.1 knakahar KASSERT(*count > 0); 591 1.1 knakahar 592 1.8 msaitoh hw_max = pci_msix_count(pa->pa_pc, pa->pa_tag); 593 1.1 knakahar if (hw_max == 0) 594 1.1 knakahar return ENODEV; 595 1.1 knakahar 596 1.1 knakahar if (*count > hw_max) { 597 1.1 knakahar DPRINTF(("cut off MSI-X count to %d\n", hw_max)); 598 1.1 knakahar *count = hw_max; /* cut off hw_max */ 599 1.1 knakahar } 600 1.1 knakahar 601 1.4 knakahar return x86_pci_msix_alloc(ihps, count, pa); 602 1.1 knakahar } 603 1.1 knakahar 604 1.1 knakahar /* 605 1.1 knakahar * This function is used by device drivers like pci_intr_map(). 606 1.1 knakahar * 607 1.1 knakahar * "ihps" is the array of vector numbers which MSI-X used instead of IRQ number. 608 1.1 knakahar * "count" can not decrease. 609 1.1 knakahar * If "count" struct intrsource cannot be allocated, return non-zero value. 610 1.1 knakahar */ 611 1.1 knakahar int 612 1.2 knakahar pci_msix_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps, 613 1.1 knakahar int count) 614 1.1 knakahar { 615 1.1 knakahar int hw_max; 616 1.1 knakahar 617 1.1 knakahar KASSERT(count > 0); 618 1.1 knakahar 619 1.8 msaitoh hw_max = pci_msix_count(pa->pa_pc, pa->pa_tag); 620 1.1 knakahar if (hw_max == 0) 621 1.1 knakahar return ENODEV; 622 1.1 knakahar 623 1.1 knakahar if (count > hw_max) { 624 1.1 knakahar DPRINTF(("over hardware max MSI-X count %d\n", hw_max)); 625 1.1 knakahar return EINVAL; 626 1.1 knakahar } 627 1.1 knakahar 628 1.4 knakahar return x86_pci_msix_alloc_exact(ihps, count, pa); 629 1.1 knakahar } 630 1.1 knakahar 631 1.1 knakahar /* 632 1.1 knakahar * This function is used by device drivers like pci_intr_map(). 633 1.19 gutterid * Furthermore, this function can map each handle to an MSI-X table index. 634 1.1 knakahar * 635 1.1 knakahar * "ihps" is the array of vector numbers which MSI-X used instead of IRQ number. 636 1.1 knakahar * "count" can not decrease. 637 1.1 knakahar * "map" size must be equal to "count". 638 1.1 knakahar * If "count" struct intrsource cannot be allocated, return non-zero value. 639 1.1 knakahar * e.g. 640 1.1 knakahar * If "map" = { 1, 4, 0 }, 641 1.1 knakahar * 1st handle is bound to MSI-X index 1 642 1.1 knakahar * 2nd handle is bound to MSI-X index 4 643 1.1 knakahar * 3rd handle is bound to MSI-X index 0 644 1.1 knakahar */ 645 1.1 knakahar int 646 1.2 knakahar pci_msix_alloc_map(const struct pci_attach_args *pa, pci_intr_handle_t **ihps, 647 1.1 knakahar u_int *table_indexes, int count) 648 1.1 knakahar { 649 1.1 knakahar int hw_max, i, j; 650 1.1 knakahar 651 1.1 knakahar KASSERT(count > 0); 652 1.1 knakahar 653 1.8 msaitoh hw_max = pci_msix_count(pa->pa_pc, pa->pa_tag); 654 1.1 knakahar if (hw_max == 0) 655 1.1 knakahar return ENODEV; 656 1.1 knakahar 657 1.1 knakahar if (count > hw_max) { 658 1.1 knakahar DPRINTF(("over hardware max MSI-X count %d\n", hw_max)); 659 1.1 knakahar return EINVAL; 660 1.1 knakahar } 661 1.1 knakahar 662 1.1 knakahar /* check not to duplicate table_index */ 663 1.1 knakahar for (i = 0; i < count; i++) { 664 1.1 knakahar u_int basing = table_indexes[i]; 665 1.1 knakahar 666 1.1 knakahar KASSERT(table_indexes[i] < PCI_MSIX_MAX_VECTORS); 667 1.1 knakahar if (basing >= hw_max) { 668 1.1 knakahar DPRINTF(("table index is over hardware max MSI-X index %d\n", 669 1.1 knakahar hw_max - 1)); 670 1.1 knakahar return EINVAL; 671 1.1 knakahar } 672 1.1 knakahar 673 1.1 knakahar for (j = i + 1; j < count; j++) { 674 1.1 knakahar if (basing == table_indexes[j]) { 675 1.1 knakahar DPRINTF(("MSI-X table index duplicated\n")); 676 1.1 knakahar return EINVAL; 677 1.1 knakahar } 678 1.1 knakahar } 679 1.1 knakahar } 680 1.1 knakahar 681 1.4 knakahar return x86_pci_msix_alloc_map(ihps, table_indexes, count, pa); 682 1.1 knakahar } 683 1.10 knakahar #endif /* __HAVE_PCI_MSI_MSIX */ 684