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