FreeBSD/sys/x86/x86/msi.c
/*
 * Try to allocate 'count' interrupt sources with contiguous IDT values.
 */
Try to allocate 'count' interrupt sources with contiguous IDT values.
Try to allocate ' count ' interrupt sources with contiguous IDT values .
int
msi_alloc(device_t dev, int count, int maxcount, int *irqs)
{
	struct msi_intsrc *msi, *fsrc;
	u_int cpu;
	int cnt, i, *mirqs, vector;
#ifdef ACPI_DMAR
	u_int cookies[count];
	int error;
#endif
	if (!msi_enabled)
		return (ENXIO);
	if (count > 1)
		mirqs = malloc(count * sizeof(*mirqs), M_MSI, M_WAITOK);
	else
		mirqs = NULL;
again:
	mtx_lock(&msi_lock);
	cnt = 0;
	for (i = FIRST_MSI_INT; i < FIRST_MSI_INT + NUM_MSI_INTS; i++) {
		msi = (struct msi_intsrc *)intr_lookup_source(i);
		if (msi == NULL)
			break;
		if (msi->msi_dev == NULL) {
			irqs[cnt] = i;
			cnt++;
			if (cnt == count)
				break;
		}
	}
	if (cnt < count) {
		if (i + (count - cnt) > FIRST_MSI_INT + NUM_MSI_INTS) {
			mtx_unlock(&msi_lock);
			free(mirqs, M_MSI);
			return (ENXIO);
		}
		mtx_unlock(&msi_lock);
		while (cnt < count) {
			msi_create_source();
			cnt++;
		}
		goto again;
	}
	KASSERT(cnt == count, ("count mismatch"));
	cpu = intr_next_cpu();
	vector = apic_alloc_vectors(cpu, irqs, count, maxcount);
	if (vector == 0) {
		mtx_unlock(&msi_lock);
		free(mirqs, M_MSI);
		return (ENOSPC);
	}
#ifdef ACPI_DMAR
	mtx_unlock(&msi_lock);
	error = iommu_alloc_msi_intr(dev, cookies, count);
	mtx_lock(&msi_lock);
	if (error == EOPNOTSUPP)
		error = 0;
	if (error != 0) {
		for (i = 0; i < count; i++)
			apic_free_vector(cpu, vector + i, irqs[i]);
		free(mirqs, M_MSI);
		return (error);
	}
	for (i = 0; i < count; i++) {
		msi = (struct msi_intsrc *)intr_lookup_source(irqs[i]);
		msi->msi_remap_cookie = cookies[i];
	}
#endif
	fsrc = (struct msi_intsrc *)intr_lookup_source(irqs[0]);
	for (i = 0; i < count; i++) {
		msi = (struct msi_intsrc *)intr_lookup_source(irqs[i]);
		msi->msi_cpu = cpu;
		msi->msi_dev = dev;
		msi->msi_vector = vector + i;
		if (bootverbose)
			printf(
		    "msi: routing MSI IRQ %d to local APIC %u vector %u\n",
			    msi->msi_irq, msi->msi_cpu, msi->msi_vector);
		msi->msi_first = fsrc;
		KASSERT(msi->msi_intsrc.is_handlers == 0,
		    ("dead MSI has handlers"));
	}
	fsrc->msi_count = count;
	fsrc->msi_maxcount = maxcount;
	if (count > 1)
		bcopy(irqs, mirqs, count * sizeof(*mirqs));
	fsrc->msi_irqs = mirqs;
	mtx_unlock(&msi_lock);
	return (0);
}
int msi_alloc ( device_t dev , int count , int maxcount , int * irqs ) { struct msi_intsrc * msi , * fsrc ; u_int cpu ; int cnt , i , * mirqs , vector ; #ifdef ACPI_DMAR u_int cookies [ count ] ; int error ; #endif if ( ! msi_enabled ) return ( ENXIO ) ; if ( count > 1 ) mirqs = malloc ( count * sizeof ( * mirqs ) , M_MSI , M_WAITOK ) ; else mirqs = NULL ; again : mtx_lock ( & msi_lock ) ; cnt = 0 ; for ( i = FIRST_MSI_INT ; i < FIRST_MSI_INT + NUM_MSI_INTS ; i ++ ) { msi = ( struct msi_intsrc * ) intr_lookup_source ( i ) ; if ( msi == NULL ) break ; if ( msi -> msi_dev == NULL ) { irqs [ cnt ] = i ; cnt ++ ; if ( cnt == count ) break ; } } if ( cnt < count ) { if ( i + ( count - cnt ) > FIRST_MSI_INT + NUM_MSI_INTS ) { mtx_unlock ( & msi_lock ) ; free ( mirqs , M_MSI ) ; return ( ENXIO ) ; } mtx_unlock ( & msi_lock ) ; while ( cnt < count ) { msi_create_source ( ) ; cnt ++ ; } goto again ; } KASSERT ( cnt == count , ( " " ) ) ; cpu = intr_next_cpu ( ) ; vector = apic_alloc_vectors ( cpu , irqs , count , maxcount ) ; if ( vector == 0 ) { mtx_unlock ( & msi_lock ) ; free ( mirqs , M_MSI ) ; return ( ENOSPC ) ; } #ifdef ACPI_DMAR mtx_unlock ( & msi_lock ) ; error = iommu_alloc_msi_intr ( dev , cookies , count ) ; mtx_lock ( & msi_lock ) ; if ( error == EOPNOTSUPP ) error = 0 ; if ( error != 0 ) { for ( i = 0 ; i < count ; i ++ ) apic_free_vector ( cpu , vector + i , irqs [ i ] ) ; free ( mirqs , M_MSI ) ; return ( error ) ; } for ( i = 0 ; i < count ; i ++ ) { msi = ( struct msi_intsrc * ) intr_lookup_source ( irqs [ i ] ) ; msi -> msi_remap_cookie = cookies [ i ] ; } #endif fsrc = ( struct msi_intsrc * ) intr_lookup_source ( irqs [ 0 ] ) ; for ( i = 0 ; i < count ; i ++ ) { msi = ( struct msi_intsrc * ) intr_lookup_source ( irqs [ i ] ) ; msi -> msi_cpu = cpu ; msi -> msi_dev = dev ; msi -> msi_vector = vector + i ; if ( bootverbose ) printf ( " \n " , msi -> msi_irq , msi -> msi_cpu , msi -> msi_vector ) ; msi -> msi_first = fsrc ; KASSERT ( msi -> msi_intsrc . is_handlers == 0 , ( " " ) ) ; } fsrc -> msi_count = count ; fsrc -> msi_maxcount = maxcount ; if ( count > 1 ) bcopy ( irqs , mirqs , count * sizeof ( * mirqs ) ) ; fsrc -> msi_irqs = mirqs ; mtx_unlock ( & msi_lock ) ; return ( 0 ) ; }
Try to allocate 'count' interrupt sources with contiguous IDT values.
Try to allocate ' count ' interrupt sources with contiguous IDT values .
/* Try to find 'count' free IRQs. */ /* End of allocated sources, so break. */ /* If this is a free one, save its IRQ in the array. */ /* Do we need to create some new sources? */ /* If we would exceed the max, give up. */ /* We need count - cnt more sources. */ /* Ok, we now have the IRQs allocated. */ /* Allocate 'count' IDT vectors. */ /* Assign IDT vectors and make these messages owned by 'dev'. */