FreeBSD/sys/dev/pci/pci.c
/*
 * Attempt to allocate *count MSI 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 a rid 1.
 */
Attempt to allocate *count MSI 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 a rid 1.
Attempt to allocate * count MSI 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 a rid 1 .
int
pci_alloc_msi_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, irqs[32];
	uint16_t ctrl;
	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_msi_blacklisted())
		return (ENXIO);
	if (cfg->msi.msi_location == 0 || !pci_do_msi)
		return (ENODEV);
	if (bootverbose)
		device_printf(child,
		    "attempting to allocate %d MSI vectors (%d supported)\n",
		    *count, cfg->msi.msi_msgnum);
	actual = min(*count, cfg->msi.msi_msgnum);
	actual = min(actual, 32);
	if (!powerof2(actual))
		return (EINVAL);
	for (;;) {
		error = PCIB_ALLOC_MSI(device_get_parent(dev), child, actual,
		    actual, irqs);
		if (error == 0)
			break;
		if (actual == 1)
			return (error);
		actual >>= 1;
	}
	for (i = 0; i < actual; i++)
		resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1,
		    irqs[i], irqs[i], 1);
	if (bootverbose) {
		if (actual == 1)
			device_printf(child, "using IRQ %d for MSI\n", irqs[0]);
		else {
			int run;
			device_printf(child, "using IRQs %d", irqs[0]);
			run = 0;
			for (i = 1; i < actual; i++) {
				if (irqs[i] == irqs[i - 1] + 1) {
					run = 1;
					continue;
				}
				if (run) {
					printf("-%d", irqs[i - 1]);
					run = 0;
				}
				printf(",%d", irqs[i]);
			}
			if (run)
				printf("-%d", irqs[actual - 1]);
			printf(" for MSI\n");
		}
	}
	ctrl = cfg->msi.msi_ctrl;
	ctrl &= ~PCIM_MSICTRL_MME_MASK;
	ctrl |= (ffs(actual) - 1) << 4;
	cfg->msi.msi_ctrl = ctrl;
	pci_write_config(child, cfg->msi.msi_location + PCIR_MSI_CTRL, ctrl, 2);
	cfg->msi.msi_alloc = actual;
	cfg->msi.msi_handlers = 0;
	*count = actual;
	return (0);
}
int pci_alloc_msi_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 , irqs [ 32 ] ; uint16_t ctrl ; 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_msi_blacklisted ( ) ) return ( ENXIO ) ; if ( cfg -> msi . msi_location == 0 || ! pci_do_msi ) return ( ENODEV ) ; if ( bootverbose ) device_printf ( child , " \n " , * count , cfg -> msi . msi_msgnum ) ; actual = min ( * count , cfg -> msi . msi_msgnum ) ; actual = min ( actual , 32 ) ; if ( ! powerof2 ( actual ) ) return ( EINVAL ) ; for ( ; ; ) { error = PCIB_ALLOC_MSI ( device_get_parent ( dev ) , child , actual , actual , irqs ) ; if ( error == 0 ) break ; if ( actual == 1 ) return ( error ) ; actual >>= 1 ; } for ( i = 0 ; i < actual ; i ++ ) resource_list_add ( & dinfo -> resources , SYS_RES_IRQ , i + 1 , irqs [ i ] , irqs [ i ] , 1 ) ; if ( bootverbose ) { if ( actual == 1 ) device_printf ( child , " \n " , irqs [ 0 ] ) ; else { int run ; device_printf ( child , " " , irqs [ 0 ] ) ; run = 0 ; for ( i = 1 ; i < actual ; i ++ ) { if ( irqs [ i ] == irqs [ i - 1 ] + 1 ) { run = 1 ; continue ; } if ( run ) { printf ( " " , irqs [ i - 1 ] ) ; run = 0 ; } printf ( " " , irqs [ i ] ) ; } if ( run ) printf ( " " , irqs [ actual - 1 ] ) ; printf ( " \n " ) ; } } ctrl = cfg -> msi . msi_ctrl ; ctrl &= ~ PCIM_MSICTRL_MME_MASK ; ctrl |= ( ffs ( actual ) - 1 ) << 4 ; cfg -> msi . msi_ctrl = ctrl ; pci_write_config ( child , cfg -> msi . msi_location + PCIR_MSI_CTRL , ctrl , 2 ) ; cfg -> msi . msi_alloc = actual ; cfg -> msi . msi_handlers = 0 ; * count = actual ; return ( 0 ) ; }
Attempt to allocate *count MSI messages.
Attempt to allocate * count MSI messages .
/* Don't let count == 0 get us into trouble. */ /* If rid 0 is allocated, then fail. */ /* Already have allocated messages? */ /* If MSI is blacklisted for this system, fail. */ /* MSI capability present? */ /* Don't ask for more than the device supports. */ /* Don't ask for more than 32 messages. */ /* MSI requires power of 2 number of messages. */ /* Try to allocate N messages. */ /* Try N / 2. */ /*
	 * We now have N actual messages mapped onto SYS_RES_IRQ
	 * resources in the irqs[] array, so add new resources
	 * starting at rid 1.
	 */ /*
			 * Be fancy and try to print contiguous runs
			 * of IRQ values as ranges.  'run' is true if
			 * we are in a range.
			 */ /* Still in a run? */ /* Finish previous range. */ /* Start new range. */ /* Unfinished range? */ /* Update control register with actual count. */ /* Update counts of alloc'd messages. */