david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[hermon] Minimise the number of VPM mapping operations

Mapping a single page at a time causes a several-second delay at
device initialisation time.  Reduce this by mapping multiple pages at
a time, using the largest block sizes possible given the alignment
constraints.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2010-09-18 22:37:54 +01:00
parent 8cd2b170b6
commit 92ced72080
1 changed files with 39 additions and 7 deletions

View File

@ -2136,35 +2136,67 @@ static int hermon_map_vpm ( struct hermon *hermon,
const struct hermonprm_virtual_physical_mapping* ),
uint64_t va, physaddr_t pa, size_t len ) {
struct hermonprm_virtual_physical_mapping mapping;
physaddr_t start;
physaddr_t low;
physaddr_t high;
physaddr_t end;
size_t size;
int rc;
/* Sanity checks */
assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
assert ( ( len & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
/* Calculate starting points */
start = pa;
end = ( start + len );
size = ( 1UL << ( fls ( start ^ end ) - 1 ) );
low = high = ( end & ~( size - 1 ) );
assert ( start < low );
assert ( high <= end );
/* These mappings tend to generate huge volumes of
* uninteresting debug data, which basically makes it
* impossible to use debugging otherwise.
*/
DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
while ( len ) {
/* Map blocks in descending order of size */
while ( size >= HERMON_PAGE_SIZE ) {
/* Find the next candidate block */
if ( ( low - size ) >= start ) {
low -= size;
pa = low;
} else if ( ( high + size ) <= end ) {
pa = high;
high += size;
} else {
size >>= 1;
continue;
}
assert ( ( va & ( size - 1 ) ) == 0 );
assert ( ( pa & ( size - 1 ) ) == 0 );
/* Map this block */
memset ( &mapping, 0, sizeof ( mapping ) );
MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
MLX_FILL_2 ( &mapping, 3,
log2size, 0,
log2size, ( ( fls ( size ) - 1 ) - 12 ),
pa_l, ( pa >> 12 ) );
if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
DBGC ( hermon, "Hermon %p could not map %llx => %lx: "
"%s\n", hermon, va, pa, strerror ( rc ) );
DBGC ( hermon, "Hermon %p could not map %08llx+%zx to "
"%08lx: %s\n",
hermon, va, size, pa, strerror ( rc ) );
return rc;
}
pa += HERMON_PAGE_SIZE;
va += HERMON_PAGE_SIZE;
len -= HERMON_PAGE_SIZE;
va += size;
}
assert ( low == start );
assert ( high == end );
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
return 0;