patch-2.1.79 linux/arch/ppc/mm/init.c
Next file: linux/arch/ppc/pmac_defconfig
Previous file: linux/arch/ppc/mm/fault.c
Back to the patch index
Back to the overall index
- Lines: 1250
- Date:
Mon Jan 12 15:18:13 1998
- Orig file:
v2.1.78/linux/arch/ppc/mm/init.c
- Orig date:
Thu Sep 4 17:07:30 1997
diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
@@ -53,21 +53,11 @@
extern char etext[], _stext[];
extern char __init_begin, __init_end;
extern RESIDUAL res;
-
-/* Hardwired MMU segments */
-#if defined(CONFIG_PREP) || defined(CONFIG_PMAC)
-#define MMU_SEGMENT_1 0x80000000
-#define MMU_SEGMENT_2 0xc0000000
-#endif /* CONFIG_PREP || CONFIG_PMAC */
-#ifdef CONFIG_CHRP
-#define MMU_SEGMENT_1 0xf0000000 /* LongTrail */
-#define MMU_SEGMENT_2 0xc0000000
-#endif /* CONFIG_CHRP */
-
+char *klimit = _end;
+struct device_node *memory_node;
void *find_mem_piece(unsigned, unsigned);
static void mapin_ram(void);
-static void inherit_prom_translations(void);
static void hash_init(void);
static void *MMU_get_page(void);
void map_page(struct task_struct *, unsigned long va,
@@ -76,22 +66,16 @@
extern void show_net_buffers(void);
extern unsigned long *find_end_of_memory(void);
-/*
- * this tells the prep system to map all of ram with the segregs
- * instead of the bats. I'd like to get this to apply to the
- * pmac as well then have everything use the bats -- Cort
- */
-#undef MAP_RAM_WITH_SEGREGS 1
+extern struct task_struct *current_set[NR_CPUS];
/*
- * these are used to setup the initial page tables
- * They can waste up to an entire page since the
- * I'll fix this shortly -- Cort
+ * this tells the system to map all of ram with the segregs
+ * (i.e. page tables) instead of the bats.
*/
-#define MAX_MMU_PAGES 16
-unsigned int probingmem = 0;
-unsigned int mmu_pages_count = 0;
-char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
+#undef MAP_RAM_WITH_SEGREGS 1
+
+/* optimization for 603 to load the tlb directly from the linux table */
+#define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -122,8 +106,12 @@
return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
}
+/*
+ * The following stuff defines a data structure for representing
+ * areas of memory as an array of (address, length) pairs, and
+ * procedures for manipulating them.
+ */
#define MAX_MEM_REGIONS 32
-phandle memory_pkg;
struct mem_pieces {
int n_regions;
@@ -134,34 +122,19 @@
struct mem_pieces prom_mem;
static void get_mem_prop(char *, struct mem_pieces *);
+static void sort_mem_pieces(struct mem_pieces *);
+static void coalesce_mem_pieces(struct mem_pieces *);
+static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
static void print_mem_pieces(struct mem_pieces *);
-unsigned long avail_start;
-
-/*
- * Read in a property describing some pieces of memory.
- */
static void
-get_mem_prop(char *name, struct mem_pieces *mp)
+sort_mem_pieces(struct mem_pieces *mp)
{
- int s, i;
-
- s = (int) call_prom("getprop", 4, 1, memory_pkg, name,
- mp->regions, sizeof(mp->regions));
- if (s < sizeof(mp->regions[0])) {
- printk("getprop /memory %s returned %d\n", name, s);
- abort();
- }
- mp->n_regions = s / sizeof(mp->regions[0]);
+ unsigned long a, s;
+ int i, j;
- /*
- * Make sure the pieces are sorted.
- */
for (i = 1; i < mp->n_regions; ++i) {
- unsigned long a, s;
- int j;
-
a = mp->regions[i].address;
s = mp->regions[i].size;
for (j = i - 1; j >= 0; --j) {
@@ -174,6 +147,41 @@
}
}
+static void
+coalesce_mem_pieces(struct mem_pieces *mp)
+{
+ unsigned long a, e;
+ int i, j, d;
+
+ d = 0;
+ for (i = 0; i < mp->n_regions; i = j) {
+ a = mp->regions[i].address;
+ e = a + mp->regions[i].size;
+ for (j = i + 1; j < mp->n_regions
+ && mp->regions[j].address <= e; ++j)
+ e = mp->regions[j].address + mp->regions[j].size;
+ mp->regions[d].address = a;
+ mp->regions[d].size = e - a;
+ ++d;
+ }
+ mp->n_regions = d;
+}
+
+/*
+ * Add some memory to an array of pieces
+ */
+static void
+append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)
+{
+ struct reg_property *rp;
+
+ if (mp->n_regions >= MAX_MEM_REGIONS)
+ return;
+ rp = &mp->regions[mp->n_regions++];
+ rp->address = start;
+ rp->size = size;
+}
+
/*
* Remove some memory from an array of pieces
*/
@@ -244,6 +252,9 @@
printk("\n");
}
+/*
+ * Scan a region for a piece of a given size with the required alignment.
+ */
void *
find_mem_piece(unsigned size, unsigned align)
{
@@ -266,8 +277,32 @@
}
/*
- * Collect information about RAM and which pieces are already in use.
- * At this point, we have the first 8MB mapped with a BAT.
+ * Read in a property describing some pieces of memory.
+ */
+static void
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+ struct reg_property *rp;
+ int s;
+
+ rp = (struct reg_property *) get_property(memory_node, name, &s);
+ if (rp == NULL) {
+ printk(KERN_ERR "error: couldn't get %s property on /memory\n",
+ name);
+ abort();
+ }
+ mp->n_regions = s / sizeof(mp->regions[0]);
+ memcpy(mp->regions, rp, s);
+
+ /* Make sure the pieces are sorted. */
+ sort_mem_pieces(mp);
+ coalesce_mem_pieces(mp);
+}
+
+/*
+ * On systems with Open Firmware, collect information about
+ * physical RAM and which pieces are already in use.
+ * At this point, we have (at least) the first 8MB mapped with a BAT.
* Our text, data, bss use something over 1MB, starting at 0.
* Open Firmware may be using 1MB at the 4MB point.
*/
@@ -275,18 +310,24 @@
{
unsigned long a, total;
unsigned long kstart, ksize;
- extern char _stext[], _end[];
int i;
- memory_pkg = call_prom("finddevice", 1, 1, "/memory");
- if (memory_pkg == (void *) -1)
- panic("can't find memory package");
+ memory_node = find_devices("memory");
+ if (memory_node == NULL) {
+ printk(KERN_ERR "can't find memory node\n");
+ abort();
+ }
/*
* Find out where physical memory is, and check that it
* starts at 0 and is contiguous. It seems that RAM is
* always physically contiguous on Power Macintoshes,
* because MacOS can't cope if it isn't.
+ *
+ * Supporting discontiguous physical memory isn't hard,
+ * it just makes the virtual <-> physical mapping functions
+ * more complicated (or else you end up wasting space
+ * in mem_map).
*/
get_mem_prop("reg", &phys_mem);
if (phys_mem.n_regions == 0)
@@ -295,15 +336,11 @@
if (a != 0)
panic("RAM doesn't start at physical address 0");
total = phys_mem.regions[0].size;
- for (i = 1; i < phys_mem.n_regions; ++i) {
- a = phys_mem.regions[i].address;
- if (a != total) {
- printk("RAM starting at 0x%lx is not contiguous\n", a);
- printk("Using RAM from 0 to 0x%lx\n", total-1);
- phys_mem.n_regions = i;
- break;
- }
- total += phys_mem.regions[i].size;
+ if (phys_mem.n_regions > 1) {
+ printk("RAM starting at 0x%x is not contiguous\n",
+ phys_mem.regions[1].address);
+ printk("Using RAM from 0 to 0x%lx\n", total-1);
+ phys_mem.n_regions = 1;
}
/* record which bits the prom is using */
@@ -320,9 +357,11 @@
* Make sure the kernel text/data/bss is in neither.
*/
kstart = __pa(_stext); /* should be 0 */
- ksize = PAGE_ALIGN(_end - _stext);
+ ksize = PAGE_ALIGN(klimit - _stext);
remove_mem_piece(&phys_avail, kstart, ksize, 0);
remove_mem_piece(&prom_mem, kstart, ksize, 0);
+ remove_mem_piece(&phys_avail, 0, 0x4000, 0);
+ remove_mem_piece(&prom_mem, 0, 0x4000, 0);
return __va(total);
}
@@ -333,14 +372,13 @@
* that setup_arch returns, making sure that there are at
* least 32 pages unused before this for MMU_get_page to use.
*/
+unsigned long avail_start;
+
unsigned long find_available_memory(void)
{
int i;
unsigned long a, free;
unsigned long start, end;
-
- if ( _machine != _MACH_Pmac )
- return 0;
free = 0;
for (i = 0; i < phys_avail.n_regions - 1; ++i) {
@@ -382,8 +420,12 @@
#ifdef CONFIG_NET
show_net_buffers();
#endif
- printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt",
+ printk("%-8s %3s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Cnt",
"Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+#ifdef __SMP__
+ printk(" %3s", "CPU");
+#endif /* __SMP__ */
+ printk("\n");
for_each_task(p)
{
printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
@@ -392,16 +434,28 @@
p->mm->context<<4, p->tss.last_syscall,
user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
(ulong)p);
- if ( p == current )
- printk("current");
- if ( p == last_task_used_math )
{
+ int iscur = 0;
+#ifdef __SMP__
+ printk("%3d ", p->processor);
+ if ( (p->processor != NO_PROC_ID) &&
+ (p == current_set[p->processor]) )
+
+#else
if ( p == current )
- printk(",");
- printk("last math");
+#endif /* __SMP__ */
+ {
+ iscur = 1;
+ printk("current");
+ }
+ if ( p == last_task_used_math )
+ {
+ if ( iscur )
+ printk(",");
+ printk("last math");
+ }
+ printk("\n");
}
-
- printk("\n");
}
}
@@ -415,9 +469,9 @@
/*
* Grab some memory for bad_page and bad_pagetable to use.
*/
- empty_bad_page = start_mem;
- empty_bad_page_table = start_mem + PAGE_SIZE;
- start_mem += 2 * PAGE_SIZE;
+ empty_bad_page = PAGE_ALIGN(start_mem);
+ empty_bad_page_table = empty_bad_page + PAGE_SIZE;
+ start_mem = empty_bad_page + 2 * PAGE_SIZE;
/* note: free_area_init uses its second argument
to size the mem_map array. */
@@ -442,53 +496,37 @@
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
- if ( _machine == _MACH_Pmac )
- {
- remove_mem_piece(&phys_avail, __pa(avail_start),
- start_mem - avail_start, 1);
-
- for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
- set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
-
- for (i = 0; i < phys_avail.n_regions; ++i) {
- a = (unsigned long) __va(phys_avail.regions[i].address);
- lim = a + phys_avail.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE)
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- }
- phys_avail.n_regions = 0;
-
- /* free the prom's memory */
- for (i = 0; i < prom_mem.n_regions; ++i) {
- a = (unsigned long) __va(prom_mem.regions[i].address);
- lim = a + prom_mem.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE)
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- }
- prom_trashed = 1;
- }
- else /* prep */
- {
- /* mark mem used by kernel as reserved, mark other unreserved */
- for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
- {
- /* skip hash table gap */
- if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
- continue;
- if ( addr < (ulong) /*Hash_end*/ start_mem )
- set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
- else
- clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
- }
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ }
+ phys_avail.n_regions = 0;
+
+ /* free the prom's memory - no-op on prep */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
+ prom_trashed = 1;
for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
if (PageReserved(mem_map + MAP_NR(addr))) {
if (addr < (ulong) etext)
codepages++;
- else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ else if (addr >= (unsigned long)&__init_begin
+ && addr < (unsigned long)&__init_end)
initpages++;
else if (addr < (ulong) start_mem)
datapages++;
@@ -497,7 +535,7 @@
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_start ||
- (addr < initrd_start || addr >= initrd_end))
+ addr < (initrd_start & PAGE_MASK) || addr >= initrd_end)
#endif /* CONFIG_BLK_DEV_INITRD */
free_page(addr);
}
@@ -512,31 +550,22 @@
}
/*
- * this should reclaim gap between _end[] and hash table
- * as well as unused mmu_pages[] on prep systems.
- * When I get around to it, I'll put initialization functions
- * (called only at boot) in their own .section and free that -- Cort
+ * Unfortunately, we can't put initialization functions in their
+ * own section and free that at this point, because gas gets some
+ * relocations wrong if we do. :-( But this code is here for when
+ * gas gets fixed.
*/
void free_initmem(void)
{
unsigned long a;
unsigned long num_freed_pages = 0;
- /* free unused mmu_pages[] */
- a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE);
- for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE )
- {
- clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags );
- atomic_set(&mem_map[MAP_NR(a)].count, 1);
- free_page(a);
- num_freed_pages++;
- }
-
a = (unsigned long)(&__init_begin);
for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
- mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
atomic_set(&mem_map[MAP_NR(a)].count, 1);
free_page(a);
+ num_freed_pages++;
}
printk ("Freeing unused kernel memory: %ldk freed\n",
@@ -565,138 +594,72 @@
return;
}
-BAT BAT0 =
-{
- {
- MMU_SEGMENT_1>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs -- supervisor mode valid */
- 1, /* vp -- user mode valid */
- },
- {
- MMU_SEGMENT_1>>17, /* brpn */
- 1, /* write-through */
- 1, /* cache-inhibited */
- 0, /* memory coherence */
- 1, /* guarded */
- BPP_RW /* protection */
- }
-};
-BAT BAT1 =
-{
- {
- MMU_SEGMENT_2>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs */
- 1, /* vp */
- },
- {
- MMU_SEGMENT_2>>17, /* brpn */
- 1, /* w */
- 1, /* i (cache disabled) */
- 0, /* m */
- 1, /* g */
- BPP_RW /* pp */
- }
-};
-BAT BAT2 =
-{
- {
- 0x90000000>>17, /* bepi */
- BL_256M, /* this gets set to amount of phys ram */
- 1, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 0, /* w */
- 0, /* i */
-#ifdef __SMP__
- 1, /* m */
-#else
- 0, /* m */
-#endif
- 0, /* g */
- BPP_RW /* pp */
- }
-};
-BAT BAT3 =
-{
- {
- 0x00000000>>17, /* bepi */
- BL_256M, /* bl */
- 0, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 0, /* w */
- 0, /* i (cache disabled) */
- 1, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
-};
+union ubat { /* BAT register values to be loaded */
+ BAT bat;
+ P601_BAT bat_601;
+ u32 word[2];
+} BATS[4][2]; /* 4 pairs of IBAT, DBAT */
+
+struct batrange { /* stores address ranges mapped by BATs */
+ unsigned long start;
+ unsigned long limit;
+ unsigned long phys;
+} bat_addrs[4];
-P601_BAT BAT0_601 =
-{
- {
- 0x80000000>>17, /* bepi */
- 1,1,0, /* wim */
- 1, 0, /* vs, vp */
- BPP_RW, /* pp */
- },
- {
- 0x80000000>>17, /* brpn */
- 1, /* v */
- BL_8M, /* bl */
- }
-};
-
-P601_BAT BAT1_601 =
-{
- {
- MMU_SEGMENT_2>>17, /* bepi */
- 1,1,0, /* wim */
- 1, 0, /* vs, vp */
- BPP_RW, /* pp */
- },
- {
- MMU_SEGMENT_2>>17, /* brpn */
- 1, /* v */
- BL_8M, /* bl */
- }
-};
-
-P601_BAT BAT2_601 =
-{
- {
- 0x90000000>>17, /* bepi */
- 0,0,0, /* wim */
- 1, 0, /* vs, vp */
- BPP_RW, /* pp */
- },
- {
- 0x00000000>>17, /* brpn */
- 1, /* v */
- BL_8M, /* bl */
- }
-};
-
-P601_BAT BAT3_601 =
+/*
+ * Set up one of the I/D BAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ */
+void
+setbat(int index, unsigned long virt, unsigned long phys,
+ unsigned int size, int flags)
{
- {
- 0x90800000>>17, /* bepi */
- 0,0,0, /* wim */
- 1, 0, /* vs, vp */
- BPP_RW, /* pp */
- },
- {
- 0x00800000>>17, /* brpn */
- 1, /* v */
- BL_8M, /* bl */
- }
-};
+ unsigned int bl;
+ int wimgxpp;
+ union ubat *bat = BATS[index];
+
+ bl = (size >> 17) - 1;
+ if ((_get_PVR() >> 16) != 1) {
+ /* 603, 604, etc. */
+ /* Do DBAT first */
+ wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+ | _PAGE_COHERENT | _PAGE_GUARDED);
+ wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+ bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+ bat[1].word[1] = phys | wimgxpp;
+ if (flags & _PAGE_USER)
+ bat[1].bat.batu.vp = 1;
+ if (flags & _PAGE_GUARDED) {
+ /* G bit must be zero in IBATs */
+ bat[0].word[0] = bat[0].word[1] = 0;
+ } else {
+ /* make IBAT same as DBAT */
+ bat[0] = bat[1];
+ }
+ } else {
+ /* 601 cpu */
+ if (bl > BL_8M)
+ bl = BL_8M;
+ wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+ | _PAGE_COHERENT);
+ wimgxpp |= (flags & _PAGE_RW)?
+ ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
+ bat->word[0] = virt | wimgxpp | 4; /* Ks=0, Ku=1 */
+ bat->word[1] = phys | bl | 0x40; /* V=1 */
+ }
+
+ bat_addrs[index].start = virt;
+ bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
+ bat_addrs[index].phys = phys;
+}
+
+#define IO_PAGE (_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW)
+#ifdef __SMP__
+#define RAM_PAGE (_PAGE_COHERENT | _PAGE_RW)
+#else
+#define RAM_PAGE (_PAGE_RW)
+#endif
/*
* This finds the amount of physical ram and does necessary
@@ -706,158 +669,76 @@
*/
unsigned long *prep_find_end_of_memory(void)
{
- int i;
-
- if (res.TotalMemory == 0 )
+ unsigned long kstart, ksize;
+ unsigned long total;
+ total = res.TotalMemory;
+
+ if (total == 0 )
{
/*
* I need a way to probe the amount of memory if the residual
* data doesn't contain it. -- Cort
*/
printk("Ramsize from residual data was 0 -- Probing for value\n");
- res.TotalMemory = 0x03000000;
- printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
+ total = 0x02000000;
+ printk("Ramsize default to be %ldM\n", total>>20);
}
+ append_mem_piece(&phys_mem, 0, total);
+ phys_avail = phys_mem;
+ kstart = __pa(_stext); /* should be 0 */
+ ksize = PAGE_ALIGN(klimit - _stext);
+ remove_mem_piece(&phys_avail, kstart, ksize, 0);
+ remove_mem_piece(&phys_avail, 0, 0x4000, 0);
- /* NOTE: everything below here is moving to mapin_ram() */
-
-
- /*
- * if this is a 601, we can only map sizes of 8M with the BAT's
- * so we have to map what we can't map with the bats with the segregs
- * head.S will copy in the appropriate BAT's according to the processor
- * since the 601_BAT{2,3} structures are already setup to map
- * the first 16M correctly
- * -- Cort
- */
-#ifndef MAP_RAM_WITH_SEGREGS /* don't need to do it twice */
- if ( _get_PVR() == 1 )
- {
- /* map in rest of ram with seg regs */
- if ( res.TotalMemory > 0x01000000 /* 16M */)
- {
- for (i = KERNELBASE+0x01000000;
- i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
- map_page(&init_task, i, __pa(i),
- _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
- }
- }
-#endif /* MAP_RAM_WITH_SEGREGS */
-
-#ifdef MAP_RAM_WITH_SEGREGS
- /* turn off bat mapping kernel since being done with segregs */
- memset(&BAT2, sizeof(BAT2), 0);
- memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
- memset(&BAT3_601, sizeof(BAT2), 0);
- /* map all of ram for kernel with segregs */
- for (i = KERNELBASE; i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
- {
- if ( i < (unsigned long)etext )
- map_page(&init_task, i, __pa(i),
- _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
- else
- map_page(&init_task, i, __pa(i),
- _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
- }
-#endif /* MAP_RAM_WITH_SEGREGS */
-
- return (__va(res.TotalMemory));
+ return (__va(total));
}
/*
* Map in all of physical memory starting at KERNELBASE.
*/
-extern int n_mem_regions;
-extern struct reg_property mem_regions[];
-
#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
static void mapin_ram()
{
- int i;
- unsigned long v, p, s, f;
+ int i;
+ unsigned long tot, bl, done;
+ unsigned long v, p, s, f;
- if ( _machine == _MACH_Pmac )
- {
- v = KERNELBASE;
- for (i = 0; i < phys_mem.n_regions; ++i) {
- p = phys_mem.regions[i].address;
- for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
- f = _PAGE_PRESENT | _PAGE_ACCESSED;
- if ((char *) v < _stext || (char *) v >= etext)
- f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
- else
- /* On the powerpc, no user access forces R/W kernel access */
- f |= _PAGE_USER;
- map_page(&init_task, v, p, f);
- v += PAGE_SIZE;
- p += PAGE_SIZE;
- }
- }
- }
- else /* prep */
- {
- /* setup the bat2 mapping to cover physical ram */
- BAT2.batu.bl = 0x1; /* 256k mapping */
- for ( f = 256*1024 /* 256k */ ;
- (f <= res.TotalMemory) && (f <= 256*1024*1024);
- f *= 2 )
- BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
- /*
- * let ibm get to the device mem from user mode since
- * the X for them needs it right now -- Cort
- */
- if ( _machine == _MACH_IBM )
- BAT0.batu.vp = BAT1.batu.vp = 1;
-
- }
-}
-
-#define MAX_PROM_TRANSLATIONS 64
-
-static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS];
-int n_translations;
-phandle mmu_pkg;
-extern ihandle prom_chosen;
-
-static void inherit_prom_translations()
-{
- int s, i, f;
- unsigned long v, p, n;
- struct translation_property *tp;
- ihandle mmu_inst;
-
- if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
- &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst))
- panic("couldn't get /chosen mmu property");
- mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst);
- if (mmu_pkg == (phandle) -1)
- panic("couldn't get mmu package");
- s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations",
- &prom_translations, sizeof(prom_translations));
- if (s < sizeof(prom_translations[0]))
- panic("couldn't get mmu translations property");
- n_translations = s / sizeof(prom_translations[0]);
-
- for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
- /* ignore stuff mapped down low */
- if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
- continue;
- /* map PPC mmu flags to linux mm flags */
- f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
- | _PAGE_COHERENT | _PAGE_GUARDED))
- | pgprot_val(PAGE_KERNEL);
- /* add these pages to the mappings */
- v = tp->virt;
- p = tp->phys;
- n = tp->size;
- for (; n != 0; n -= PAGE_SIZE) {
+#ifndef MAP_RAM_WITH_SEGREGS
+ /* Set up BAT2 and if necessary BAT3 to cover RAM. */
+ tot = (unsigned long)end_of_DRAM - KERNELBASE;
+ for (bl = 128<<10; bl < 256<<20; bl <<= 1)
+ if (bl * 2 > tot)
+ break;
+ setbat(2, KERNELBASE, 0, bl, RAM_PAGE);
+ done = __pa(bat_addrs[2].limit) + 1;
+ if (done < tot) {
+ /* use BAT3 to cover a bit more */
+ tot -= done;
+ for (bl = 128<<10; bl < 256<<20; bl <<= 1)
+ if (bl * 2 > tot)
+ break;
+ setbat(3, KERNELBASE+done, done, bl, RAM_PAGE);
+ }
+#endif
+
+ v = KERNELBASE;
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ f = _PAGE_PRESENT | _PAGE_ACCESSED;
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+ else
+ /* On the powerpc, no user access
+ forces R/W kernel access */
+ f |= _PAGE_USER;
map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
- }
+ }
}
/*
@@ -866,56 +747,78 @@
static void hash_init(void)
{
int Hash_bits;
- unsigned long h;
+ unsigned long h, ramsize;
extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
- hash_page_patch_C[];
+ hash_page_patch_C[], hash_page_patch_D[];
/*
* Allow 64k of hash table for every 16MB of memory,
* up to a maximum of 2MB.
*/
- for (h = 64<<10; h < (ulong)__pa(end_of_DRAM) / 256 && h < 2<<20; h *= 2)
+ ramsize = (ulong)end_of_DRAM - KERNELBASE;
+ for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
;
Hash_size = h;
Hash_mask = (h >> 6) - 1;
-
+
+#ifdef NO_RELOAD_HTAB
+ /* shrink the htab since we don't use it on 603's -- Cort */
+ switch (_get_PVR()>>16) {
+ case 3: /* 603 */
+ case 6: /* 603e */
+ case 7: /* 603ev */
+ Hash_size = 0;
+ Hash_mask = 0;
+ break;
+ default:
+ /* on 601/4 let things be */
+ break;
+ }
+#endif /* NO_RELOAD_HTAB */
+
/* Find some memory for the hash table. */
- if ( is_prep )
- /* align htab on a Hash_size boundry above _end[] */
- Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
- else /* pmac */
+ if ( Hash_size )
Hash = find_mem_piece(Hash_size, Hash_size);
-
+ else
+ Hash = 0;
+
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- __pa(end_of_DRAM) >> 20, Hash_size >> 10, Hash);
- memset(Hash, 0, Hash_size);
- Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+ ramsize >> 20, Hash_size >> 10, Hash);
+ if ( Hash_size )
+ {
+ memset(Hash, 0, Hash_size);
+ Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
- /*
- * Patch up the instructions in head.S:hash_page
- */
- Hash_bits = ffz(~Hash_size) - 6;
- hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
- | (__pa(Hash) >> 16);
- hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
- | ((26 - Hash_bits) << 6);
- if (Hash_bits > 16)
- Hash_bits = 16;
- hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
- | ((26 - Hash_bits) << 6);
- hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
- | (Hash_mask >> 10);
- hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
- | (Hash_mask >> 10);
+ /*
+ * Patch up the instructions in head.S:hash_page
+ */
+ Hash_bits = ffz(~Hash_size) - 6;
+ hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+ | (__pa(Hash) >> 16);
+ hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ if (Hash_bits > 16)
+ Hash_bits = 16;
+ hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+ | (Hash_mask >> 10);
+ hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+ | (Hash_mask >> 10);
+ hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff)
+ | (Hash_mask >> 10);
+ /*
+ * Ensure that the locations we've patched have been written
+ * out from the data cache and invalidated in the instruction
+ * cache, on those machines with split caches.
+ */
+ flush_icache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_D + 1));
+ }
+ else
+ Hash_end = 0;
- /*
- * Ensure that the locations we've patched have been written
- * out from the data cache and invalidated in the instruction
- * cache, on those machines with split caches.
- */
- flush_icache_range((unsigned long) hash_page_patch_A,
- (unsigned long) (hash_page_patch_C + 1));
}
@@ -929,19 +832,40 @@
void
MMU_init(void)
{
- if ( _machine == _MACH_Pmac )
+ if (have_of)
end_of_DRAM = pmac_find_end_of_memory();
- else /* prep and chrp */
+ else /* prep */
end_of_DRAM = prep_find_end_of_memory();
-
+
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
/* Map in all of RAM starting at KERNELBASE */
mapin_ram();
- if ( _machine == _MACH_Pmac )
- /* Copy mappings from the prom */
- inherit_prom_translations();
+
+ /*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas. RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+ switch (_machine) {
+ case _MACH_prep:
+ setbat(0, 0x80000000, 0x80000000, 0x10000000,
+ IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0));
+ setbat(1, 0xd0000000, 0xc0000000, 0x10000000,
+ IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0));
+ break;
+ case _MACH_chrp:
+ setbat(0, 0xc0000000, 0xc0000000, 0x10000000, IO_PAGE);
+ setbat(1, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE);
+ setbat(3, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+ break;
+ case _MACH_Pmac:
+ setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE);
+ /* this is used to cover registers used by smp boards -- Cort */
+ setbat(3, 0xf8000000, 0xf8000000, 0x100000, IO_PAGE);
+ break;
+ }
}
static void *
@@ -954,18 +878,7 @@
if (p == 0)
panic("couldn't get a page in MMU_get_page");
} else {
- if ( is_prep || (_machine == _MACH_chrp) )
- {
- mmu_pages_count++;
- if ( mmu_pages_count > MAX_MMU_PAGES )
- printk("out of mmu pages!\n");
- p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
- (mmu_pages_count+PAGE_SIZE));
- }
- else /* pmac */
- {
- p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
- }
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
}
memset(p, 0, PAGE_SIZE);
return p;
@@ -976,30 +889,15 @@
{
unsigned long p, end = addr + size;
- /*
- * BAT mappings on prep cover this already so don't waste
- * space with it. -- Cort
- */
- if ( is_prep )
- if ( ((addr >= 0xc0000000) && (end < (0xc0000000+(256<<20)))) ||
- ((addr >= 0x80000000) && (end < (0x80000000+(256<<20)))) )
- return (void *)addr;
for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
- map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ map_page(&init_task, p, p,
+ pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
return (void *) addr;
}
-extern void iounmap(unsigned long *addr)
+void iounmap(unsigned long *addr)
{
- /*
- * BAT mappings on prep cover this already so don't waste
- * space with it. -- Cort
- */
- if ( is_prep )
- if ( (((unsigned long)addr >= 0xc0000000) && ((unsigned long)addr < (0xc0000000+(256<<20)))) ||
- (((unsigned long)addr >= 0x80000000) && ((unsigned long)addr < (0x80000000+(256<<20)))) )
- return;
- /* else unmap it */
+ /* XXX todo */
}
void
@@ -1008,7 +906,7 @@
{
pmd_t *pd;
pte_t *pg;
-
+ int b;
if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
@@ -1017,7 +915,18 @@
/* Use upper 10 bits of VA to index the first level map */
pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
- /* Need to allocate second-level table */
+ /*
+ * Need to allocate second-level table, but first
+ * check whether this address is already mapped by
+ * the BATs; if so, don't bother allocating the page.
+ */
+ for (b = 0; b < 4; ++b) {
+ if (va >= bat_addrs[b].start
+ && va <= bat_addrs[b].limit) {
+ /* XXX should check the phys address matches */
+ return;
+ }
+ }
pg = (pte_t *) MMU_get_page();
pmd_val(*pd) = (unsigned long) pg;
}
@@ -1042,22 +951,14 @@
*/
/*
- * Flush all tlb/hash table entries except for the kernel's.
- * We use the fact that only kernel mappings use VSIDs 0 - 15.
+ * Flush all tlb/hash table entries (except perhaps for those
+ * mapping RAM starting at PAGE_OFFSET, since they never change).
*/
void
-flush_tlb_all(void)
+local_flush_tlb_all(void)
{
- struct task_struct *tsk;
-
- read_lock(&tasklist_lock);
- for_each_task(tsk) {
- if (tsk->mm)
- tsk->mm->context = NO_CONTEXT;
- }
- read_unlock(&tasklist_lock);
- get_mmu_context(current);
- set_context(current->mm->context);
+ memset(Hash, 0, Hash_size);
+ _tlbia();
}
@@ -1067,7 +968,7 @@
* that might be in the hash table.
*/
void
-flush_tlb_mm(struct mm_struct *mm)
+local_flush_tlb_mm(struct mm_struct *mm)
{
mm->context = NO_CONTEXT;
if (mm == current->mm) {
@@ -1077,6 +978,16 @@
}
}
+void
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ if (vmaddr < TASK_SIZE)
+ flush_hash_page(vma->vm_mm->context, vmaddr);
+ else
+ flush_hash_page(0, vmaddr);
+}
+
+
/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
@@ -1084,9 +995,16 @@
-- Cort
*/
void
-flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
start &= PAGE_MASK;
+
+ if (end - start > 20 * PAGE_SIZE)
+ {
+ flush_tlb_mm(mm);
+ return;
+ }
+
for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
{
flush_hash_page(mm->context, start);
@@ -1117,4 +1035,58 @@
current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
set_context(current->mm->context);
}
+
+#if 0
+/*
+ * Cache flush functions - these functions cause caches to be flushed
+ * on _all_ processors due to their use of dcbf. local_flush_cache_all() is
+ * the only function that will not act on all processors in the system.
+ * -- Cort
+ */
+void local_flush_cache_all(void)
+{
+#if 0
+ unsigned long hid0,tmp;
+ asm volatile(
+ "mfspr %0,1008 \n\t"
+ "mr %1,%0 \n\t"
+ "or %0,%2,%2 \n\t"
+ "mtspr 1008,%0 \n\t"
+ "sync \n\t"
+ "isync \n\t"
+ "andc %0,%0,%2 \n\t"
+ "mtspr 1008,%0 \n\t"
+ : "=r" (tmp), "=r" (hid0)
+ : "r" (HID0_ICFI|HID0_DCI)
+ );
+#endif
+}
+
+void local_flush_cache_mm(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma = NULL;
+ vma = mm->mmap;
+ while(vma)
+ {
+ local_flush_cache_range(mm,vma->vm_start,vma->vm_end);
+ vma = vma->vm_next;
+ }
+}
+
+void local_flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ unsigned long i;
+ vmaddr = PAGE_ALIGN(vmaddr);
+ for ( i = vmaddr ; i <= (vmaddr+PAGE_SIZE); i += 32 )
+ asm volatile("dcbf %0,%1\n\ticbi %0,%1\n\t" :: "r" (i), "r" (0));
+}
+
+void local_flush_cache_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ unsigned long i;
+ for ( i = start ; i <= end; i += 32 )
+ asm volatile("dcbf %0,%1\n\ticbi %0,%1\n\t" :: "r" (i), "r" (0));
+}
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov