]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[hermon] Minimise the number of VPM mapping operations
authorMichael Brown <mcb30@ipxe.org>
Sat, 18 Sep 2010 21:37:54 +0000 (22:37 +0100)
committerMichael Brown <mcb30@ipxe.org>
Sat, 18 Sep 2010 22:20:50 +0000 (23:20 +0100)
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>
src/drivers/infiniband/hermon.c

index cebfb178e94e4ae7f1935a8e89fbe5ee5eb41075..ade6f43a72d6a8a0b9228a9eadd15fe88687ecd6 100644 (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;