Hi, this is second version of high memory detection for Indigo2. It will allow to use more that 256M RAM. I was told by Ralf that CONFIG_HIGHMEM is broken for I2, so you'll need to build 64bit kernel to use it (I was also told there is more bugs related to high memory support and I think that once high memory is detected properly more people will be interested in hunting those bugs :)) Patch also completely replaces ARCS based memory detection by memory controller based one. We need to read memory configuration from MC anyway, so this will make kernel a bit smaller. Index: arch/mips/sgi-ip22/ip22-mc.c =================================================================== RCS file: /home/cvs/linux/arch/mips/sgi-ip22/ip22-mc.c,v retrieving revision 1.1.2.7 diff -u -r1.1.2.7 ip22-mc.c --- arch/mips/sgi-ip22/ip22-mc.c 6 Apr 2003 01:47:27 -0000 1.1.2.7 +++ arch/mips/sgi-ip22/ip22-mc.c 14 May 2003 07:37:53 -0000 @@ -1,51 +1,111 @@ /* - * ip22-mc.c: Routines for manipulating the INDY memory controller. + * ip22-mc.c: Routines for manipulating SGI Memory Controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes + * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) */ #include <linux/init.h> #include <linux/kernel.h> #include <asm/addrspace.h> +#include <asm/bootinfo.h> #include <asm/ptrace.h> #include <asm/sgialib.h> #include <asm/sgi/mc.h> #include <asm/sgi/hpc3.h> #include <asm/sgi/ip22.h> -/* #define DEBUG_SGIMC */ - struct sgimc_regs *sgimc; -#ifdef DEBUG_SGIMC -static inline char *mconfig_string(unsigned long val) +static inline unsigned int get_bank_size(unsigned int val) { switch(val & SGIMC_MCONFIG_RMASK) { - case SGIMC_MCONFIG_FOURMB: - return "4MB"; - - case SGIMC_MCONFIG_EIGHTMB: - return "8MB"; + case SGIMC_MCONFIG_256K: return 4*4*256 * 1024; + case SGIMC_MCONFIG_512K: return 4*4*512 * 1024; + case SGIMC_MCONFIG_1M: return 4*4*1024 * 1024; + case SGIMC_MCONFIG_2M: return 4*4*2048 * 1024; + case SGIMC_MCONFIG_4M: return 4*4*4096 * 1024; + case SGIMC_MCONFIG_8M: return 4*4*8192 * 1024; + default: return 0; + } +} - case SGIMC_MCONFIG_SXTEENMB: - return "16MB"; +static inline unsigned int get_bank_config(int bank) +{ + unsigned int res = bank > 1 ? sgimc->mconfig1 : sgimc->mconfig0; + return bank % 2 ? res & 0xffff : res >> 16; +} - case SGIMC_MCONFIG_TTWOMB: - return "32MB"; +struct mem { + unsigned long addr; + unsigned long size; +}; - case SGIMC_MCONFIG_SFOURMB: - return "64MB"; +/* + * Detect installed memory, do some sanity checks and notify kernel about it + */ +static void probe_memory(void) +{ + int i, j, found, cnt = 0; + struct mem bank[4]; + struct mem space[2] = {{SGIMC_SEG0_BADDR, 0}, {SGIMC_SEG1_BADDR, 0}}; + + printk(KERN_INFO "MC: Probing memory configuration:\n"); + for (i = 0; i < ARRAY_SIZE(bank); i++) { + int tmp = get_bank_config(i); + if (!(tmp & SGIMC_MCONFIG_BVALID)) + continue; + + if (!(bank[cnt].size = get_bank_size(tmp))) { + printk(KERN_WARNING " bank%d: unknown, ignored\n", i); + continue; + } - case SGIMC_MCONFIG_OTEIGHTMB: - return "128MB"; + bank[cnt].addr = (tmp & SGIMC_MCONFIG_BASEADDR) << 22; + printk(KERN_INFO " bank%d: %3ldM @ %08lx\n", + i, bank[cnt].size / 1024 / 1024, bank[cnt].addr); + cnt++; + } - default: - return "wheee, unknown"; + /* And you thought bubble sort is dead algorithm... */ + do { + unsigned long addr, size; + + found = 0; + for (i = 1; i < cnt; i++) + if (bank[i-1].addr > bank[i].addr) { + addr = bank[i].addr; + size = bank[i].size; + bank[i].addr = bank[i-1].addr; + bank[i].size = bank[i-1].size; + bank[i-1].addr = addr; + bank[i-1].size = size; + found = 1; + } + } while (found); + + /* Figure out how are memory banks mapped into spaces */ + for (i = 0; i < cnt; i++) { + found = 0; + for (j = 0; j < ARRAY_SIZE(space) && !found; j++) + if (space[j].addr + space[j].size == bank[i].addr) { + space[j].size += bank[i].size; + found = 1; + } + /* There is either hole or overlapping memory */ + if (!found) + printk(KERN_CRIT "MC: Memory configuration mismatch " + "(%08lx), expect Bus Error soon\n", + bank[i].addr); } + + for (i = 0; i < ARRAY_SIZE(space); i++) + if (space[i].size) + add_memory_region(space[i].addr, space[i].size, + BOOT_MEM_RAM); } -#endif void __init sgimc_init(void) { @@ -56,17 +116,6 @@ printk(KERN_INFO "MC: SGI memory controller Revision %d\n", (int) sgimc->systemid & SGIMC_SYSID_MASKREV); -#ifdef DEBUG_SGIMC - prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n", - mconfig_string(sgimc->mconfig0), - mconfig_string(sgimc->mconfig1)); - - prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n", - sgimc->cpuctrl0, sgimc->cpuctrl1); - prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n", - sgimc->divider, sgimc->gioparm); -#endif - /* Place the MC into a known state. This must be done before * interrupts are first enabled etc. */ @@ -126,27 +175,32 @@ */ /* First the basic invariants across all GIO64 implementations. */ - tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits. */ - tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists. */ + tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */ + tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */ if (ip22_is_fullhouse()) { /* Fullhouse specific settings. */ if (SGIOC_SYSID_BOARDREV(sgioc->sysid) < 2) { - tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC at 64bits */ - tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp0 pipelines */ - tmp |= SGIMC_GIOPAR_MASTEREXP1;/* exp1 masters */ - tmp |= SGIMC_GIOPAR_RTIMEEXP0; /* exp0 is realtime */ + tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC at 64bits */ + tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp0 pipelines */ + tmp |= SGIMC_GIOPAR_MASTEREXP1; /* exp1 masters */ + tmp |= SGIMC_GIOPAR_RTIMEEXP0; /* exp0 is realtime */ } else { - tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC 64bits */ - tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */ + tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC 64bits */ + tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */ tmp |= SGIMC_GIOPAR_PLINEEXP1; - tmp |= SGIMC_GIOPAR_MASTEREISA;/* EISA masters */ - tmp |= SGIMC_GIOPAR_GFX64; /* GFX at 64 bits */ + tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */ + tmp |= SGIMC_GIOPAR_GFX64; /* GFX at 64 bits */ } } else { /* Guiness specific settings. */ - tmp |= SGIMC_GIOPAR_EISA64; /* MC talks to EISA at 64bits */ - tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */ + tmp |= SGIMC_GIOPAR_EISA64; /* MC talks to EISA at 64bits */ + tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */ } - sgimc->giopar = tmp; /* poof */ + sgimc->giopar = tmp; /* poof */ + + probe_memory(); } + +void __init prom_meminit(void) {} +void __init prom_free_prom_memory (void) {} Index: arch/mips/config-shared.in =================================================================== RCS file: /home/cvs/linux/arch/mips/Attic/config-shared.in,v retrieving revision 1.1.2.59 diff -u -r1.1.2.59 config-shared.in --- arch/mips/config-shared.in 5 May 2003 07:50:48 -0000 1.1.2.59 +++ arch/mips/config-shared.in 14 May 2003 07:37:53 -0000 @@ -481,7 +481,6 @@ fi if [ "$CONFIG_SGI_IP22" = "y" ]; then define_bool CONFIG_ARC32 y - define_bool CONFIG_ARC_MEMORY y define_bool CONFIG_ARC_PROMLIB y define_bool CONFIG_BOARD_SCACHE y define_bool CONFIG_BOOT_ELF32 y Index: include/asm-mips/sgi/mc.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/sgi/mc.h,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 mc.h --- include/asm-mips/sgi/mc.h 27 Apr 2003 22:25:28 -0000 1.1.2.2 +++ include/asm-mips/sgi/mc.h 14 May 2003 07:37:53 -0000 @@ -95,19 +95,22 @@ u32 _unused10[3]; volatile u32 lbursttp; /* Time period for long bursts */ + /* MC chip can drive up to 4 bank 4 SIMMs each. All SIMMs in bank must + * be the same size. The size encoding for supported SIMMs is bellow */ u32 _unused11[9]; volatile u32 mconfig0; /* Memory config register zero */ u32 _unused12; volatile u32 mconfig1; /* Memory config register one */ - - /* These defines apply to both mconfig registers above. */ -#define SGIMC_MCONFIG_FOURMB 0x00000000 /* Physical ram = 4megs */ -#define SGIMC_MCONFIG_EIGHTMB 0x00000100 /* Physical ram = 8megs */ -#define SGIMC_MCONFIG_SXTEENMB 0x00000300 /* Physical ram = 16megs */ -#define SGIMC_MCONFIG_TTWOMB 0x00000700 /* Physical ram = 32megs */ -#define SGIMC_MCONFIG_SFOURMB 0x00000f00 /* Physical ram = 64megs */ -#define SGIMC_MCONFIG_OTEIGHTMB 0x00001f00 /* Physical ram = 128megs */ +#define SGIMC_MCONFIG_BASEADDR 0x000000ff /* Base address of bank*/ +#define SGIMC_MCONFIG_256K 0x00000000 /* 256k x 36 bits */ +#define SGIMC_MCONFIG_512K 0x00000100 /* 512k x 36 bits, 2 subbanks */ +#define SGIMC_MCONFIG_1M 0x00000300 /* 1M x 36 bits */ +#define SGIMC_MCONFIG_2M 0x00000700 /* 2M x 36 bits, 2 subbanks */ +#define SGIMC_MCONFIG_4M 0x00000f00 /* 4M x 36 bits */ +#define SGIMC_MCONFIG_8M 0x00001f00 /* 8M x 36 bits, 2 subbanks */ #define SGIMC_MCONFIG_RMASK 0x00001f00 /* Ram config bitmask */ +#define SGIMC_MCONFIG_BVALID 0x00002000 /* Bank is valid */ +#define SGIMC_MCONFIG_SBANKS 0x00004000 /* Number of subbanks */ u32 _unused13; volatile u32 cmacc; /* Mem access config for CPU */ Index: include/asm-mips64/sgi/mc.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips64/sgi/mc.h,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 mc.h --- include/asm-mips64/sgi/mc.h 27 Apr 2003 22:25:28 -0000 1.1.2.2 +++ include/asm-mips64/sgi/mc.h 14 May 2003 07:37:53 -0000 @@ -95,19 +95,22 @@ u32 _unused10[3]; volatile u32 lbursttp; /* Time period for long bursts */ + /* MC chip can drive up to 4 bank 4 SIMMs each. All SIMMs in bank must + * be the same size. The size encoding for supported SIMMs is bellow */ u32 _unused11[9]; volatile u32 mconfig0; /* Memory config register zero */ u32 _unused12; volatile u32 mconfig1; /* Memory config register one */ - - /* These defines apply to both mconfig registers above. */ -#define SGIMC_MCONFIG_FOURMB 0x00000000 /* Physical ram = 4megs */ -#define SGIMC_MCONFIG_EIGHTMB 0x00000100 /* Physical ram = 8megs */ -#define SGIMC_MCONFIG_SXTEENMB 0x00000300 /* Physical ram = 16megs */ -#define SGIMC_MCONFIG_TTWOMB 0x00000700 /* Physical ram = 32megs */ -#define SGIMC_MCONFIG_SFOURMB 0x00000f00 /* Physical ram = 64megs */ -#define SGIMC_MCONFIG_OTEIGHTMB 0x00001f00 /* Physical ram = 128megs */ +#define SGIMC_MCONFIG_BASEADDR 0x000000ff /* Base address of bank*/ +#define SGIMC_MCONFIG_256K 0x00000000 /* 256k x 36 bits */ +#define SGIMC_MCONFIG_512K 0x00000100 /* 512k x 36 bits, 2 subbanks */ +#define SGIMC_MCONFIG_1M 0x00000300 /* 1M x 36 bits */ +#define SGIMC_MCONFIG_2M 0x00000700 /* 2M x 36 bits, 2 subbanks */ +#define SGIMC_MCONFIG_4M 0x00000f00 /* 4M x 36 bits */ +#define SGIMC_MCONFIG_8M 0x00001f00 /* 8M x 36 bits, 2 subbanks */ #define SGIMC_MCONFIG_RMASK 0x00001f00 /* Ram config bitmask */ +#define SGIMC_MCONFIG_BVALID 0x00002000 /* Bank is valid */ +#define SGIMC_MCONFIG_SBANKS 0x00004000 /* Number of subbanks */ u32 _unused13; volatile u32 cmacc; /* Mem access config for CPU */