OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [arch/] [s390/] [kernel/] [setup.c] - Blame information for rev 63

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 63 marcus.erl
/*
2
 *  arch/s390/kernel/setup.c
3
 *
4
 *  S390 version
5
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6
 *    Author(s): Hartmut Penner (hp@de.ibm.com),
7
 *               Martin Schwidefsky (schwidefsky@de.ibm.com)
8
 *
9
 *  Derived from "arch/i386/kernel/setup.c"
10
 *    Copyright (C) 1995, Linus Torvalds
11
 */
12
 
13
/*
14
 * This file handles the architecture-dependent parts of initialization
15
 */
16
 
17
#include <linux/errno.h>
18
#include <linux/module.h>
19
#include <linux/sched.h>
20
#include <linux/kernel.h>
21
#include <linux/mm.h>
22
#include <linux/stddef.h>
23
#include <linux/unistd.h>
24
#include <linux/ptrace.h>
25
#include <linux/slab.h>
26
#include <linux/user.h>
27
#include <linux/a.out.h>
28
#include <linux/tty.h>
29
#include <linux/ioport.h>
30
#include <linux/delay.h>
31
#include <linux/init.h>
32
#include <linux/initrd.h>
33
#include <linux/bootmem.h>
34
#include <linux/root_dev.h>
35
#include <linux/console.h>
36
#include <linux/seq_file.h>
37
#include <linux/kernel_stat.h>
38
#include <linux/device.h>
39
#include <linux/notifier.h>
40
#include <linux/pfn.h>
41
#include <linux/ctype.h>
42
#include <linux/reboot.h>
43
 
44
#include <asm/ipl.h>
45
#include <asm/uaccess.h>
46
#include <asm/system.h>
47
#include <asm/smp.h>
48
#include <asm/mmu_context.h>
49
#include <asm/cpcmd.h>
50
#include <asm/lowcore.h>
51
#include <asm/irq.h>
52
#include <asm/page.h>
53
#include <asm/ptrace.h>
54
#include <asm/sections.h>
55
#include <asm/ebcdic.h>
56
#include <asm/compat.h>
57
 
58
long psw_kernel_bits    = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
59
                           PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
60
long psw_user_bits      = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
61
                           PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
62
                           PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
63
 
64
/*
65
 * User copy operations.
66
 */
67
struct uaccess_ops uaccess;
68
EXPORT_SYMBOL(uaccess);
69
 
70
/*
71
 * Machine setup..
72
 */
73
unsigned int console_mode = 0;
74
unsigned int console_devno = -1;
75
unsigned int console_irq = -1;
76
unsigned long machine_flags = 0;
77
unsigned long elf_hwcap = 0;
78
char elf_platform[ELF_PLATFORM_SIZE];
79
 
80
struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
81
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
82
static unsigned long __initdata memory_end;
83
 
84
/*
85
 * This is set up by the setup-routine at boot-time
86
 * for S390 need to find out, what we have to setup
87
 * using address 0x10400 ...
88
 */
89
 
90
#include <asm/setup.h>
91
 
92
static struct resource code_resource = {
93
        .name  = "Kernel code",
94
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
95
};
96
 
97
static struct resource data_resource = {
98
        .name = "Kernel data",
99
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
100
};
101
 
102
/*
103
 * cpu_init() initializes state that is per-CPU.
104
 */
105
void __cpuinit cpu_init(void)
106
{
107
        int addr = hard_smp_processor_id();
108
 
109
        /*
110
         * Store processor id in lowcore (used e.g. in timer_interrupt)
111
         */
112
        get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
113
        S390_lowcore.cpu_data.cpu_addr = addr;
114
 
115
        /*
116
         * Force FPU initialization:
117
         */
118
        clear_thread_flag(TIF_USEDFPU);
119
        clear_used_math();
120
 
121
        atomic_inc(&init_mm.mm_count);
122
        current->active_mm = &init_mm;
123
        if (current->mm)
124
                BUG();
125
        enter_lazy_tlb(&init_mm, current);
126
}
127
 
128
/*
129
 * VM halt and poweroff setup routines
130
 */
131
char vmhalt_cmd[128] = "";
132
char vmpoff_cmd[128] = "";
133
static char vmpanic_cmd[128] = "";
134
 
135
static void strncpy_skip_quote(char *dst, char *src, int n)
136
{
137
        int sx, dx;
138
 
139
        dx = 0;
140
        for (sx = 0; src[sx] != 0; sx++) {
141
                if (src[sx] == '"') continue;
142
                dst[dx++] = src[sx];
143
                if (dx >= n) break;
144
        }
145
}
146
 
147
static int __init vmhalt_setup(char *str)
148
{
149
        strncpy_skip_quote(vmhalt_cmd, str, 127);
150
        vmhalt_cmd[127] = 0;
151
        return 1;
152
}
153
 
154
__setup("vmhalt=", vmhalt_setup);
155
 
156
static int __init vmpoff_setup(char *str)
157
{
158
        strncpy_skip_quote(vmpoff_cmd, str, 127);
159
        vmpoff_cmd[127] = 0;
160
        return 1;
161
}
162
 
163
__setup("vmpoff=", vmpoff_setup);
164
 
165
static int vmpanic_notify(struct notifier_block *self, unsigned long event,
166
                          void *data)
167
{
168
        if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
169
                cpcmd(vmpanic_cmd, NULL, 0, NULL);
170
 
171
        return NOTIFY_OK;
172
}
173
 
174
#define PANIC_PRI_VMPANIC       0
175
 
176
static struct notifier_block vmpanic_nb = {
177
        .notifier_call = vmpanic_notify,
178
        .priority = PANIC_PRI_VMPANIC
179
};
180
 
181
static int __init vmpanic_setup(char *str)
182
{
183
        static int register_done __initdata = 0;
184
 
185
        strncpy_skip_quote(vmpanic_cmd, str, 127);
186
        vmpanic_cmd[127] = 0;
187
        if (!register_done) {
188
                register_done = 1;
189
                atomic_notifier_chain_register(&panic_notifier_list,
190
                                               &vmpanic_nb);
191
        }
192
        return 1;
193
}
194
 
195
__setup("vmpanic=", vmpanic_setup);
196
 
197
/*
198
 * condev= and conmode= setup parameter.
199
 */
200
 
201
static int __init condev_setup(char *str)
202
{
203
        int vdev;
204
 
205
        vdev = simple_strtoul(str, &str, 0);
206
        if (vdev >= 0 && vdev < 65536) {
207
                console_devno = vdev;
208
                console_irq = -1;
209
        }
210
        return 1;
211
}
212
 
213
__setup("condev=", condev_setup);
214
 
215
static int __init conmode_setup(char *str)
216
{
217
#if defined(CONFIG_SCLP_CONSOLE)
218
        if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
219
                SET_CONSOLE_SCLP;
220
#endif
221
#if defined(CONFIG_TN3215_CONSOLE)
222
        if (strncmp(str, "3215", 5) == 0)
223
                SET_CONSOLE_3215;
224
#endif
225
#if defined(CONFIG_TN3270_CONSOLE)
226
        if (strncmp(str, "3270", 5) == 0)
227
                SET_CONSOLE_3270;
228
#endif
229
        return 1;
230
}
231
 
232
__setup("conmode=", conmode_setup);
233
 
234
static void __init conmode_default(void)
235
{
236
        char query_buffer[1024];
237
        char *ptr;
238
 
239
        if (MACHINE_IS_VM) {
240
                cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL);
241
                console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
242
                ptr = strstr(query_buffer, "SUBCHANNEL =");
243
                console_irq = simple_strtoul(ptr + 13, NULL, 16);
244
                cpcmd("QUERY TERM", query_buffer, 1024, NULL);
245
                ptr = strstr(query_buffer, "CONMODE");
246
                /*
247
                 * Set the conmode to 3215 so that the device recognition
248
                 * will set the cu_type of the console to 3215. If the
249
                 * conmode is 3270 and we don't set it back then both
250
                 * 3215 and the 3270 driver will try to access the console
251
                 * device (3215 as console and 3270 as normal tty).
252
                 */
253
                cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
254
                if (ptr == NULL) {
255
#if defined(CONFIG_SCLP_CONSOLE)
256
                        SET_CONSOLE_SCLP;
257
#endif
258
                        return;
259
                }
260
                if (strncmp(ptr + 8, "3270", 4) == 0) {
261
#if defined(CONFIG_TN3270_CONSOLE)
262
                        SET_CONSOLE_3270;
263
#elif defined(CONFIG_TN3215_CONSOLE)
264
                        SET_CONSOLE_3215;
265
#elif defined(CONFIG_SCLP_CONSOLE)
266
                        SET_CONSOLE_SCLP;
267
#endif
268
                } else if (strncmp(ptr + 8, "3215", 4) == 0) {
269
#if defined(CONFIG_TN3215_CONSOLE)
270
                        SET_CONSOLE_3215;
271
#elif defined(CONFIG_TN3270_CONSOLE)
272
                        SET_CONSOLE_3270;
273
#elif defined(CONFIG_SCLP_CONSOLE)
274
                        SET_CONSOLE_SCLP;
275
#endif
276
                }
277
        } else if (MACHINE_IS_P390) {
278
#if defined(CONFIG_TN3215_CONSOLE)
279
                SET_CONSOLE_3215;
280
#elif defined(CONFIG_TN3270_CONSOLE)
281
                SET_CONSOLE_3270;
282
#endif
283
        } else {
284
#if defined(CONFIG_SCLP_CONSOLE)
285
                SET_CONSOLE_SCLP;
286
#endif
287
        }
288
}
289
 
290
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
291
static void __init setup_zfcpdump(unsigned int console_devno)
292
{
293
        static char str[64];
294
 
295
        if (ipl_info.type != IPL_TYPE_FCP_DUMP)
296
                return;
297
        if (console_devno != -1)
298
                sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x",
299
                        ipl_info.data.fcp.dev_id.devno, console_devno);
300
        else
301
                sprintf(str, "cio_ignore=all,!0.0.%04x",
302
                        ipl_info.data.fcp.dev_id.devno);
303
        strcat(COMMAND_LINE, " ");
304
        strcat(COMMAND_LINE, str);
305
        console_loglevel = 2;
306
}
307
#else
308
static inline void setup_zfcpdump(unsigned int console_devno) {}
309
#endif /* CONFIG_ZFCPDUMP */
310
 
311
#ifdef CONFIG_SMP
312
void (*_machine_restart)(char *command) = machine_restart_smp;
313
void (*_machine_halt)(void) = machine_halt_smp;
314
void (*_machine_power_off)(void) = machine_power_off_smp;
315
#else
316
/*
317
 * Reboot, halt and power_off routines for non SMP.
318
 */
319
static void do_machine_restart_nonsmp(char * __unused)
320
{
321
        do_reipl();
322
}
323
 
324
static void do_machine_halt_nonsmp(void)
325
{
326
        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
327
                __cpcmd(vmhalt_cmd, NULL, 0, NULL);
328
        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
329
}
330
 
331
static void do_machine_power_off_nonsmp(void)
332
{
333
        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
334
                __cpcmd(vmpoff_cmd, NULL, 0, NULL);
335
        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
336
}
337
 
338
void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
339
void (*_machine_halt)(void) = do_machine_halt_nonsmp;
340
void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
341
#endif
342
 
343
 /*
344
 * Reboot, halt and power_off stubs. They just call _machine_restart,
345
 * _machine_halt or _machine_power_off.
346
 */
347
 
348
void machine_restart(char *command)
349
{
350
        if ((!in_interrupt() && !in_atomic()) || oops_in_progress)
351
                /*
352
                 * Only unblank the console if we are called in enabled
353
                 * context or a bust_spinlocks cleared the way for us.
354
                 */
355
                console_unblank();
356
        _machine_restart(command);
357
}
358
 
359
void machine_halt(void)
360
{
361
        if (!in_interrupt() || oops_in_progress)
362
                /*
363
                 * Only unblank the console if we are called in enabled
364
                 * context or a bust_spinlocks cleared the way for us.
365
                 */
366
                console_unblank();
367
        _machine_halt();
368
}
369
 
370
void machine_power_off(void)
371
{
372
        if (!in_interrupt() || oops_in_progress)
373
                /*
374
                 * Only unblank the console if we are called in enabled
375
                 * context or a bust_spinlocks cleared the way for us.
376
                 */
377
                console_unblank();
378
        _machine_power_off();
379
}
380
 
381
/*
382
 * Dummy power off function.
383
 */
384
void (*pm_power_off)(void) = machine_power_off;
385
 
386
static int __init early_parse_mem(char *p)
387
{
388
        memory_end = memparse(p, &p);
389
        return 0;
390
}
391
early_param("mem", early_parse_mem);
392
 
393
/*
394
 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
395
 */
396
static int __init early_parse_ipldelay(char *p)
397
{
398
        unsigned long delay = 0;
399
 
400
        delay = simple_strtoul(p, &p, 0);
401
 
402
        switch (*p) {
403
        case 's':
404
        case 'S':
405
                delay *= 1000000;
406
                break;
407
        case 'm':
408
        case 'M':
409
                delay *= 60 * 1000000;
410
        }
411
 
412
        /* now wait for the requested amount of time */
413
        udelay(delay);
414
 
415
        return 0;
416
}
417
early_param("ipldelay", early_parse_ipldelay);
418
 
419
#ifdef CONFIG_S390_SWITCH_AMODE
420
unsigned int switch_amode = 0;
421
EXPORT_SYMBOL_GPL(switch_amode);
422
 
423
static void set_amode_and_uaccess(unsigned long user_amode,
424
                                  unsigned long user32_amode)
425
{
426
        psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
427
                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
428
                        PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
429
#ifdef CONFIG_COMPAT
430
        psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
431
                          PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
432
                          PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
433
        psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
434
                          PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
435
                          PSW32_MASK_PSTATE;
436
#endif
437
        psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
438
                          PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
439
 
440
        if (MACHINE_HAS_MVCOS) {
441
                printk("mvcos available.\n");
442
                memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
443
        } else {
444
                printk("mvcos not available.\n");
445
                memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
446
        }
447
}
448
 
449
/*
450
 * Switch kernel/user addressing modes?
451
 */
452
static int __init early_parse_switch_amode(char *p)
453
{
454
        switch_amode = 1;
455
        return 0;
456
}
457
early_param("switch_amode", early_parse_switch_amode);
458
 
459
#else /* CONFIG_S390_SWITCH_AMODE */
460
static inline void set_amode_and_uaccess(unsigned long user_amode,
461
                                         unsigned long user32_amode)
462
{
463
}
464
#endif /* CONFIG_S390_SWITCH_AMODE */
465
 
466
#ifdef CONFIG_S390_EXEC_PROTECT
467
unsigned int s390_noexec = 0;
468
EXPORT_SYMBOL_GPL(s390_noexec);
469
 
470
/*
471
 * Enable execute protection?
472
 */
473
static int __init early_parse_noexec(char *p)
474
{
475
        if (!strncmp(p, "off", 3))
476
                return 0;
477
        switch_amode = 1;
478
        s390_noexec = 1;
479
        return 0;
480
}
481
early_param("noexec", early_parse_noexec);
482
#endif /* CONFIG_S390_EXEC_PROTECT */
483
 
484
static void setup_addressing_mode(void)
485
{
486
        if (s390_noexec) {
487
                printk("S390 execute protection active, ");
488
                set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
489
        } else if (switch_amode) {
490
                printk("S390 address spaces switched, ");
491
                set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
492
        }
493
#ifdef CONFIG_TRACE_IRQFLAGS
494
        sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
495
        io_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
496
#endif
497
}
498
 
499
static void __init
500
setup_lowcore(void)
501
{
502
        struct _lowcore *lc;
503
        int lc_pages;
504
 
505
        /*
506
         * Setup lowcore for boot cpu
507
         */
508
        lc_pages = sizeof(void *) == 8 ? 2 : 1;
509
        lc = (struct _lowcore *)
510
                __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0);
511
        memset(lc, 0, lc_pages * PAGE_SIZE);
512
        lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
513
        lc->restart_psw.addr =
514
                PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
515
        if (switch_amode)
516
                lc->restart_psw.mask |= PSW_ASC_HOME;
517
        lc->external_new_psw.mask = psw_kernel_bits;
518
        lc->external_new_psw.addr =
519
                PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
520
        lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
521
        lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
522
        lc->program_new_psw.mask = psw_kernel_bits;
523
        lc->program_new_psw.addr =
524
                PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
525
        lc->mcck_new_psw.mask =
526
                psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
527
        lc->mcck_new_psw.addr =
528
                PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
529
        lc->io_new_psw.mask = psw_kernel_bits;
530
        lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
531
        lc->ipl_device = S390_lowcore.ipl_device;
532
        lc->jiffy_timer = -1LL;
533
        lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
534
        lc->async_stack = (unsigned long)
535
                __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
536
        lc->panic_stack = (unsigned long)
537
                __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
538
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
539
        lc->thread_info = (unsigned long) &init_thread_union;
540
#ifndef CONFIG_64BIT
541
        if (MACHINE_HAS_IEEE) {
542
                lc->extended_save_area_addr = (__u32)
543
                        __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
544
                /* enable extended save area */
545
                __ctl_set_bit(14, 29);
546
        }
547
#endif
548
        set_prefix((u32)(unsigned long) lc);
549
}
550
 
551
static void __init
552
setup_resources(void)
553
{
554
        struct resource *res, *sub_res;
555
        int i;
556
 
557
        code_resource.start = (unsigned long) &_text;
558
        code_resource.end = (unsigned long) &_etext - 1;
559
        data_resource.start = (unsigned long) &_etext;
560
        data_resource.end = (unsigned long) &_edata - 1;
561
 
562
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
563
                res = alloc_bootmem_low(sizeof(struct resource));
564
                res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
565
                switch (memory_chunk[i].type) {
566
                case CHUNK_READ_WRITE:
567
                        res->name = "System RAM";
568
                        break;
569
                case CHUNK_READ_ONLY:
570
                        res->name = "System ROM";
571
                        res->flags |= IORESOURCE_READONLY;
572
                        break;
573
                default:
574
                        res->name = "reserved";
575
                }
576
                res->start = memory_chunk[i].addr;
577
                res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
578
                request_resource(&iomem_resource, res);
579
 
580
                if (code_resource.start >= res->start  &&
581
                        code_resource.start <= res->end &&
582
                        code_resource.end > res->end) {
583
                        sub_res = alloc_bootmem_low(sizeof(struct resource));
584
                        memcpy(sub_res, &code_resource,
585
                                sizeof(struct resource));
586
                        sub_res->end = res->end;
587
                        code_resource.start = res->end + 1;
588
                        request_resource(res, sub_res);
589
                }
590
 
591
                if (code_resource.start >= res->start &&
592
                        code_resource.start <= res->end &&
593
                        code_resource.end <= res->end)
594
                        request_resource(res, &code_resource);
595
 
596
                if (data_resource.start >= res->start &&
597
                        data_resource.start <= res->end &&
598
                        data_resource.end > res->end) {
599
                        sub_res = alloc_bootmem_low(sizeof(struct resource));
600
                        memcpy(sub_res, &data_resource,
601
                                sizeof(struct resource));
602
                        sub_res->end = res->end;
603
                        data_resource.start = res->end + 1;
604
                        request_resource(res, sub_res);
605
                }
606
 
607
                if (data_resource.start >= res->start &&
608
                        data_resource.start <= res->end &&
609
                        data_resource.end <= res->end)
610
                        request_resource(res, &data_resource);
611
        }
612
}
613
 
614
unsigned long real_memory_size;
615
EXPORT_SYMBOL_GPL(real_memory_size);
616
 
617
static void __init setup_memory_end(void)
618
{
619
        unsigned long memory_size;
620
        unsigned long max_mem, max_phys;
621
        int i;
622
 
623
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
624
        if (ipl_info.type == IPL_TYPE_FCP_DUMP)
625
                memory_end = ZFCPDUMP_HSA_SIZE;
626
#endif
627
        memory_size = 0;
628
        max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
629
        memory_end &= PAGE_MASK;
630
 
631
        max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
632
 
633
        for (i = 0; i < MEMORY_CHUNKS; i++) {
634
                struct mem_chunk *chunk = &memory_chunk[i];
635
 
636
                real_memory_size = max(real_memory_size,
637
                                       chunk->addr + chunk->size);
638
                if (chunk->addr >= max_mem) {
639
                        memset(chunk, 0, sizeof(*chunk));
640
                        continue;
641
                }
642
                if (chunk->addr + chunk->size > max_mem)
643
                        chunk->size = max_mem - chunk->addr;
644
                memory_size = max(memory_size, chunk->addr + chunk->size);
645
        }
646
        if (!memory_end)
647
                memory_end = memory_size;
648
}
649
 
650
static void __init
651
setup_memory(void)
652
{
653
        unsigned long bootmap_size;
654
        unsigned long start_pfn, end_pfn;
655
        int i;
656
 
657
        /*
658
         * partially used pages are not usable - thus
659
         * we are rounding upwards:
660
         */
661
        start_pfn = PFN_UP(__pa(&_end));
662
        end_pfn = max_pfn = PFN_DOWN(memory_end);
663
 
664
#ifdef CONFIG_BLK_DEV_INITRD
665
        /*
666
         * Move the initrd in case the bitmap of the bootmem allocater
667
         * would overwrite it.
668
         */
669
 
670
        if (INITRD_START && INITRD_SIZE) {
671
                unsigned long bmap_size;
672
                unsigned long start;
673
 
674
                bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1);
675
                bmap_size = PFN_PHYS(bmap_size);
676
 
677
                if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) {
678
                        start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
679
 
680
                        if (start + INITRD_SIZE > memory_end) {
681
                                printk("initrd extends beyond end of memory "
682
                                       "(0x%08lx > 0x%08lx)\n"
683
                                       "disabling initrd\n",
684
                                       start + INITRD_SIZE, memory_end);
685
                                INITRD_START = INITRD_SIZE = 0;
686
                        } else {
687
                                printk("Moving initrd (0x%08lx -> 0x%08lx, "
688
                                       "size: %ld)\n",
689
                                       INITRD_START, start, INITRD_SIZE);
690
                                memmove((void *) start, (void *) INITRD_START,
691
                                        INITRD_SIZE);
692
                                INITRD_START = start;
693
                        }
694
                }
695
        }
696
#endif
697
 
698
        /*
699
         * Initialize the boot-time allocator
700
         */
701
        bootmap_size = init_bootmem(start_pfn, end_pfn);
702
 
703
        /*
704
         * Register RAM areas with the bootmem allocator.
705
         */
706
 
707
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
708
                unsigned long start_chunk, end_chunk, pfn;
709
 
710
                if (memory_chunk[i].type != CHUNK_READ_WRITE)
711
                        continue;
712
                start_chunk = PFN_DOWN(memory_chunk[i].addr);
713
                end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1;
714
                end_chunk = min(end_chunk, end_pfn);
715
                if (start_chunk >= end_chunk)
716
                        continue;
717
                add_active_range(0, start_chunk, end_chunk);
718
                pfn = max(start_chunk, start_pfn);
719
                for (; pfn <= end_chunk; pfn++)
720
                        page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
721
        }
722
 
723
        psw_set_key(PAGE_DEFAULT_KEY);
724
 
725
        free_bootmem_with_active_regions(0, max_pfn);
726
 
727
        /*
728
         * Reserve memory used for lowcore/command line/kernel image.
729
         */
730
        reserve_bootmem(0, (unsigned long)_ehead);
731
        reserve_bootmem((unsigned long)_stext,
732
                        PFN_PHYS(start_pfn) - (unsigned long)_stext);
733
        /*
734
         * Reserve the bootmem bitmap itself as well. We do this in two
735
         * steps (first step was init_bootmem()) because this catches
736
         * the (very unlikely) case of us accidentally initializing the
737
         * bootmem allocator with an invalid RAM area.
738
         */
739
        reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
740
 
741
#ifdef CONFIG_BLK_DEV_INITRD
742
        if (INITRD_START && INITRD_SIZE) {
743
                if (INITRD_START + INITRD_SIZE <= memory_end) {
744
                        reserve_bootmem(INITRD_START, INITRD_SIZE);
745
                        initrd_start = INITRD_START;
746
                        initrd_end = initrd_start + INITRD_SIZE;
747
                } else {
748
                        printk("initrd extends beyond end of memory "
749
                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
750
                               initrd_start + INITRD_SIZE, memory_end);
751
                        initrd_start = initrd_end = 0;
752
                }
753
        }
754
#endif
755
}
756
 
757
static __init unsigned int stfl(void)
758
{
759
        asm volatile(
760
                "       .insn   s,0xb2b10000,0(0)\n" /* stfl */
761
                "0:\n"
762
                EX_TABLE(0b,0b));
763
        return S390_lowcore.stfl_fac_list;
764
}
765
 
766
static __init int stfle(unsigned long long *list, int doublewords)
767
{
768
        typedef struct { unsigned long long _[doublewords]; } addrtype;
769
        register unsigned long __nr asm("0") = doublewords - 1;
770
 
771
        asm volatile(".insn s,0xb2b00000,%0" /* stfle */
772
                     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
773
        return __nr + 1;
774
}
775
 
776
/*
777
 * Setup hardware capabilities.
778
 */
779
static void __init setup_hwcaps(void)
780
{
781
        static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
782
        struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
783
        unsigned long long facility_list_extended;
784
        unsigned int facility_list;
785
        int i;
786
 
787
        facility_list = stfl();
788
        /*
789
         * The store facility list bits numbers as found in the principles
790
         * of operation are numbered with bit 1UL<<31 as number 0 to
791
         * bit 1UL<<0 as number 31.
792
         *   Bit 0: instructions named N3, "backported" to esa-mode
793
         *   Bit 2: z/Architecture mode is active
794
         *   Bit 7: the store-facility-list-extended facility is installed
795
         *   Bit 17: the message-security assist is installed
796
         *   Bit 19: the long-displacement facility is installed
797
         *   Bit 21: the extended-immediate facility is installed
798
         * These get translated to:
799
         *   HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1,
800
         *   HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3,
801
         *   HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5.
802
         */
803
        for (i = 0; i < 6; i++)
804
                if (facility_list & (1UL << (31 - stfl_bits[i])))
805
                        elf_hwcap |= 1UL << i;
806
 
807
        /*
808
         * Check for additional facilities with store-facility-list-extended.
809
         * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0
810
         * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information
811
         * as stored by stfl, bits 32-xxx contain additional facilities.
812
         * How many facility words are stored depends on the number of
813
         * doublewords passed to the instruction. The additional facilites
814
         * are:
815
         *   Bit 43: decimal floating point facility is installed
816
         * translated to:
817
         *   HWCAP_S390_DFP bit 6.
818
         */
819
        if ((elf_hwcap & (1UL << 2)) &&
820
            stfle(&facility_list_extended, 1) > 0) {
821
                if (facility_list_extended & (1ULL << (64 - 43)))
822
                        elf_hwcap |= 1UL << 6;
823
        }
824
 
825
        switch (cpuinfo->cpu_id.machine) {
826
        case 0x9672:
827
#if !defined(CONFIG_64BIT)
828
        default:        /* Use "g5" as default for 31 bit kernels. */
829
#endif
830
                strcpy(elf_platform, "g5");
831
                break;
832
        case 0x2064:
833
        case 0x2066:
834
#if defined(CONFIG_64BIT)
835
        default:        /* Use "z900" as default for 64 bit kernels. */
836
#endif
837
                strcpy(elf_platform, "z900");
838
                break;
839
        case 0x2084:
840
        case 0x2086:
841
                strcpy(elf_platform, "z990");
842
                break;
843
        case 0x2094:
844
                strcpy(elf_platform, "z9-109");
845
                break;
846
        }
847
}
848
 
849
/*
850
 * Setup function called from init/main.c just after the banner
851
 * was printed.
852
 */
853
 
854
void __init
855
setup_arch(char **cmdline_p)
856
{
857
        /*
858
         * print what head.S has found out about the machine
859
         */
860
#ifndef CONFIG_64BIT
861
        printk((MACHINE_IS_VM) ?
862
               "We are running under VM (31 bit mode)\n" :
863
               "We are running native (31 bit mode)\n");
864
        printk((MACHINE_HAS_IEEE) ?
865
               "This machine has an IEEE fpu\n" :
866
               "This machine has no IEEE fpu\n");
867
#else /* CONFIG_64BIT */
868
        printk((MACHINE_IS_VM) ?
869
               "We are running under VM (64 bit mode)\n" :
870
               "We are running native (64 bit mode)\n");
871
#endif /* CONFIG_64BIT */
872
 
873
        /* Save unparsed command line copy for /proc/cmdline */
874
        strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
875
 
876
        *cmdline_p = COMMAND_LINE;
877
        *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0';
878
 
879
        ROOT_DEV = Root_RAM0;
880
 
881
        init_mm.start_code = PAGE_OFFSET;
882
        init_mm.end_code = (unsigned long) &_etext;
883
        init_mm.end_data = (unsigned long) &_edata;
884
        init_mm.brk = (unsigned long) &_end;
885
 
886
        if (MACHINE_HAS_MVCOS)
887
                memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess));
888
        else
889
                memcpy(&uaccess, &uaccess_std, sizeof(uaccess));
890
 
891
        parse_early_param();
892
 
893
        setup_ipl_info();
894
        setup_memory_end();
895
        setup_addressing_mode();
896
        setup_memory();
897
        setup_resources();
898
        setup_lowcore();
899
 
900
        cpu_init();
901
        __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
902
        smp_setup_cpu_possible_map();
903
 
904
        /*
905
         * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
906
         */
907
        setup_hwcaps();
908
 
909
        /*
910
         * Create kernel page tables and switch to virtual addressing.
911
         */
912
        paging_init();
913
 
914
        /* Setup default console */
915
        conmode_default();
916
 
917
        /* Setup zfcpdump support */
918
        setup_zfcpdump(console_devno);
919
}
920
 
921
void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
922
{
923
   printk("cpu %d "
924
#ifdef CONFIG_SMP
925
           "phys_idx=%d "
926
#endif
927
           "vers=%02X ident=%06X machine=%04X unused=%04X\n",
928
           cpuinfo->cpu_nr,
929
#ifdef CONFIG_SMP
930
           cpuinfo->cpu_addr,
931
#endif
932
           cpuinfo->cpu_id.version,
933
           cpuinfo->cpu_id.ident,
934
           cpuinfo->cpu_id.machine,
935
           cpuinfo->cpu_id.unused);
936
}
937
 
938
/*
939
 * show_cpuinfo - Get information on one CPU for use by procfs.
940
 */
941
 
942
static int show_cpuinfo(struct seq_file *m, void *v)
943
{
944
        static const char *hwcap_str[7] = {
945
                "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp"
946
        };
947
        struct cpuinfo_S390 *cpuinfo;
948
        unsigned long n = (unsigned long) v - 1;
949
        int i;
950
 
951
        s390_adjust_jiffies();
952
        preempt_disable();
953
        if (!n) {
954
                seq_printf(m, "vendor_id       : IBM/S390\n"
955
                               "# processors    : %i\n"
956
                               "bogomips per cpu: %lu.%02lu\n",
957
                               num_online_cpus(), loops_per_jiffy/(500000/HZ),
958
                               (loops_per_jiffy/(5000/HZ))%100);
959
                seq_puts(m, "features\t: ");
960
                for (i = 0; i < 7; i++)
961
                        if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
962
                                seq_printf(m, "%s ", hwcap_str[i]);
963
                seq_puts(m, "\n");
964
        }
965
 
966
        if (cpu_online(n)) {
967
#ifdef CONFIG_SMP
968
                if (smp_processor_id() == n)
969
                        cpuinfo = &S390_lowcore.cpu_data;
970
                else
971
                        cpuinfo = &lowcore_ptr[n]->cpu_data;
972
#else
973
                cpuinfo = &S390_lowcore.cpu_data;
974
#endif
975
                seq_printf(m, "processor %li: "
976
                               "version = %02X,  "
977
                               "identification = %06X,  "
978
                               "machine = %04X\n",
979
                               n, cpuinfo->cpu_id.version,
980
                               cpuinfo->cpu_id.ident,
981
                               cpuinfo->cpu_id.machine);
982
        }
983
        preempt_enable();
984
        return 0;
985
}
986
 
987
static void *c_start(struct seq_file *m, loff_t *pos)
988
{
989
        return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
990
}
991
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
992
{
993
        ++*pos;
994
        return c_start(m, pos);
995
}
996
static void c_stop(struct seq_file *m, void *v)
997
{
998
}
999
struct seq_operations cpuinfo_op = {
1000
        .start  = c_start,
1001
        .next   = c_next,
1002
        .stop   = c_stop,
1003
        .show   = show_cpuinfo,
1004
};
1005
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.