setup.c 14.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1995 Linus Torvalds
 * Copyright (C) 1995 Waldorf Electronics
 * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03  Ralf Baechle
 * Copyright (C) 1996 Stoned Elipot
 * Copyright (C) 1999 Silicon Graphics, Inc.
11
 * Copyright (C) 2000, 2001, 2002, 2007  Maciej W. Rozycki
L
Linus Torvalds 已提交
12 13 14
 */
#include <linux/init.h>
#include <linux/ioport.h>
15
#include <linux/export.h>
16
#include <linux/screen_info.h>
T
Tejun Heo 已提交
17
#include <linux/memblock.h>
L
Linus Torvalds 已提交
18 19 20 21 22
#include <linux/bootmem.h>
#include <linux/initrd.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <linux/console.h>
D
Dave Hansen 已提交
23
#include <linux/pfn.h>
24
#include <linux/debugfs.h>
L
Linus Torvalds 已提交
25 26 27

#include <asm/addrspace.h>
#include <asm/bootinfo.h>
28
#include <asm/bugs.h>
R
Ralf Baechle 已提交
29
#include <asm/cache.h>
L
Linus Torvalds 已提交
30 31 32
#include <asm/cpu.h>
#include <asm/sections.h>
#include <asm/setup.h>
33
#include <asm/smp-ops.h>
34
#include <asm/prom.h>
L
Linus Torvalds 已提交
35

R
Ralf Baechle 已提交
36
struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
L
Linus Torvalds 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

EXPORT_SYMBOL(cpu_data);

#ifdef CONFIG_VT
struct screen_info screen_info;
#endif

/*
 * Despite it's name this variable is even if we don't have PCI
 */
unsigned int PCI_DMA_BUS_IS_PHYS;

EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS);

/*
 * Setup information
 *
 * These are initialized so they are in the .data section
 */
R
Ralf Baechle 已提交
56
unsigned long mips_machtype __read_mostly = MACH_UNKNOWN;
L
Linus Torvalds 已提交
57 58 59 60 61

EXPORT_SYMBOL(mips_machtype);

struct boot_mem_map boot_mem_map;

62 63 64 65 66 67
static char __initdata command_line[COMMAND_LINE_SIZE];
char __initdata arcs_cmdline[COMMAND_LINE_SIZE];

#ifdef CONFIG_CMDLINE_BOOL
static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
#endif
L
Linus Torvalds 已提交
68 69 70 71 72

/*
 * mips_io_port_base is the begin of the address space to which x86 style
 * I/O ports are mapped.
 */
D
David Daney 已提交
73
const unsigned long mips_io_port_base = -1;
L
Linus Torvalds 已提交
74 75 76 77 78 79 80 81 82 83
EXPORT_SYMBOL(mips_io_port_base);

static struct resource code_resource = { .name = "Kernel code", };
static struct resource data_resource = { .name = "Kernel data", };

void __init add_memory_region(phys_t start, phys_t size, long type)
{
	int x = boot_mem_map.nr_map;
	struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1;

84 85
	/* Sanity check */
	if (start + size < start) {
86
		pr_warning("Trying to add an invalid memory region, skipped\n");
87 88 89
		return;
	}

L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99
	/*
	 * Try to merge with previous entry if any.  This is far less than
	 * perfect but is sufficient for most real world cases.
	 */
	if (x && prev->addr + prev->size == start && prev->type == type) {
		prev->size += size;
		return;
	}

	if (x == BOOT_MEM_MAP_MAX) {
100
		pr_err("Ooops! Too many entries in the memory map!\n");
L
Linus Torvalds 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
		return;
	}

	boot_mem_map.map[x].addr = start;
	boot_mem_map.map[x].size = size;
	boot_mem_map.map[x].type = type;
	boot_mem_map.nr_map++;
}

static void __init print_memory_map(void)
{
	int i;
	const int field = 2 * sizeof(unsigned long);

	for (i = 0; i < boot_mem_map.nr_map; i++) {
116
		printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
L
Linus Torvalds 已提交
117 118 119 120 121
		       field, (unsigned long long) boot_mem_map.map[i].size,
		       field, (unsigned long long) boot_mem_map.map[i].addr);

		switch (boot_mem_map.map[i].type) {
		case BOOT_MEM_RAM:
122
			printk(KERN_CONT "(usable)\n");
L
Linus Torvalds 已提交
123
			break;
124 125 126
		case BOOT_MEM_INIT_RAM:
			printk(KERN_CONT "(usable after init)\n");
			break;
L
Linus Torvalds 已提交
127
		case BOOT_MEM_ROM_DATA:
128
			printk(KERN_CONT "(ROM data)\n");
L
Linus Torvalds 已提交
129 130
			break;
		case BOOT_MEM_RESERVED:
131
			printk(KERN_CONT "(reserved)\n");
L
Linus Torvalds 已提交
132 133
			break;
		default:
134
			printk(KERN_CONT "type %lu\n", boot_mem_map.map[i].type);
L
Linus Torvalds 已提交
135 136 137 138 139
			break;
		}
	}
}

140 141 142 143 144
/*
 * Manage initrd
 */
#ifdef CONFIG_BLK_DEV_INITRD

145
static int __init rd_start_early(char *p)
L
Linus Torvalds 已提交
146
{
147
	unsigned long start = memparse(p, &p);
L
Linus Torvalds 已提交
148

149
#ifdef CONFIG_64BIT
150 151 152
	/* Guess if the sign extension was forgotten by bootloader */
	if (start < XKPHYS)
		start = (int)start;
L
Linus Torvalds 已提交
153
#endif
154 155 156 157 158 159 160 161 162
	initrd_start = start;
	initrd_end += start;
	return 0;
}
early_param("rd_start", rd_start_early);

static int __init rd_size_early(char *p)
{
	initrd_end += memparse(p, &p);
L
Linus Torvalds 已提交
163 164
	return 0;
}
165
early_param("rd_size", rd_size_early);
L
Linus Torvalds 已提交
166

167
/* it returns the next free pfn after initrd */
168 169
static unsigned long __init init_initrd(void)
{
170
	unsigned long end;
171 172

	/*
173 174 175
	 * Board specific code or command line parser should have
	 * already set up initrd_start and initrd_end. In these cases
	 * perfom sanity checks and use them if all looks good.
176
	 */
177
	if (!initrd_start || initrd_end <= initrd_start)
178 179 180
		goto disable;

	if (initrd_start & ~PAGE_MASK) {
181
		pr_err("initrd start must be page aligned\n");
182
		goto disable;
183
	}
184
	if (initrd_start < PAGE_OFFSET) {
185
		pr_err("initrd start < PAGE_OFFSET\n");
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
		goto disable;
	}

	/*
	 * Sanitize initrd addresses. For example firmware
	 * can't guess if they need to pass them through
	 * 64-bits values if the kernel has been built in pure
	 * 32-bit. We need also to switch from KSEG0 to XKPHYS
	 * addresses now, so the code can now safely use __pa().
	 */
	end = __pa(initrd_end);
	initrd_end = (unsigned long)__va(end);
	initrd_start = (unsigned long)__va(__pa(initrd_start));

	ROOT_DEV = Root_RAM0;
	return PFN_UP(end);
disable:
	initrd_start = 0;
	initrd_end = 0;
	return 0;
206 207 208 209 210 211 212 213 214 215
}

static void __init finalize_initrd(void)
{
	unsigned long size = initrd_end - initrd_start;

	if (size == 0) {
		printk(KERN_INFO "Initrd not found or empty");
		goto disable;
	}
216
	if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
217
		printk(KERN_ERR "Initrd extends beyond end of memory");
218 219 220
		goto disable;
	}

221
	reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
222 223
	initrd_below_start_ok = 1;

224 225
	pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
		initrd_start, size);
226 227
	return;
disable:
228
	printk(KERN_CONT " - disabling initrd\n");
229 230 231 232 233 234
	initrd_start = 0;
	initrd_end = 0;
}

#else  /* !CONFIG_BLK_DEV_INITRD */

235 236 237 238 239
static unsigned long __init init_initrd(void)
{
	return 0;
}

240 241 242 243
#define finalize_initrd()	do {} while (0)

#endif

244 245 246 247
/*
 * Initialize the bootmem allocator. It also setup initrd related data
 * if needed.
 */
248 249
#ifdef CONFIG_SGI_IP27

250
static void __init bootmem_init(void)
L
Linus Torvalds 已提交
251
{
252 253 254 255 256 257 258 259
	init_initrd();
	finalize_initrd();
}

#else  /* !CONFIG_SGI_IP27 */

static void __init bootmem_init(void)
{
260
	unsigned long reserved_end;
261
	unsigned long mapstart = ~0UL;
L
Linus Torvalds 已提交
262 263 264 265
	unsigned long bootmap_size;
	int i;

	/*
266 267 268
	 * Init any data related to initrd. It's a nop if INITRD is
	 * not selected. Once that done we can determine the low bound
	 * of usable memory.
L
Linus Torvalds 已提交
269
	 */
270 271
	reserved_end = max(init_initrd(),
			   (unsigned long) PFN_UP(__pa_symbol(&_end)));
L
Linus Torvalds 已提交
272

273 274 275 276 277 278 279
	/*
	 * max_low_pfn is not a number of pages. The number of pages
	 * of the system is given by 'max_low_pfn - min_low_pfn'.
	 */
	min_low_pfn = ~0UL;
	max_low_pfn = 0;

280 281 282
	/*
	 * Find the highest page frame number we have available.
	 */
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290
	for (i = 0; i < boot_mem_map.nr_map; i++) {
		unsigned long start, end;

		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
			continue;

		start = PFN_UP(boot_mem_map.map[i].addr);
		end = PFN_DOWN(boot_mem_map.map[i].addr
291
				+ boot_mem_map.map[i].size);
L
Linus Torvalds 已提交
292

293 294 295 296
		if (end > max_low_pfn)
			max_low_pfn = end;
		if (start < min_low_pfn)
			min_low_pfn = start;
297
		if (end <= reserved_end)
L
Linus Torvalds 已提交
298
			continue;
299 300 301
		if (start >= mapstart)
			continue;
		mapstart = max(reserved_end, start);
L
Linus Torvalds 已提交
302 303
	}

304 305
	if (min_low_pfn >= max_low_pfn)
		panic("Incorrect memory mapping !!!");
306
	if (min_low_pfn > ARCH_PFN_OFFSET) {
307 308 309
		pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
			(min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
			min_low_pfn - ARCH_PFN_OFFSET);
310
	} else if (min_low_pfn < ARCH_PFN_OFFSET) {
311 312
		pr_info("%lu free pages won't be used\n",
			ARCH_PFN_OFFSET - min_low_pfn);
313
	}
314
	min_low_pfn = ARCH_PFN_OFFSET;
315

L
Linus Torvalds 已提交
316 317 318
	/*
	 * Determine low and high memory ranges
	 */
R
Ralf Baechle 已提交
319
	max_pfn = max_low_pfn;
320
	if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
321 322
#ifdef CONFIG_HIGHMEM
		highstart_pfn = PFN_DOWN(HIGHMEM_START);
323
		highend_pfn = max_low_pfn;
L
Linus Torvalds 已提交
324
#endif
325
		max_low_pfn = PFN_DOWN(HIGHMEM_START);
L
Linus Torvalds 已提交
326 327 328
	}

	/*
329
	 * Initialize the boot-time allocator with low memory only.
L
Linus Torvalds 已提交
330
	 */
331 332
	bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
					 min_low_pfn, max_low_pfn);
333 334 335 336 337 338 339 340 341


	for (i = 0; i < boot_mem_map.nr_map; i++) {
		unsigned long start, end;

		start = PFN_UP(boot_mem_map.map[i].addr);
		end = PFN_DOWN(boot_mem_map.map[i].addr
				+ boot_mem_map.map[i].size);

342 343
		if (start <= min_low_pfn)
			start = min_low_pfn;
344 345 346 347 348 349 350 351 352 353 354 355 356 357
		if (start >= end)
			continue;

#ifndef CONFIG_HIGHMEM
		if (end > max_low_pfn)
			end = max_low_pfn;

		/*
		 * ... finally, is the area going away?
		 */
		if (end <= start)
			continue;
#endif

T
Tejun Heo 已提交
358
		memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
359 360
	}

L
Linus Torvalds 已提交
361 362 363 364
	/*
	 * Register fully available low RAM pages with the bootmem allocator.
	 */
	for (i = 0; i < boot_mem_map.nr_map; i++) {
365
		unsigned long start, end, size;
L
Linus Torvalds 已提交
366

367 368 369 370
		start = PFN_UP(boot_mem_map.map[i].addr);
		end   = PFN_DOWN(boot_mem_map.map[i].addr
				    + boot_mem_map.map[i].size);

L
Linus Torvalds 已提交
371 372 373
		/*
		 * Reserve usable memory.
		 */
374 375 376 377 378
		switch (boot_mem_map.map[i].type) {
		case BOOT_MEM_RAM:
			break;
		case BOOT_MEM_INIT_RAM:
			memory_present(0, start, end);
L
Linus Torvalds 已提交
379
			continue;
380 381 382 383
		default:
			/* Not usable memory */
			continue;
		}
L
Linus Torvalds 已提交
384 385

		/*
386 387
		 * We are rounding up the start address of usable memory
		 * and at the end of the usable range downwards.
L
Linus Torvalds 已提交
388
		 */
389
		if (start >= max_low_pfn)
L
Linus Torvalds 已提交
390
			continue;
391 392 393 394
		if (start < reserved_end)
			start = reserved_end;
		if (end > max_low_pfn)
			end = max_low_pfn;
L
Linus Torvalds 已提交
395 396

		/*
397
		 * ... finally, is the area going away?
L
Linus Torvalds 已提交
398
		 */
399
		if (end <= start)
L
Linus Torvalds 已提交
400
			continue;
401
		size = end - start;
L
Linus Torvalds 已提交
402 403

		/* Register lowmem ranges */
404 405
		free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
		memory_present(0, start, end);
L
Linus Torvalds 已提交
406 407
	}

408 409 410
	/*
	 * Reserve the bootmap memory.
	 */
411
	reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
412

413 414 415 416
	/*
	 * Reserve initrd memory if needed.
	 */
	finalize_initrd();
L
Linus Torvalds 已提交
417 418
}

419 420
#endif	/* CONFIG_SGI_IP27 */

421
/*
J
Joe Perches 已提交
422
 * arch_mem_init - initialize memory management subsystem
423 424 425 426 427
 *
 *  o plat_mem_setup() detects the memory configuration and will record detected
 *    memory areas using add_memory_region.
 *
 * At this stage the memory configuration of the system is known to the
J
Joe Perches 已提交
428
 * kernel but generic memory management system is still entirely uninitialized.
429 430 431 432 433 434 435 436 437 438 439 440 441 442
 *
 *  o bootmem_init()
 *  o sparse_init()
 *  o paging_init()
 *
 * At this stage the bootmem allocator is ready to use.
 *
 * NOTE: historically plat_mem_setup did the entire platform initialization.
 *       This was rather impractical because it meant plat_mem_setup had to
 * get away without any kind of memory allocator.  To keep old code from
 * breaking plat_setup was just renamed to plat_setup and a second platform
 * initialization hook for anything else was introduced.
 */

443
static int usermem __initdata;
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466

static int __init early_parse_mem(char *p)
{
	unsigned long start, size;

	/*
	 * If a user specifies memory size, we
	 * blow away any automatically generated
	 * size.
	 */
	if (usermem == 0) {
		boot_mem_map.nr_map = 0;
		usermem = 1;
 	}
	start = 0;
	size = memparse(p, &p);
	if (*p == '@')
		start = memparse(p + 1, &p);

	add_memory_region(start, size, BOOT_MEM_RAM);
	return 0;
}
early_param("mem", early_parse_mem);
467 468 469

static void __init arch_mem_init(char **cmdline_p)
{
470 471
	phys_t init_mem, init_end, init_size;

472 473
	extern void plat_mem_setup(void);

474 475 476
	/* call board setup routine */
	plat_mem_setup();

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
	init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT;
	init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT;
	init_size = init_end - init_mem;
	if (init_size) {
		/* Make sure it is in the boot_mem_map */
		int i, found;
		found = 0;
		for (i = 0; i < boot_mem_map.nr_map; i++) {
			if (init_mem >= boot_mem_map.map[i].addr &&
			    init_mem < (boot_mem_map.map[i].addr +
					boot_mem_map.map[i].size)) {
				found = 1;
				break;
			}
		}
		if (!found)
			add_memory_region(init_mem, init_size,
					  BOOT_MEM_INIT_RAM);
	}

497
	pr_info("Determined physical RAM map:\n");
498 499
	print_memory_map();

500 501 502 503 504 505 506 507 508 509 510 511 512 513
#ifdef CONFIG_CMDLINE_BOOL
#ifdef CONFIG_CMDLINE_OVERRIDE
	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
	if (builtin_cmdline[0]) {
		strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
		strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE);
	}
	strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
#endif
#else
	strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
#endif
	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
514 515 516

	*cmdline_p = command_line;

517 518 519
	parse_early_param();

	if (usermem) {
520
		pr_info("User-defined physical RAM map:\n");
521 522 523
		print_memory_map();
	}

524
	bootmem_init();
525
	device_tree_init();
526
	sparse_init();
527
	plat_swiotlb_setup();
528 529 530
	paging_init();
}

531
static void __init resource_init(void)
L
Linus Torvalds 已提交
532 533 534
{
	int i;

535 536 537
	if (UNCAC_BASE != IO_BASE)
		return;

538 539 540 541
	code_resource.start = __pa_symbol(&_text);
	code_resource.end = __pa_symbol(&_etext) - 1;
	data_resource.start = __pa_symbol(&_etext);
	data_resource.end = __pa_symbol(&_edata) - 1;
L
Linus Torvalds 已提交
542 543 544 545 546 547 548 549 550 551

	/*
	 * Request address space for all standard RAM.
	 */
	for (i = 0; i < boot_mem_map.nr_map; i++) {
		struct resource *res;
		unsigned long start, end;

		start = boot_mem_map.map[i].addr;
		end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
552
		if (start >= HIGHMEM_START)
L
Linus Torvalds 已提交
553
			continue;
554 555
		if (end >= HIGHMEM_START)
			end = HIGHMEM_START - 1;
L
Linus Torvalds 已提交
556 557 558 559

		res = alloc_bootmem(sizeof(struct resource));
		switch (boot_mem_map.map[i].type) {
		case BOOT_MEM_RAM:
560
		case BOOT_MEM_INIT_RAM:
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
		case BOOT_MEM_ROM_DATA:
			res->name = "System RAM";
			break;
		case BOOT_MEM_RESERVED:
		default:
			res->name = "reserved";
		}

		res->start = start;
		res->end = end;

		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
		request_resource(&iomem_resource, res);

		/*
		 *  We don't know which RAM region contains kernel data,
		 *  so we try it repeatedly and let the resource manager
		 *  test it.
		 */
		request_resource(res, &code_resource);
		request_resource(res, &data_resource);
	}
}

void __init setup_arch(char **cmdline_p)
{
	cpu_probe();
	prom_init();
589 590

#ifdef CONFIG_EARLY_PRINTK
591
	setup_early_printk();
592
#endif
L
Linus Torvalds 已提交
593
	cpu_report();
594
	check_bugs_early();
L
Linus Torvalds 已提交
595 596 597

#if defined(CONFIG_VT)
#if defined(CONFIG_VGA_CONSOLE)
R
Ralf Baechle 已提交
598
	conswitchp = &vga_con;
L
Linus Torvalds 已提交
599
#elif defined(CONFIG_DUMMY_CONSOLE)
R
Ralf Baechle 已提交
600
	conswitchp = &dummy_con;
L
Linus Torvalds 已提交
601 602 603
#endif
#endif

604
	arch_mem_init(cmdline_p);
L
Linus Torvalds 已提交
605 606

	resource_init();
607
	plat_smp_setup();
L
Linus Torvalds 已提交
608 609
}

610 611
unsigned long kernelsp[NR_CPUS];
unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
612 613 614 615 616 617 618 619

#ifdef CONFIG_DEBUG_FS
struct dentry *mips_debugfs_dir;
static int __init debugfs_mips(void)
{
	struct dentry *d;

	d = debugfs_create_dir("mips", NULL);
620 621
	if (!d)
		return -ENOMEM;
622 623 624 625 626
	mips_debugfs_dir = d;
	return 0;
}
arch_initcall(debugfs_mips);
#endif