linux-old/arch/ppc/mm/mem_pieces.c
<<
>>
Prefs
   1/*
   2 *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
   3 *      Changes to accomodate Power Macintoshes.
   4 *    Cort Dougan <cort@cs.nmt.edu>
   5 *      Rewrites.
   6 *    Grant Erickson <grant@lcse.umn.edu>
   7 *      General rework and split from mm/init.c.
   8 *
   9 *    Module name: mem_pieces.c
  10 *
  11 *    Description:
  12 *      Routines and data structures for manipulating and representing
  13 *      phyiscal memory extents (i.e. address/length pairs).
  14 *
  15 */
  16
  17#include <linux/config.h>
  18#include <linux/kernel.h>
  19#include <linux/stddef.h>
  20#include <linux/blk.h>
  21#include <linux/init.h>
  22
  23#include "mem_pieces.h"
  24
  25extern struct mem_pieces phys_avail;
  26
  27static void mem_pieces_print(struct mem_pieces *);
  28
  29/*
  30 * Scan a region for a piece of a given size with the required alignment.
  31 */
  32void __init *
  33mem_pieces_find(unsigned int size, unsigned int align)
  34{
  35        int i;
  36        unsigned a, e;
  37        struct mem_pieces *mp = &phys_avail;
  38
  39        for (i = 0; i < mp->n_regions; ++i) {
  40                a = mp->regions[i].address;
  41                e = a + mp->regions[i].size;
  42                a = (a + align - 1) & -align;
  43                if (a + size <= e) {
  44                        mem_pieces_remove(mp, a, size, 1);
  45                        return __va(a);
  46                }
  47        }
  48        panic("Couldn't find %u bytes at %u alignment\n", size, align);
  49
  50        return NULL;
  51}
  52
  53/*
  54 * Remove some memory from an array of pieces
  55 */
  56void __init
  57mem_pieces_remove(struct mem_pieces *mp, unsigned int start, unsigned int size,
  58                  int must_exist)
  59{
  60        int i, j;
  61        unsigned int end, rs, re;
  62        struct reg_property *rp;
  63
  64        end = start + size;
  65        for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
  66                if (end > rp->address && start < rp->address + rp->size)
  67                        break;
  68        }
  69        if (i >= mp->n_regions) {
  70                if (must_exist)
  71                        printk("mem_pieces_remove: [%x,%x) not in any region\n",
  72                               start, end);
  73                return;
  74        }
  75        for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
  76                rs = rp->address;
  77                re = rs + rp->size;
  78                if (must_exist && (start < rs || end > re)) {
  79                        printk("mem_pieces_remove: bad overlap [%x,%x) with",
  80                               start, end);
  81                        mem_pieces_print(mp);
  82                        must_exist = 0;
  83                }
  84                if (start > rs) {
  85                        rp->size = start - rs;
  86                        if (end < re) {
  87                                /* need to split this entry */
  88                                if (mp->n_regions >= MEM_PIECES_MAX)
  89                                        panic("eek... mem_pieces overflow");
  90                                for (j = mp->n_regions; j > i + 1; --j)
  91                                        mp->regions[j] = mp->regions[j-1];
  92                                ++mp->n_regions;
  93                                rp[1].address = end;
  94                                rp[1].size = re - end;
  95                        }
  96                } else {
  97                        if (end < re) {
  98                                rp->address = end;
  99                                rp->size = re - end;
 100                        } else {
 101                                /* need to delete this entry */
 102                                for (j = i; j < mp->n_regions - 1; ++j)
 103                                        mp->regions[j] = mp->regions[j+1];
 104                                --mp->n_regions;
 105                                --i;
 106                                --rp;
 107                        }
 108                }
 109        }
 110}
 111
 112static void __init
 113mem_pieces_print(struct mem_pieces *mp)
 114{
 115        int i;
 116
 117        for (i = 0; i < mp->n_regions; ++i)
 118                printk(" [%x, %x)", mp->regions[i].address,
 119                       mp->regions[i].address + mp->regions[i].size);
 120        printk("\n");
 121}
 122
 123#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
 124/*
 125 * Add some memory to an array of pieces
 126 */
 127void __init
 128mem_pieces_append(struct mem_pieces *mp, unsigned int start, unsigned int size)
 129{
 130        struct reg_property *rp;
 131
 132        if (mp->n_regions >= MEM_PIECES_MAX)
 133                return;
 134        rp = &mp->regions[mp->n_regions++];
 135        rp->address = start;
 136        rp->size = size;
 137}
 138#endif /* CONFIG_APUS || CONFIG_ALL_PPC */
 139
 140void __init
 141mem_pieces_sort(struct mem_pieces *mp)
 142{
 143        unsigned long a, s;
 144        int i, j;
 145
 146        for (i = 1; i < mp->n_regions; ++i) {
 147                a = mp->regions[i].address;
 148                s = mp->regions[i].size;
 149                for (j = i - 1; j >= 0; --j) {
 150                        if (a >= mp->regions[j].address)
 151                                break;
 152                        mp->regions[j+1] = mp->regions[j];
 153                }
 154                mp->regions[j+1].address = a;
 155                mp->regions[j+1].size = s;
 156        }
 157}
 158
 159void __init
 160mem_pieces_coalesce(struct mem_pieces *mp)
 161{
 162        unsigned long a, s, ns;
 163        int i, j, d;
 164
 165        d = 0;
 166        for (i = 0; i < mp->n_regions; i = j) {
 167                a = mp->regions[i].address;
 168                s = mp->regions[i].size;
 169                for (j = i + 1; j < mp->n_regions
 170                             && mp->regions[j].address - a <= s; ++j) {
 171                        ns = mp->regions[j].address + mp->regions[j].size - a;
 172                        if (ns > s)
 173                                s = ns;
 174                }
 175                mp->regions[d].address = a;
 176                mp->regions[d].size = s;
 177                ++d;
 178        }
 179        mp->n_regions = d;
 180}
 181
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.