setup.c 17.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *  arch/s390/kernel/setup.c
 *
 *  S390 version
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Author(s): Hartmut Penner (hp@de.ibm.com),
 *               Martin Schwidefsky (schwidefsky@de.ibm.com)
 *
 *  Derived from "arch/i386/kernel/setup.c"
 *    Copyright (C) 1995, Linus Torvalds
 */

/*
 * This file handles the architecture-dependent parts of initialization
 */

#include <linux/errno.h>
18
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
19 20 21 22 23 24
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
Linus Torvalds's avatar
Linus Torvalds committed
25
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29 30 31 32
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/init.h>
Christoph Hellwig's avatar
Christoph Hellwig committed
33
#include <linux/initrd.h>
Linus Torvalds's avatar
Linus Torvalds committed
34
#include <linux/bootmem.h>
Alexander Viro's avatar
Alexander Viro committed
35
#include <linux/root_dev.h>
Linus Torvalds's avatar
Linus Torvalds committed
36
#include <linux/console.h>
Linus Torvalds's avatar
Linus Torvalds committed
37
#include <linux/seq_file.h>
38 39
#include <linux/kernel_stat.h>

Linus Torvalds's avatar
Linus Torvalds committed
40 41 42 43
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/smp.h>
#include <asm/mmu_context.h>
Linus Torvalds's avatar
Linus Torvalds committed
44
#include <asm/cpcmd.h>
45
#include <asm/lowcore.h>
46
#include <asm/irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49 50

/*
 * Machine setup..
 */
Linus Torvalds's avatar
Linus Torvalds committed
51 52
unsigned int console_mode = 0;
unsigned int console_device = -1;
53
unsigned int console_irq = -1;
Linus Torvalds's avatar
Linus Torvalds committed
54 55
unsigned long memory_size = 0;
unsigned long machine_flags = 0;
56
struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
Linus Torvalds's avatar
Linus Torvalds committed
57 58
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
Linus Torvalds's avatar
Linus Torvalds committed
59
int cpus_initialized = 0;
60
static cpumask_t cpu_initialized;
Linus Torvalds's avatar
Linus Torvalds committed
61
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
Linus Torvalds's avatar
Linus Torvalds committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

/*
 * Setup options
 */
extern int _text,_etext, _edata, _end;

/*
 * This is set up by the setup-routine at boot-time
 * for S390 need to find out, what we have to setup
 * using address 0x10400 ...
 */

#include <asm/setup.h>

static char command_line[COMMAND_LINE_SIZE] = { 0, };
       char saved_command_line[COMMAND_LINE_SIZE];

static struct resource code_resource = { "Kernel code", 0x100000, 0 };
static struct resource data_resource = { "Kernel data", 0, 0 };

/*
 * cpu_init() initializes state that is per-CPU.
 */
85
void __devinit cpu_init (void)
Linus Torvalds's avatar
Linus Torvalds committed
86 87
{
        int nr = smp_processor_id();
Linus Torvalds's avatar
Linus Torvalds committed
88
        int addr = hard_smp_processor_id();
Linus Torvalds's avatar
Linus Torvalds committed
89

90
        if (cpu_test_and_set(nr,cpu_initialized)) {
Linus Torvalds's avatar
Linus Torvalds committed
91
                printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
92
                for (;;) local_irq_enable();
Linus Torvalds's avatar
Linus Torvalds committed
93 94 95 96 97 98 99
        }
        cpus_initialized++;

        /*
         * Store processor id in lowcore (used e.g. in timer_interrupt)
         */
        asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
Linus Torvalds's avatar
Linus Torvalds committed
100
        S390_lowcore.cpu_data.cpu_addr = addr;
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103 104

        /*
         * Force FPU initialization:
         */
105
        clear_thread_flag(TIF_USEDFPU);
Linus Torvalds's avatar
Linus Torvalds committed
106 107 108 109 110 111 112
        current->used_math = 0;

        /* Setup active_mm for idle_task  */
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
        if (current->mm)
                BUG();
113
        enter_lazy_tlb(&init_mm, current);
Linus Torvalds's avatar
Linus Torvalds committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
}

/*
 * VM halt and poweroff setup routines
 */
char vmhalt_cmd[128] = "";
char vmpoff_cmd[128] = "";

static inline void strncpy_skip_quote(char *dst, char *src, int n)
{
        int sx, dx;

        dx = 0;
        for (sx = 0; src[sx] != 0; sx++) {
                if (src[sx] == '"') continue;
                dst[dx++] = src[sx];
                if (dx >= n) break;
        }
}

static int __init vmhalt_setup(char *str)
{
        strncpy_skip_quote(vmhalt_cmd, str, 127);
        vmhalt_cmd[127] = 0;
        return 1;
}

__setup("vmhalt=", vmhalt_setup);

static int __init vmpoff_setup(char *str)
{
        strncpy_skip_quote(vmpoff_cmd, str, 127);
        vmpoff_cmd[127] = 0;
        return 1;
}

__setup("vmpoff=", vmpoff_setup);

Linus Torvalds's avatar
Linus Torvalds committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/*
 * condev= and conmode= setup parameter.
 */

static int __init condev_setup(char *str)
{
	int vdev;

	vdev = simple_strtoul(str, &str, 0);
	if (vdev >= 0 && vdev < 65536)
		console_device = vdev;
	return 1;
}

__setup("condev=", condev_setup);

static int __init conmode_setup(char *str)
{
170 171 172
#if defined(CONFIG_SCLP_CONSOLE)
	if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
                SET_CONSOLE_SCLP;
Linus Torvalds's avatar
Linus Torvalds committed
173 174
#endif
#if defined(CONFIG_TN3215_CONSOLE)
175
	if (strncmp(str, "3215", 5) == 0)
Linus Torvalds's avatar
Linus Torvalds committed
176 177 178
		SET_CONSOLE_3215;
#endif
#if defined(CONFIG_TN3270_CONSOLE)
179
	if (strncmp(str, "3270", 5) == 0)
Linus Torvalds's avatar
Linus Torvalds committed
180 181 182 183 184 185 186 187 188 189 190 191 192
		SET_CONSOLE_3270;
#endif
        return 1;
}

__setup("conmode=", conmode_setup);

static void __init conmode_default(void)
{
	char query_buffer[1024];
	char *ptr;

        if (MACHINE_IS_VM) {
193 194 195 196
		cpcmd("QUERY CONSOLE", query_buffer, 1024);
		console_device = simple_strtoul(query_buffer + 5, NULL, 16);
		ptr = strstr(query_buffer, "SUBCHANNEL =");
		console_irq = simple_strtoul(ptr + 13, NULL, 16);
Linus Torvalds's avatar
Linus Torvalds committed
197 198 199 200 201 202 203 204 205 206 207
		cpcmd("QUERY TERM", query_buffer, 1024);
		ptr = strstr(query_buffer, "CONMODE");
		/*
		 * Set the conmode to 3215 so that the device recognition 
		 * will set the cu_type of the console to 3215. If the
		 * conmode is 3270 and we don't set it back then both
		 * 3215 and the 3270 driver will try to access the console
		 * device (3215 as console and 3270 as normal tty).
		 */
		cpcmd("TERM CONMODE 3215", NULL, 0);
		if (ptr == NULL) {
208 209
#if defined(CONFIG_SCLP_CONSOLE)
			SET_CONSOLE_SCLP;
Linus Torvalds's avatar
Linus Torvalds committed
210 211 212 213 214 215 216 217
#endif
			return;
		}
		if (strncmp(ptr + 8, "3270", 4) == 0) {
#if defined(CONFIG_TN3270_CONSOLE)
			SET_CONSOLE_3270;
#elif defined(CONFIG_TN3215_CONSOLE)
			SET_CONSOLE_3215;
218 219
#elif defined(CONFIG_SCLP_CONSOLE)
			SET_CONSOLE_SCLP;
Linus Torvalds's avatar
Linus Torvalds committed
220 221 222 223 224 225
#endif
		} else if (strncmp(ptr + 8, "3215", 4) == 0) {
#if defined(CONFIG_TN3215_CONSOLE)
			SET_CONSOLE_3215;
#elif defined(CONFIG_TN3270_CONSOLE)
			SET_CONSOLE_3270;
226 227
#elif defined(CONFIG_SCLP_CONSOLE)
			SET_CONSOLE_SCLP;
Linus Torvalds's avatar
Linus Torvalds committed
228 229 230 231 232 233 234 235 236
#endif
		}
        } else if (MACHINE_IS_P390) {
#if defined(CONFIG_TN3215_CONSOLE)
		SET_CONSOLE_3215;
#elif defined(CONFIG_TN3270_CONSOLE)
		SET_CONSOLE_3270;
#endif
	} else {
237 238
#if defined(CONFIG_SCLP_CONSOLE)
		SET_CONSOLE_SCLP;
Linus Torvalds's avatar
Linus Torvalds committed
239 240 241 242
#endif
	}
}

243 244 245 246 247 248 249 250 251
#ifdef CONFIG_SMP
extern void machine_restart_smp(char *);
extern void machine_halt_smp(void);
extern void machine_power_off_smp(void);

void (*_machine_restart)(char *command) = machine_restart_smp;
void (*_machine_halt)(void) = machine_halt_smp;
void (*_machine_power_off)(void) = machine_power_off_smp;
#else
Linus Torvalds's avatar
Linus Torvalds committed
252 253 254
/*
 * Reboot, halt and power_off routines for non SMP.
 */
255
extern void do_reipl(unsigned long devno);
256
static void do_machine_restart_nonsmp(char * __unused)
Linus Torvalds's avatar
Linus Torvalds committed
257
{
258 259 260 261
	if (MACHINE_IS_VM)
		cpcmd ("IPL", NULL, 0);
	else
		do_reipl (0x10000 | S390_lowcore.ipl_device);
Linus Torvalds's avatar
Linus Torvalds committed
262 263
}

264
static void do_machine_halt_nonsmp(void)
Linus Torvalds's avatar
Linus Torvalds committed
265 266 267
{
        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                cpcmd(vmhalt_cmd, NULL, 0);
Linus Torvalds's avatar
Linus Torvalds committed
268
        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
Linus Torvalds's avatar
Linus Torvalds committed
269 270
}

271
static void do_machine_power_off_nonsmp(void)
Linus Torvalds's avatar
Linus Torvalds committed
272 273 274
{
        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                cpcmd(vmpoff_cmd, NULL, 0);
Linus Torvalds's avatar
Linus Torvalds committed
275
        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
Linus Torvalds's avatar
Linus Torvalds committed
276
}
277 278 279 280

void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
void (*_machine_halt)(void) = do_machine_halt_nonsmp;
void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
Linus Torvalds's avatar
Linus Torvalds committed
281 282
#endif

283 284 285 286 287 288 289 290 291 292
 /*
 * Reboot, halt and power_off stubs. They just call _machine_restart,
 * _machine_halt or _machine_power_off. 
 */

void machine_restart(char *command)
{
	_machine_restart(command);
}

293 294
EXPORT_SYMBOL(machine_restart);

295 296 297 298 299
void machine_halt(void)
{
	_machine_halt();
}

300 301
EXPORT_SYMBOL(machine_halt);

302 303 304 305 306
void machine_power_off(void)
{
	_machine_power_off();
}

307 308
EXPORT_SYMBOL(machine_power_off);

Linus Torvalds's avatar
Linus Torvalds committed
309 310 311 312
/*
 * Setup function called from init/main.c just after the banner
 * was printed.
 */
Linus Torvalds's avatar
Linus Torvalds committed
313 314
extern char _pstart, _pend, _stext;

Linus Torvalds's avatar
Linus Torvalds committed
315 316 317 318
void __init setup_arch(char **cmdline_p)
{
        unsigned long bootmap_size;
        unsigned long memory_start, memory_end;
Linus Torvalds's avatar
Linus Torvalds committed
319
        char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
Linus Torvalds's avatar
Linus Torvalds committed
320 321 322 323
	struct resource *res;
	unsigned long start_pfn, end_pfn;
        static unsigned int smptrap=0;
        unsigned long delay = 0;
324
	struct _lowcore *lc;
Linus Torvalds's avatar
Linus Torvalds committed
325
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328 329 330 331 332 333

        if (smptrap)
                return;
        smptrap=1;

        /*
         * print what head.S has found out about the machine 
         */
334
#ifndef CONFIG_ARCH_S390X
Linus Torvalds's avatar
Linus Torvalds committed
335
	printk((MACHINE_IS_VM) ?
336 337
	       "We are running under VM (31 bit mode)\n" :
	       "We are running native (31 bit mode)\n");
Linus Torvalds's avatar
Linus Torvalds committed
338 339 340
	printk((MACHINE_HAS_IEEE) ?
	       "This machine has an IEEE fpu\n" :
	       "This machine has no IEEE fpu\n");
341 342 343 344 345
#else /* CONFIG_ARCH_S390X */
	printk((MACHINE_IS_VM) ?
	       "We are running under VM (64 bit mode)\n" :
	       "We are running native (64 bit mode)\n");
#endif /* CONFIG_ARCH_S390X */
Linus Torvalds's avatar
Linus Torvalds committed
346

Alexander Viro's avatar
Alexander Viro committed
347
        ROOT_DEV = Root_RAM0;
Linus Torvalds's avatar
Linus Torvalds committed
348
        memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
349
#ifndef CONFIG_ARCH_S390X
Linus Torvalds's avatar
Linus Torvalds committed
350
	memory_end = memory_size & ~0x400000UL;  /* align memory end to 4MB */
Linus Torvalds's avatar
Linus Torvalds committed
351 352 353 354 355 356 357
        /*
         * We need some free virtual space to be able to do vmalloc.
         * On a machine with 2GB memory we make sure that we have at
         * least 128 MB free space for vmalloc.
         */
        if (memory_end > 1920*1024*1024)
                memory_end = 1920*1024*1024;
358 359 360
#else /* CONFIG_ARCH_S390X */
	memory_end = memory_size & ~0x200000UL;  /* detected in head.s */
#endif /* CONFIG_ARCH_S390X */
Linus Torvalds's avatar
Linus Torvalds committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
        init_mm.start_code = PAGE_OFFSET;
        init_mm.end_code = (unsigned long) &_etext;
        init_mm.end_data = (unsigned long) &_edata;
        init_mm.brk = (unsigned long) &_end;

	code_resource.start = (unsigned long) &_text;
	code_resource.end = (unsigned long) &_etext - 1;
	data_resource.start = (unsigned long) &_etext;
	data_resource.end = (unsigned long) &_edata - 1;

        /* Save unparsed command line copy for /proc/cmdline */
        memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
        saved_command_line[COMMAND_LINE_SIZE-1] = '\0';

        for (;;) {
                /*
                 * "mem=XXX[kKmM]" sets memsize 
                 */
                if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
                        memory_end = simple_strtoul(from+4, &from, 0);
                        if ( *from == 'K' || *from == 'k' ) {
                                memory_end = memory_end << 10;
                                from++;
                        } else if ( *from == 'M' || *from == 'm' ) {
                                memory_end = memory_end << 20;
                                from++;
                        }
                }
                /*
                 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
                 */
                if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
                        delay = simple_strtoul(from+9, &from, 0);
			if (*from == 's' || *from == 'S') {
				delay = delay*1000000;
				from++;
			} else if (*from == 'm' || *from == 'M') {
				delay = delay*60*1000000;
				from++;
			}
Linus Torvalds's avatar
Linus Torvalds committed
401
			/* now wait for the requested amount of time */
Linus Torvalds's avatar
Linus Torvalds committed
402
			udelay(delay);
Linus Torvalds's avatar
Linus Torvalds committed
403
                }
Linus Torvalds's avatar
Linus Torvalds committed
404 405
                cn = *(from++);
                if (!cn)
Linus Torvalds's avatar
Linus Torvalds committed
406
                        break;
Linus Torvalds's avatar
Linus Torvalds committed
407 408
                if (cn == '\n')
                        cn = ' ';  /* replace newlines with space */
Linus Torvalds's avatar
Linus Torvalds committed
409 410
		if (cn == 0x0d)
			cn = ' ';  /* replace 0x0d with space */
Linus Torvalds's avatar
Linus Torvalds committed
411 412 413 414
                if (cn == ' ' && c == ' ')
                        continue;  /* remove additional spaces */
                c = cn;
                if (to - command_line >= COMMAND_LINE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
415 416 417
                        break;
                *(to++) = c;
        }
Linus Torvalds's avatar
Linus Torvalds committed
418
        if (c == ' ' && to > command_line) to--;
Linus Torvalds's avatar
Linus Torvalds committed
419 420 421 422 423 424 425 426
        *to = '\0';
        *cmdline_p = command_line;

	/*
	 * partially used pages are not usable - thus
	 * we are rounding upwards:
	 */
	start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
427
	end_pfn = max_pfn = memory_end >> PAGE_SHIFT;
Linus Torvalds's avatar
Linus Torvalds committed
428 429 430 431 432 433 434

	/*
	 * Initialize the boot-time allocator (with low memory only):
	 */
	bootmap_size = init_bootmem(start_pfn, end_pfn);

	/*
Linus Torvalds's avatar
Linus Torvalds committed
435
	 * Register RAM areas with the bootmem allocator.
Linus Torvalds's avatar
Linus Torvalds committed
436
	 */
Linus Torvalds's avatar
Linus Torvalds committed
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
	for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
		unsigned long start_chunk, end_chunk;

		if (memory_chunk[i].type != CHUNK_READ_WRITE)
			continue;
		start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
		start_chunk >>= PAGE_SHIFT;
		end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
		end_chunk >>= PAGE_SHIFT;
		if (start_chunk < start_pfn)
			start_chunk = start_pfn;
		if (end_chunk > end_pfn)
			end_chunk = end_pfn;
		if (start_chunk < end_chunk)
			free_bootmem(start_chunk << PAGE_SHIFT,
				     (end_chunk - start_chunk) << PAGE_SHIFT);
	}
Linus Torvalds's avatar
Linus Torvalds committed
454 455 456 457 458 459 460 461 462 463 464

        /*
         * Reserve the bootmem bitmap itself as well. We do this in two
         * steps (first step was init_bootmem()) because this catches
         * the (very unlikely) case of us accidentally initializing the
         * bootmem allocator with an invalid RAM area.
         */
        reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);

#ifdef CONFIG_BLK_DEV_INITRD
        if (INITRD_START) {
Linus Torvalds's avatar
Linus Torvalds committed
465
		if (INITRD_START + INITRD_SIZE <= memory_end) {
Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469 470 471 472 473 474 475 476
			reserve_bootmem(INITRD_START, INITRD_SIZE);
			initrd_start = INITRD_START;
			initrd_end = initrd_start + INITRD_SIZE;
		} else {
                        printk("initrd extends beyond end of memory "
                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
                               initrd_start + INITRD_SIZE, memory_end);
                        initrd_start = initrd_end = 0;
		}
        }
#endif
Linus Torvalds's avatar
Linus Torvalds committed
477

Linus Torvalds's avatar
Linus Torvalds committed
478 479 480
        /*
         * Setup lowcore for boot cpu
         */
481
#ifndef CONFIG_ARCH_S390X
482 483
	lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
	memset(lc, 0, PAGE_SIZE);
484 485 486 487
#else /* CONFIG_ARCH_S390X */
	lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
	memset(lc, 0, 2*PAGE_SIZE);
#endif /* CONFIG_ARCH_S390X */
488
	lc->restart_psw.mask = PSW_BASE_BITS;
489 490
	lc->restart_psw.addr =
		PSW_ADDR_AMODE + (unsigned long) restart_int_handler;
491
	lc->external_new_psw.mask = PSW_KERNEL_BITS;
492 493
	lc->external_new_psw.addr =
		PSW_ADDR_AMODE + (unsigned long) ext_int_handler;
494
	lc->svc_new_psw.mask = PSW_KERNEL_BITS;
495
	lc->svc_new_psw.addr = PSW_ADDR_AMODE + (unsigned long) system_call;
496
	lc->program_new_psw.mask = PSW_KERNEL_BITS;
497 498 499 500 501
	lc->program_new_psw.addr =
		PSW_ADDR_AMODE + (unsigned long)pgm_check_handler;
	lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
	lc->mcck_new_psw.addr =
		PSW_ADDR_AMODE + (unsigned long) mcck_int_handler;
502
	lc->io_new_psw.mask = PSW_KERNEL_BITS;
503
	lc->io_new_psw.addr = PSW_ADDR_AMODE + (unsigned long) io_int_handler;
504
	lc->ipl_device = S390_lowcore.ipl_device;
505
	lc->jiffy_timer = -1LL;
506 507 508 509 510
	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
	lc->async_stack = (unsigned long)
		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
#ifdef CONFIG_ARCH_S390X
511 512 513 514 515
	if (MACHINE_HAS_DIAG44)
		lc->diag44_opcode = 0x83000044;
	else
		lc->diag44_opcode = 0x07000700;
#endif /* CONFIG_ARCH_S390X */
516
	set_prefix((u32)(unsigned long) lc);
Linus Torvalds's avatar
Linus Torvalds committed
517
        cpu_init();
518
        __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
Linus Torvalds's avatar
Linus Torvalds committed
519 520 521 522

	/*
	 * Create kernel page tables and switch to virtual addressing.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
523 524
        paging_init();

Linus Torvalds's avatar
Linus Torvalds committed
525 526 527 528 529 530 531
	res = alloc_bootmem_low(sizeof(struct resource));
	res->start = 0;
	res->end = memory_end;
	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
	request_resource(&iomem_resource, res);
	request_resource(res, &code_resource);
	request_resource(res, &data_resource);
Linus Torvalds's avatar
Linus Torvalds committed
532 533 534

        /* Setup default console */
	conmode_default();
Linus Torvalds's avatar
Linus Torvalds committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
}

void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
{
   printk("cpu %d "
#ifdef CONFIG_SMP
           "phys_idx=%d "
#endif
           "vers=%02X ident=%06X machine=%04X unused=%04X\n",
           cpuinfo->cpu_nr,
#ifdef CONFIG_SMP
           cpuinfo->cpu_addr,
#endif
           cpuinfo->cpu_id.version,
           cpuinfo->cpu_id.ident,
           cpuinfo->cpu_id.machine,
           cpuinfo->cpu_id.unused);
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
555
 * show_cpuinfo - Get information on one CPU for use by procfs.
Linus Torvalds's avatar
Linus Torvalds committed
556 557
 */

Linus Torvalds's avatar
Linus Torvalds committed
558
static int show_cpuinfo(struct seq_file *m, void *v)
Linus Torvalds's avatar
Linus Torvalds committed
559 560
{
        struct cpuinfo_S390 *cpuinfo;
561
	unsigned long n = (unsigned long) v - 1;
Linus Torvalds's avatar
Linus Torvalds committed
562

563
	if (!n) {
Linus Torvalds's avatar
Linus Torvalds committed
564
		seq_printf(m, "vendor_id       : IBM/S390\n"
Linus Torvalds's avatar
Linus Torvalds committed
565 566
			       "# processors    : %i\n"
			       "bogomips per cpu: %lu.%02lu\n",
567
			       num_online_cpus(), loops_per_jiffy/(500000/HZ),
Linus Torvalds's avatar
Linus Torvalds committed
568
			       (loops_per_jiffy/(5000/HZ))%100);
569
	}
570
	if (cpu_online(n)) {
571
#ifdef CONFIG_SMP
572 573 574 575
		if (smp_processor_id() == n)
			cpuinfo = &S390_lowcore.cpu_data;
		else
			cpuinfo = &lowcore_ptr[n]->cpu_data;
576 577 578
#else
		cpuinfo = &S390_lowcore.cpu_data;
#endif
579
		seq_printf(m, "processor %li: "
Linus Torvalds's avatar
Linus Torvalds committed
580 581 582 583 584 585
			       "version = %02X,  "
			       "identification = %06X,  "
			       "machine = %04X\n",
			       n, cpuinfo->cpu_id.version,
			       cpuinfo->cpu_id.ident,
			       cpuinfo->cpu_id.machine);
Linus Torvalds's avatar
Linus Torvalds committed
586
	}
Linus Torvalds's avatar
Linus Torvalds committed
587
        return 0;
Linus Torvalds's avatar
Linus Torvalds committed
588 589
}

Linus Torvalds's avatar
Linus Torvalds committed
590 591
static void *c_start(struct seq_file *m, loff_t *pos)
{
592
	return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
Linus Torvalds's avatar
Linus Torvalds committed
593 594 595 596 597 598 599 600 601 602
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
	++*pos;
	return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
struct seq_operations cpuinfo_op = {
603 604 605 606
	.start	= c_start,
	.next	= c_next,
	.stop	= c_stop,
	.show	= show_cpuinfo,
Linus Torvalds's avatar
Linus Torvalds committed
607
};
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

/*
 * show_interrupts is needed by /proc/interrupts.
 */

static const char *intrclass_names[] = {
	"EXT",
	"I/O",
};

int show_interrupts(struct seq_file *p, void *v)
{
        int i, j;
	
        seq_puts(p, "           ");
	
        for (j=0; j<NR_CPUS; j++)
                if (cpu_online(j))
                        seq_printf(p, "CPU%d       ",j);
	
        seq_putc(p, '\n');
	
        for (i = 0 ; i < NR_IRQS ; i++) {
		seq_printf(p, "%s: ", intrclass_names[i]);
#ifndef CONFIG_SMP
		seq_printf(p, "%10u ", kstat_irqs(i));
#else
		for (j = 0; j < NR_CPUS; j++)
			if (cpu_online(j))
				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
                seq_putc(p, '\n');
		
        }
	
        return 0;
}