FreeBSD/sys/dev/pci/pci.c
/*
 * Attempt to allocate *count MSI-X messages.  The actual number allocated is
 * returned in *count.  After this function returns, each message will be
 * available to the driver as SYS_RES_IRQ resources starting at rid 1.
 */
Attempt to allocate *count MSI-X messages.  The actual number allocated is
returned in *count.  After this function returns, each message will be
available to the driver as SYS_RES_IRQ resources starting at rid 1.
Attempt to allocate * count MSI - X messages . The actual number allocated is returned in * count . After this function returns each message will be available to the driver as SYS_RES_IRQ resources starting at rid 1 .
int
pci_alloc_msix_method(device_t dev, device_t child, int *count)
{
	struct pci_devinfo *dinfo = device_get_ivars(child);
	pcicfgregs *cfg = &dinfo->cfg;
	struct resource_list_entry *rle;
	int actual, error, i, irq, max;
	if (*count == 0)
		return (EINVAL);
	rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
	if (rle != NULL && rle->res != NULL)
		return (ENXIO);
	if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
		return (ENXIO);
	if (pci_msix_blacklisted())
		return (ENXIO);
	if (cfg->msix.msix_location == 0 || !pci_do_msix)
		return (ENODEV);
	rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
	    cfg->msix.msix_table_bar);
	if (rle == NULL || rle->res == NULL ||
	    !(rman_get_flags(rle->res) & RF_ACTIVE))
		return (ENXIO);
	cfg->msix.msix_table_res = rle->res;
	if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) {
		rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
		    cfg->msix.msix_pba_bar);
		if (rle == NULL || rle->res == NULL ||
		    !(rman_get_flags(rle->res) & RF_ACTIVE))
			return (ENXIO);
	}
	cfg->msix.msix_pba_res = rle->res;
	if (bootverbose)
		device_printf(child,
		    "attempting to allocate %d MSI-X vectors (%d supported)\n",
		    *count, cfg->msix.msix_msgnum);
	max = min(*count, cfg->msix.msix_msgnum);
	for (i = 0; i < max; i++) {
		error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq);
		if (error) {
			if (i == 0)
				return (error);
			break;
		}
		resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
		    irq, 1);
	}
	actual = i;
	if (bootverbose) {
		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
		if (actual == 1)
			device_printf(child, "using IRQ %ju for MSI-X\n",
			    rle->start);
		else {
			int run;
			device_printf(child, "using IRQs %ju", rle->start);
			irq = rle->start;
			run = 0;
			for (i = 1; i < actual; i++) {
				rle = resource_list_find(&dinfo->resources,
				    SYS_RES_IRQ, i + 1);
				if (rle->start == irq + 1) {
					run = 1;
					irq++;
					continue;
				}
				if (run) {
					printf("-%d", irq);
					run = 0;
				}
				printf(",%ju", rle->start);
				irq = rle->start;
			}
			if (run)
				printf("-%d", irq);
			printf(" for MSI-X\n");
		}
	}
	for (i = 0; i < cfg->msix.msix_msgnum; i++)
		pci_mask_msix(child, i);
	cfg->msix.msix_vectors = malloc(sizeof(struct msix_vector) * actual,
	    M_DEVBUF, M_WAITOK | M_ZERO);
	cfg->msix.msix_table = malloc(sizeof(struct msix_table_entry) * actual,
	    M_DEVBUF, M_WAITOK | M_ZERO);
	for (i = 0; i < actual; i++) {
		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
		cfg->msix.msix_vectors[i].mv_irq = rle->start;
		cfg->msix.msix_table[i].mte_vector = i + 1;
	}
	cfg->msix.msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
	pci_write_config(child, cfg->msix.msix_location + PCIR_MSIX_CTRL,
	    cfg->msix.msix_ctrl, 2);
	cfg->msix.msix_alloc = actual;
	cfg->msix.msix_table_len = actual;
	*count = actual;
	return (0);
}
int pci_alloc_msix_method ( device_t dev , device_t child , int * count ) { struct pci_devinfo * dinfo = device_get_ivars ( child ) ; pcicfgregs * cfg = & dinfo -> cfg ; struct resource_list_entry * rle ; int actual , error , i , irq , max ; if ( * count == 0 ) return ( EINVAL ) ; rle = resource_list_find ( & dinfo -> resources , SYS_RES_IRQ , 0 ) ; if ( rle != NULL && rle -> res != NULL ) return ( ENXIO ) ; if ( cfg -> msi . msi_alloc != 0 || cfg -> msix . msix_alloc != 0 ) return ( ENXIO ) ; if ( pci_msix_blacklisted ( ) ) return ( ENXIO ) ; if ( cfg -> msix . msix_location == 0 || ! pci_do_msix ) return ( ENODEV ) ; rle = resource_list_find ( & dinfo -> resources , SYS_RES_MEMORY , cfg -> msix . msix_table_bar ) ; if ( rle == NULL || rle -> res == NULL || ! ( rman_get_flags ( rle -> res ) & RF_ACTIVE ) ) return ( ENXIO ) ; cfg -> msix . msix_table_res = rle -> res ; if ( cfg -> msix . msix_pba_bar != cfg -> msix . msix_table_bar ) { rle = resource_list_find ( & dinfo -> resources , SYS_RES_MEMORY , cfg -> msix . msix_pba_bar ) ; if ( rle == NULL || rle -> res == NULL || ! ( rman_get_flags ( rle -> res ) & RF_ACTIVE ) ) return ( ENXIO ) ; } cfg -> msix . msix_pba_res = rle -> res ; if ( bootverbose ) device_printf ( child , " \n " , * count , cfg -> msix . msix_msgnum ) ; max = min ( * count , cfg -> msix . msix_msgnum ) ; for ( i = 0 ; i < max ; i ++ ) { error = PCIB_ALLOC_MSIX ( device_get_parent ( dev ) , child , & irq ) ; if ( error ) { if ( i == 0 ) return ( error ) ; break ; } resource_list_add ( & dinfo -> resources , SYS_RES_IRQ , i + 1 , irq , irq , 1 ) ; } actual = i ; if ( bootverbose ) { rle = resource_list_find ( & dinfo -> resources , SYS_RES_IRQ , 1 ) ; if ( actual == 1 ) device_printf ( child , " \n " , rle -> start ) ; else { int run ; device_printf ( child , " " , rle -> start ) ; irq = rle -> start ; run = 0 ; for ( i = 1 ; i < actual ; i ++ ) { rle = resource_list_find ( & dinfo -> resources , SYS_RES_IRQ , i + 1 ) ; if ( rle -> start == irq + 1 ) { run = 1 ; irq ++ ; continue ; } if ( run ) { printf ( " " , irq ) ; run = 0 ; } printf ( " " , rle -> start ) ; irq = rle -> start ; } if ( run ) printf ( " " , irq ) ; printf ( " \n " ) ; } } for ( i = 0 ; i < cfg -> msix . msix_msgnum ; i ++ ) pci_mask_msix ( child , i ) ; cfg -> msix . msix_vectors = malloc ( sizeof ( struct msix_vector ) * actual , M_DEVBUF , M_WAITOK | M_ZERO ) ; cfg -> msix . msix_table = malloc ( sizeof ( struct msix_table_entry ) * actual , M_DEVBUF , M_WAITOK | M_ZERO ) ; for ( i = 0 ; i < actual ; i ++ ) { rle = resource_list_find ( & dinfo -> resources , SYS_RES_IRQ , i + 1 ) ; cfg -> msix . msix_vectors [ i ] . mv_irq = rle -> start ; cfg -> msix . msix_table [ i ] . mte_vector = i + 1 ; } cfg -> msix . msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE ; pci_write_config ( child , cfg -> msix . msix_location + PCIR_MSIX_CTRL , cfg -> msix . msix_ctrl , 2 ) ; cfg -> msix . msix_alloc = actual ; cfg -> msix . msix_table_len = actual ; * count = actual ; return ( 0 ) ; }
Attempt to allocate *count MSI-X messages.
Attempt to allocate * count MSI - X messages .
/* Don't let count == 0 get us into trouble. */ /* If rid 0 is allocated, then fail. */ /* Already have allocated messages? */ /* If MSI-X is blacklisted for this system, fail. */ /* MSI-X capability present? */ /* Make sure the appropriate BARs are mapped. */ /* Allocate a message. */ /*
			 * Be fancy and try to print contiguous runs of
			 * IRQ values as ranges.  'irq' is the previous IRQ.
			 * 'run' is true if we are in a range.
			 */ /* Still in a run? */ /* Finish previous range. */ /* Start new range. */ /* Unfinished range? */ /* Mask all vectors. */ /* Allocate and initialize vector data and virtual table. */ /* Update control register to enable MSI-X. */ /* Update counts of alloc'd messages. */