FreeBSD/sys/arm/arm/pmap-v4.c
/*
 * Returns a pointer to the L2 bucket associated with the specified pmap
 * and VA.
 *
 * If no L2 bucket exists, perform the necessary allocations to put an L2
 * bucket/page table in place.
 *
 * Note that if a new L2 bucket/page was allocated, the caller *must*
 * increment the bucket occupancy counter appropriately *before*
 * releasing the pmap's lock to ensure no other thread or cpu deallocates
 * the bucket/page in the meantime.
 */
Returns a pointer to the L2 bucket associated with the specified pmap
and VA.

If no L2 bucket exists, perform the necessary allocations to put an L2
bucket/page table in place.

Note that if a new L2 bucket/page was allocated, the caller *must
increment the bucket occupancy counter appropriately *before
releasing the pmap's lock to ensure no other thread or cpu deallocates
the bucket/page in the meantime.
Returns a pointer to the L2 bucket associated with the specified pmap and VA . If no L2 bucket exists perform the necessary allocations to put an L2 bucket / page table in place . Note that if a new L2 bucket / page was allocated the caller * must increment the bucket occupancy counter appropriately * before releasing the pmap ' s lock to ensure no other thread or cpu deallocates the bucket / page in the meantime .
static struct l2_bucket *
pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
{
	struct l2_dtable *l2;
	struct l2_bucket *l2b;
	u_short l1idx;
	l1idx = L1_IDX(va);
	PMAP_ASSERT_LOCKED(pm);
	rw_assert(&pvh_global_lock, RA_WLOCKED);
	if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
		PMAP_UNLOCK(pm);
		rw_wunlock(&pvh_global_lock);
		if ((l2 = uma_zalloc(l2table_zone, M_NOWAIT)) == NULL) {
			rw_wlock(&pvh_global_lock);
			PMAP_LOCK(pm);
			return (NULL);
		}
		rw_wlock(&pvh_global_lock);
		PMAP_LOCK(pm);
		if (pm->pm_l2[L2_IDX(l1idx)] != NULL) {
			uma_zfree(l2table_zone, l2);
			l2 = pm->pm_l2[L2_IDX(l1idx)];
		} else {
			bzero(l2, sizeof(*l2));
			pm->pm_l2[L2_IDX(l1idx)] = l2;
		}
	}
	l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
	if (l2b->l2b_kva == NULL) {
		pt_entry_t *ptep;
		l2->l2_occupancy++;
		PMAP_UNLOCK(pm);
		rw_wunlock(&pvh_global_lock);
		ptep = uma_zalloc(l2zone, M_NOWAIT);
		rw_wlock(&pvh_global_lock);
		PMAP_LOCK(pm);
		if (l2b->l2b_kva != NULL) {
			l2->l2_occupancy--;
			uma_zfree(l2zone, ptep);
			return (l2b);
		}
		l2b->l2b_phys = vtophys(ptep);
		if (ptep == NULL) {
			l2->l2_occupancy--;
			if (l2->l2_occupancy == 0) {
				pm->pm_l2[L2_IDX(l1idx)] = NULL;
				uma_zfree(l2table_zone, l2);
			}
			return (NULL);
		}
		l2b->l2b_kva = ptep;
		l2b->l2b_l1idx = l1idx;
	}
	return (l2b);
}
static struct l2_bucket * pmap_alloc_l2_bucket ( pmap_t pm , vm_offset_t va ) { struct l2_dtable * l2 ; struct l2_bucket * l2b ; u_short l1idx ; l1idx = L1_IDX ( va ) ; PMAP_ASSERT_LOCKED ( pm ) ; rw_assert ( & pvh_global_lock , RA_WLOCKED ) ; if ( ( l2 = pm -> pm_l2 [ L2_IDX ( l1idx ) ] ) == NULL ) { PMAP_UNLOCK ( pm ) ; rw_wunlock ( & pvh_global_lock ) ; if ( ( l2 = uma_zalloc ( l2table_zone , M_NOWAIT ) ) == NULL ) { rw_wlock ( & pvh_global_lock ) ; PMAP_LOCK ( pm ) ; return ( NULL ) ; } rw_wlock ( & pvh_global_lock ) ; PMAP_LOCK ( pm ) ; if ( pm -> pm_l2 [ L2_IDX ( l1idx ) ] != NULL ) { uma_zfree ( l2table_zone , l2 ) ; l2 = pm -> pm_l2 [ L2_IDX ( l1idx ) ] ; } else { bzero ( l2 , sizeof ( * l2 ) ) ; pm -> pm_l2 [ L2_IDX ( l1idx ) ] = l2 ; } } l2b = & l2 -> l2_bucket [ L2_BUCKET ( l1idx ) ] ; if ( l2b -> l2b_kva == NULL ) { pt_entry_t * ptep ; l2 -> l2_occupancy ++ ; PMAP_UNLOCK ( pm ) ; rw_wunlock ( & pvh_global_lock ) ; ptep = uma_zalloc ( l2zone , M_NOWAIT ) ; rw_wlock ( & pvh_global_lock ) ; PMAP_LOCK ( pm ) ; if ( l2b -> l2b_kva != NULL ) { l2 -> l2_occupancy -- ; uma_zfree ( l2zone , ptep ) ; return ( l2b ) ; } l2b -> l2b_phys = vtophys ( ptep ) ; if ( ptep == NULL ) { l2 -> l2_occupancy -- ; if ( l2 -> l2_occupancy == 0 ) { pm -> pm_l2 [ L2_IDX ( l1idx ) ] = NULL ; uma_zfree ( l2table_zone , l2 ) ; } return ( NULL ) ; } l2b -> l2b_kva = ptep ; l2b -> l2b_l1idx = l1idx ; } return ( l2b ) ; }
Returns a pointer to the L2 bucket associated with the specified pmap
 and VA.
Returns a pointer to the L2 bucket associated with the specified pmap and VA .
/*
		 * No mapping at this address, as there is
		 * no entry in the L1 table.
		 * Need to allocate a new l2_dtable.
		 */ /*
			 * Someone already allocated the l2_dtable while
			 * we were doing the same.
			 */ /*
			 * Link it into the parent pmap
			 */ /*
	 * Fetch pointer to the L2 page table associated with the address.
	 */ /*
		 * No L2 page table has been allocated. Chances are, this
		 * is because we just allocated the l2_dtable, above.
		 */ /* We lost the race. */ /*
			 * Oops, no more L2 page tables available at this
			 * time. We may need to deallocate the l2_dtable
			 * if we allocated a new one above.
			 */