Changeset 24424

Show
Ignore:
Timestamp:
03/17/08 15:50:46 (8 months ago)
Author:
korli
Message:

algorithm to find best suited mtrr values to match a memory region. tested ok with 3071MB.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • haiku/trunk/src/system/kernel/arch/x86/arch_vm.cpp

    r24244 r24424  
    3232#endif 
    3333 
     34#define TRACE_MTRR_ARCH_VM 
     35#ifdef TRACE_MTRR_ARCH_VM 
     36#       define TRACE_MTRR(x...) dprintf(x) 
     37#else 
     38#       define TRACE_MTRR(x...)  
     39#endif 
     40 
    3441 
    3542#define kMaxMemoryTypeRegisters 32 
     
    8491 
    8592 
     93static void 
     94nearest_powers(uint64 value, uint64 *lower, uint64 *upper) 
     95{ 
     96        uint64 power = 1UL << 12; 
     97        *lower = power; 
     98                // 12 bits is the smallest supported alignment/length 
     99 
     100        while (value >= power) { 
     101                *lower = power; 
     102                power <<= 1; 
     103        } 
     104 
     105        *upper = power; 
     106} 
     107 
     108 
    86109static status_t 
    87110set_memory_type(int32 id, uint64 base, uint64 length, uint32 type) 
     
    92115                return B_OK; 
    93116 
    94         uint32 newType; 
    95  
    96117        switch (type) { 
    97118                case B_MTR_UC: 
    98                         newType = IA32_MTR_UNCACHED; 
     119                        type = IA32_MTR_UNCACHED; 
    99120                        break; 
    100121                case B_MTR_WC: 
    101                         newType = IA32_MTR_WRITE_COMBINING; 
     122                        type = IA32_MTR_WRITE_COMBINING; 
    102123                        break; 
    103124                case B_MTR_WT: 
    104                         newType = IA32_MTR_WRITE_THROUGH; 
     125                        type = IA32_MTR_WRITE_THROUGH; 
    105126                        break; 
    106127                case B_MTR_WP: 
    107                         newType = IA32_MTR_WRITE_PROTECTED; 
     128                        type = IA32_MTR_WRITE_PROTECTED; 
    108129                        break; 
    109130                case B_MTR_WB: 
    110                         newType = IA32_MTR_WRITE_BACK; 
     131                        type = IA32_MTR_WRITE_BACK; 
    111132                        break; 
    112133 
     
    119140 
    120141        // length must be a power of 2; just round it up to the next value 
    121         uint64 newLength = nearest_power(length); 
    122  
    123         // avoids more than 2GB slots 
    124         if (newLength > 0x80000000) 
    125                 newLength = 0x80000000; 
    126  
    127         if (newLength + base <= base) { 
     142        length = nearest_power(length);          
     143 
     144        if (length + base <= base) { 
    128145                // 4GB overflow 
    129146                return B_BAD_VALUE; 
     
    131148 
    132149        // base must be aligned to the length 
    133         if (base & (newLength - 1)) 
     150        if (base & (length - 1)) 
    134151                return B_BAD_VALUE; 
    135152 
     
    138155                return B_ERROR; 
    139156 
    140         TRACE(("allocate MTRR slot %ld, base = %Lx, length = %Lx\n", index, 
    141                 base, newLength)); 
     157        TRACE_MTRR("allocate MTRR slot %ld, base = %Lx, length = %Lx\n", index, base, length); 
    142158 
    143159        sMemoryTypeIDs[index] = id; 
    144         x86_set_mtrr(index, base, newLength, newType); 
    145  
    146         // now handle remaining memory 
    147         if (length > newLength) { 
    148                 // TODO iterate over smaller lengths to avoid the PCI hole after the physical memory. 
    149                 set_memory_type(id, base + newLength, length - newLength, type); 
    150         } 
     160        x86_set_mtrr(index, base, length, type); 
    151161 
    152162        return B_OK; 
     163} 
     164 
     165 
     166static int64 sols[5]; 
     167static int solCount; 
     168static int64 props[5]; 
     169 
     170 
     171static void 
     172find_nearest(uint64 value, int iteration) 
     173{ 
     174        TRACE_MTRR("find_nearest %Lx %d\n", value, iteration); 
     175        if (iteration > 4 || (iteration + 1) >= solCount) 
     176                return; 
     177        uint64 down, up; 
     178        int i; 
     179        nearest_powers(value, &down, &up); 
     180        props[iteration] = down; 
     181        if (value - down < 0x100000) { 
     182                for (i=0; i<=iteration; i++) 
     183                        sols[i] = props[i]; 
     184                solCount = iteration + 1; 
     185                return; 
     186        } 
     187        find_nearest(value - down, iteration + 1); 
     188        props[iteration] = -up; 
     189        if (up - value < 0x100000) { 
     190                for (i=0; i<=iteration; i++) 
     191                        sols[i] = props[i]; 
     192                solCount = iteration + 1; 
     193                return; 
     194        } 
     195        find_nearest(up - value, iteration + 1); 
     196} 
     197 
     198 
     199static status_t 
     200set_memory_write_back(int32 id, uint64 base, uint64 length) 
     201{ 
     202        int i; 
     203        TRACE_MTRR("set_memory_write_back base %Lx length %Lx\n", base, length); 
     204        solCount = 5; 
     205        find_nearest(length, 0); 
     206 
     207#ifdef TRACE_MTRR 
     208        dprintf("sols: "); 
     209        for (i=0; i<solCount; i++) { 
     210                dprintf("0x%Lx ", sols[i]); 
     211        } 
     212        dprintf("\n"); 
     213#endif 
     214 
     215        bool nextDown = false; 
     216        for (int i = 0; i < solCount; i++) { 
     217                if (sols[i] < 0) { 
     218                        if (nextDown) 
     219                                base += sols[i]; 
     220                        set_memory_type(id, base, -sols[i], nextDown ? B_MTR_UC : B_MTR_WB); 
     221                        if (!nextDown) 
     222                                base -= sols[i]; 
     223                        nextDown = !nextDown; 
     224                } else { 
     225                        if (nextDown) 
     226                                base -= sols[i]; 
     227                        set_memory_type(id, base, sols[i], nextDown ? B_MTR_UC : B_MTR_WB); 
     228                        if (!nextDown) 
     229                                base += sols[i]; 
     230                } 
     231        } 
    153232} 
    154233 
     
    227306 
    228307        for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 
    229                 set_memory_type(-1, args->physical_memory_range[i].start, 
    230                         args->physical_memory_range[i].size, B_MTR_WB); 
     308                set_memory_write_back(-1, args->physical_memory_range[i].start, 
     309                        args->physical_memory_range[i].size); 
    231310        } 
    232311