/* change all active ASCEs to avoid the creation of new TLBs */ if (current->active_mm == mm) {
asce.val = mm->context.asce;
get_lowcore()->user_asce = asce;
local_ctl_load(7, &asce); if (!test_thread_flag(TIF_ASCE_PRIMARY))
local_ctl_load(1, &asce);
}
__tlb_flush_local();
}
if (!alloc) return 0;
pte = origin;
pte += (addr & _PAGE_INDEX) >> PAGE_SHIFT; do {
next = base_page_addr_end(addr, end);
*pte = base_lra(addr);
} while (pte++, addr = next, addr < end); return 0;
}
staticint base_segment_walk(unsignedlong *origin, unsignedlong addr, unsignedlong end, int alloc)
{ unsignedlong *ste, next, *table; int rc;
ste = origin;
ste += (addr & _SEGMENT_INDEX) >> _SEGMENT_SHIFT; do {
next = base_segment_addr_end(addr, end); if (*ste & _SEGMENT_ENTRY_INVALID) { if (!alloc) continue;
table = base_pgt_alloc(); if (!table) return -ENOMEM;
*ste = __pa(table) | _SEGMENT_ENTRY;
}
table = __va(*ste & _SEGMENT_ENTRY_ORIGIN);
rc = base_page_walk(table, addr, next, alloc); if (rc) return rc; if (!alloc)
base_pgt_free(table);
cond_resched();
} while (ste++, addr = next, addr < end); return 0;
}
staticint base_region3_walk(unsignedlong *origin, unsignedlong addr, unsignedlong end, int alloc)
{ unsignedlong *rtte, next, *table; int rc;
rtte = origin;
rtte += (addr & _REGION3_INDEX) >> _REGION3_SHIFT; do {
next = base_region3_addr_end(addr, end); if (*rtte & _REGION_ENTRY_INVALID) { if (!alloc) continue;
table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY); if (!table) return -ENOMEM;
*rtte = __pa(table) | _REGION3_ENTRY;
}
table = __va(*rtte & _REGION_ENTRY_ORIGIN);
rc = base_segment_walk(table, addr, next, alloc); if (rc) return rc; if (!alloc)
base_crst_free(table);
} while (rtte++, addr = next, addr < end); return 0;
}
staticint base_region2_walk(unsignedlong *origin, unsignedlong addr, unsignedlong end, int alloc)
{ unsignedlong *rste, next, *table; int rc;
rste = origin;
rste += (addr & _REGION2_INDEX) >> _REGION2_SHIFT; do {
next = base_region2_addr_end(addr, end); if (*rste & _REGION_ENTRY_INVALID) { if (!alloc) continue;
table = base_crst_alloc(_REGION3_ENTRY_EMPTY); if (!table) return -ENOMEM;
*rste = __pa(table) | _REGION2_ENTRY;
}
table = __va(*rste & _REGION_ENTRY_ORIGIN);
rc = base_region3_walk(table, addr, next, alloc); if (rc) return rc; if (!alloc)
base_crst_free(table);
} while (rste++, addr = next, addr < end); return 0;
}
staticint base_region1_walk(unsignedlong *origin, unsignedlong addr, unsignedlong end, int alloc)
{ unsignedlong *rfte, next, *table; int rc;
rfte = origin;
rfte += (addr & _REGION1_INDEX) >> _REGION1_SHIFT; do {
next = base_region1_addr_end(addr, end); if (*rfte & _REGION_ENTRY_INVALID) { if (!alloc) continue;
table = base_crst_alloc(_REGION2_ENTRY_EMPTY); if (!table) return -ENOMEM;
*rfte = __pa(table) | _REGION1_ENTRY;
}
table = __va(*rfte & _REGION_ENTRY_ORIGIN);
rc = base_region2_walk(table, addr, next, alloc); if (rc) return rc; if (!alloc)
base_crst_free(table);
} while (rfte++, addr = next, addr < end); return 0;
}
/** * base_asce_free - free asce and tables returned from base_asce_alloc() * @asce: asce to be freed * * Frees all region, segment, and page tables that were allocated with a * corresponding base_asce_alloc() call.
*/ void base_asce_free(unsignedlong asce)
{ unsignedlong *table = __va(asce & _ASCE_ORIGIN);
if (!asce) return; switch (asce & _ASCE_TYPE_MASK) { case _ASCE_TYPE_SEGMENT:
base_segment_walk(table, 0, _REGION3_SIZE, 0); break; case _ASCE_TYPE_REGION3:
base_region3_walk(table, 0, _REGION2_SIZE, 0); break; case _ASCE_TYPE_REGION2:
base_region2_walk(table, 0, _REGION1_SIZE, 0); break; case _ASCE_TYPE_REGION1:
base_region1_walk(table, 0, TASK_SIZE_MAX, 0); break;
}
base_crst_free(table);
}
/** * base_asce_alloc - create kernel mapping without enhanced DAT features * @addr: virtual start address of kernel mapping * @num_pages: number of consecutive pages * * Generate an asce, including all required region, segment and page tables, * that can be used to access the virtual kernel mapping. The difference is * that the returned asce does not make use of any enhanced DAT features like * e.g. large pages. This is required for some I/O functions that pass an * asce, like e.g. some service call requests. * * Note: the returned asce may NEVER be attached to any cpu. It may only be * used for I/O requests. tlb entries that might result because the * asce was attached to a cpu won't be cleared.
*/ unsignedlong base_asce_alloc(unsignedlong addr, unsignedlong num_pages)
{ unsignedlong asce, *table, end; int rc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.