[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:
parent
8cd2b170b6
commit
92ced72080
|
@ -2136,35 +2136,67 @@ static int hermon_map_vpm ( struct hermon *hermon,
|
||||||
const struct hermonprm_virtual_physical_mapping* ),
|
const struct hermonprm_virtual_physical_mapping* ),
|
||||||
uint64_t va, physaddr_t pa, size_t len ) {
|
uint64_t va, physaddr_t pa, size_t len ) {
|
||||||
struct hermonprm_virtual_physical_mapping mapping;
|
struct hermonprm_virtual_physical_mapping mapping;
|
||||||
|
physaddr_t start;
|
||||||
|
physaddr_t low;
|
||||||
|
physaddr_t high;
|
||||||
|
physaddr_t end;
|
||||||
|
size_t size;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
|
assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
|
||||||
assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
|
assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
|
||||||
assert ( ( len & ( 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
|
/* These mappings tend to generate huge volumes of
|
||||||
* uninteresting debug data, which basically makes it
|
* uninteresting debug data, which basically makes it
|
||||||
* impossible to use debugging otherwise.
|
* impossible to use debugging otherwise.
|
||||||
*/
|
*/
|
||||||
DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
|
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 ) );
|
memset ( &mapping, 0, sizeof ( mapping ) );
|
||||||
MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
|
MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
|
||||||
MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
|
MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
|
||||||
MLX_FILL_2 ( &mapping, 3,
|
MLX_FILL_2 ( &mapping, 3,
|
||||||
log2size, 0,
|
log2size, ( ( fls ( size ) - 1 ) - 12 ),
|
||||||
pa_l, ( pa >> 12 ) );
|
pa_l, ( pa >> 12 ) );
|
||||||
if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
|
if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
|
||||||
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
|
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
|
||||||
DBGC ( hermon, "Hermon %p could not map %llx => %lx: "
|
DBGC ( hermon, "Hermon %p could not map %08llx+%zx to "
|
||||||
"%s\n", hermon, va, pa, strerror ( rc ) );
|
"%08lx: %s\n",
|
||||||
|
hermon, va, size, pa, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
pa += HERMON_PAGE_SIZE;
|
va += size;
|
||||||
va += HERMON_PAGE_SIZE;
|
|
||||||
len -= HERMON_PAGE_SIZE;
|
|
||||||
}
|
}
|
||||||
|
assert ( low == start );
|
||||||
|
assert ( high == end );
|
||||||
|
|
||||||
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
|
DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Reference in New Issue