Commit ebbde003 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (24/27): boot sequence.

Rework boot sequence on s390:

Traditionally, device detection os s390 is done completely
at a _very_ early stage during bootup (from init_irq(),
i.e. before memory management or the console are there).

This has always been a bad idea, but now it broke even more
since the linux driver model requires devices detection
to take place after the core_initcalls are done.

We now do only a small amount of scanning (probably
less in the future) at the early stage, the bulk of it
is done from a proper subsys_initcall(). This requires
some changes in related areas:

- the machine check handler initialization is split in
  two halves, since we want to catch major machine malfunctions
  as early as possible, but device machine checks can only
  be caught after the channel subsystem is up.

- some functions that are called from the css initialization
  made some assumptions of when to use kmalloc or bootmem_alloc,
  which were broken anyway. We fix this here and hopefully
  can get rid of bootmem_alloc for the css completely in the future.

- the debug logging feature for s390 was not used for functions
  in the initialization before, since it requires the memory
  management to be working. Now that we can be sure that it
  works, some special cases can be removed.

Now that these changes are done, a partial implementation of the
device model for the channel subsystem is possible, but at this
point, none of the device drivers make use of that yet.
parent 2abb6c50
......@@ -21,6 +21,7 @@
#include <asm/semaphore.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h>
......@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock);
static int initialized = 0;
static int initialized;
static struct file_operations debug_file_ops = {
read: debug_output,
......@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT;
if (!initialized)
debug_init();
BUG();
down(&debug_lock);
/* create new debug_info */
......@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature
*/
int debug_init(void)
static int __init debug_init(void)
{
int rc = 0;
down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
}
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
up(&debug_lock);
return rc;
......@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
}
/*
* init_module:
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
* clean up module
*/
void cleanup_module(void)
void __exit debug_exit(void)
{
#ifdef DEBUG
printk("debug_cleanup_module: \n");
......@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return;
}
#endif /* MODULE */
/*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
......
......@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/*
* cpu_init() initializes state that is per-CPU.
*/
void __init cpu_init (void)
void __devinit cpu_init (void)
{
int nr = smp_processor_id();
int addr = hard_smp_processor_id();
......
......@@ -454,7 +454,7 @@ extern void init_cpu_timer(void);
extern int pfault_init(void);
extern int pfault_token(void);
int __init start_secondary(void *cpuvoid)
int __devinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
......@@ -474,7 +474,7 @@ int __init start_secondary(void *cpuvoid)
return cpu_idle(NULL);
}
static struct task_struct *__init fork_by_hand(void)
static struct task_struct *__devinit fork_by_hand(void)
{
struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never
......
......@@ -21,6 +21,7 @@
#include <asm/semaphore.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h>
......@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock);
static int initialized = 0;
static int initialized;
static struct file_operations debug_file_ops = {
read: debug_output,
......@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT;
if (!initialized)
debug_init();
BUG();
down(&debug_lock);
/* create new debug_info */
......@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature
*/
int debug_init(void)
static int __init debug_init(void)
{
int rc = 0;
down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
}
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
up(&debug_lock);
return rc;
......@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
}
/*
* init_module:
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
* clean up module
*/
void cleanup_module(void)
void __exit debug_exit(void)
{
#ifdef DEBUG
printk("debug_cleanup_module: \n");
......@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return;
}
#endif /* MODULE */
/*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
......
......@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/*
* cpu_init() initializes state that is per-CPU.
*/
void __init cpu_init (void)
void __devinit cpu_init (void)
{
int nr = smp_processor_id();
int addr = hard_smp_processor_id();
......
......@@ -435,7 +435,7 @@ void __init smp_check_cpus(unsigned int max_cpus)
extern void init_cpu_timer(void);
extern int pfault_init(void);
int __init start_secondary(void *cpuvoid)
int __devinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
......@@ -455,7 +455,7 @@ int __init start_secondary(void *cpuvoid)
return cpu_idle(NULL);
}
static struct task_struct * __init fork_by_hand(void)
static struct task_struct * __devinit fork_by_hand(void)
{
struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never
......
......@@ -7,8 +7,9 @@ export-objs := s390dyn.o qdio.o
obj-$(CONFIG_QDIO) += qdio.o
obj-y += s390mach.o s390dyn.o sysinfo.o
obj-y += block/ char/ misc/ net/ cio/
obj-y += cio/ block/ char/ misc/ net/
drivers-y += drivers/s390/built-in.o
include $(TOPDIR)/Rules.make
......@@ -693,13 +693,12 @@ static int raw3215_startup(raw3215_info *raw)
if (raw->flags & RAW3215_ACTIVE)
return 0;
if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
"3215 terminal driver", &raw->devstat) != 0)
if (s390_request_console_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
"3215 terminal driver", &raw->devstat) != 0)
return -1;
raw->line_pos = 0;
raw->flags |= RAW3215_ACTIVE;
s390irq_spin_lock_irqsave(raw->irq, flags);
set_cons_dev(raw->irq);
raw3215_try_io(raw);
s390irq_spin_unlock_irqrestore(raw->irq, flags);
......@@ -1064,7 +1063,6 @@ void __init con3215_init(void)
/* Check if 3215 is to be the console */
if (!CONSOLE_IS_3215)
return;
irq = raw3215_find_dev(0);
/* Set the console mode for VM */
if (MACHINE_IS_VM) {
......@@ -1072,6 +1070,22 @@ void __init con3215_init(void)
cpcmd("TERM AUTOCR OFF", NULL, 0);
}
if (console_device != -1) {
/* use the device number that was specified on the
* command line */
irq = raw3215_find_dev(0);
} else if (MACHINE_IS_VM) {
/* under VM, the console is at device number 0009
* by default, so try that */
irq = get_irq_by_devno(0x0009);
} else {
/* unlike in 2.4, we cannot autoprobe here, since
* the channel subsystem is not fully initialized.
* With some luck, the HWC console can take over */
printk(KERN_WARNING "3215 console not found\n");
return;
}
/* allocate 3215 request structures */
raw3215_freelist = NULL;
spin_lock_init(&raw3215_freelist_lock);
......
/*
* drivers/s390/cio/cio_debug.c
* S/390 common I/O routines -- message ids for debugging
* $Revision: 1.4 $
* $Revision: 1.5 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -69,4 +69,4 @@ cio_debug_init (void)
return ret;
}
__initcall (cio_debug_init);
arch_initcall (cio_debug_init);
/*
* drivers/s390/cio/requestirq.c
* S/390 common I/O routines --
* $Revision: 1.7 $
* $Revision: 1.12 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -122,6 +122,34 @@ s390_request_irq (unsigned int irq,
NULL, irqflags, devname, dev_id);
}
int
s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
int ret;
unsigned long flags;
s390_device_recognition_irq (irq);
ret = s390_request_irq_special (irq, (io_handler_func_t) handler,
NULL, irqflags, devname, dev_id);
if (ret)
goto out;
s390irq_spin_lock_irqsave(irq, flags);
ret = set_cons_dev(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
if (ret)
free_irq(irq, dev_id);
out:
return ret;
}
/*
* request_irq wrapper
*/
......@@ -151,7 +179,7 @@ s390_free_irq (unsigned int irq, void *dev_id)
s390irq_spin_lock_irqsave (irq, flags);
CIO_DEBUG_NOCONS(irq,KERN_DEBUG, printk, 2,
CIO_DEBUG_NOCONS(irq,KERN_DEBUG, DBG, 2,
"Trying to free IRQ %d\n",
irq);
......
This diff is collapsed.
......@@ -11,6 +11,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/completion.h>
#ifdef CONFIG_SMP
#include <linux/smp.h>
#endif
......@@ -51,6 +52,7 @@ static spinlock_t mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t crw_queue_lock = SPIN_LOCK_UNLOCKED;
static struct semaphore s_sem;
static DECLARE_COMPLETION(mchchk_thread_active);
#ifdef CONFIG_MACHCHK_WARNING
static int mchchk_wng_posted = 0;
......@@ -103,14 +105,15 @@ s390_init_machine_check(void)
kernel_thread(s390_machine_check_handler, &s_sem,
CLONE_FS | CLONE_FILES);
wait_for_completion(&mchchk_thread_active);
ctl_clear_bit(14, 25); /* disable damage MCH */
ctl_set_bit(14, 26); /* enable degradation MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */
ctl_set_bit(14, 28); /* enable channel report MCH */
#ifdef CONFIG_MACHCK_WARNING
#ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */
#endif
......@@ -127,6 +130,30 @@ s390_init_machine_check(void)
return;
}
/*
* initialize the machine check handler really early to be able to
* catch all machine checks that happen during boot
*/
static int __init
machine_check_init (void)
{
s390_init_machine_check();
return 0;
}
arch_initcall(machine_check_init);
/*
* Machine checks for the channel subsystem must be enabled
* after the channel subsystem is initialized
*/
static int __init
machine_check_crw_init (void)
{
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
device_initcall (machine_check_crw_init);
static void
s390_handle_damage(char *msg)
{
......@@ -244,6 +271,8 @@ s390_machine_check_handler(void *parm)
DBG(KERN_NOTICE "mach_handler : ready\n");
complete(&mchchk_thread_active);
do {
DBG(KERN_NOTICE "mach_handler : waiting for wakeup\n");
......
......@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq,
const char *devname,
void *dev_id);
extern int s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
extern int set_cons_dev(int irq);
extern int wait_cons_dev(int irq);
extern schib_t *s390_get_schib( int irq );
......@@ -860,28 +866,8 @@ typedef struct {
__u32 vrdccrft : 8; /* real device feature (output) */
} __attribute__ ((packed,aligned(4))) diag210_t;
void VM_virtual_device_info( __u16 devno, /* device number */
senseid_t *ps ); /* ptr to senseID data */
extern __inline__ int diag210( diag210_t * addr)
{
int ccode;
extern int diag210( diag210_t * addr);
__asm__ __volatile__(
#ifdef CONFIG_ARCH_S390X
" sam31\n"
" diag %1,0,0x210\n"
" sam64\n"
#else
" diag %1,0,0x210\n"
#endif
" ipm %0\n"
" srl %0,28"
: "=d" (ccode)
: "a" (addr)
: "cc" );
return ccode;
}
extern __inline__ int chsc( chsc_area_t * chsc_area)
{
int cc;
......
......@@ -9,22 +9,25 @@
#ifndef __s390io_h
#define __s390io_h
#include <linux/device.h>
/*
* IRQ data structure used by I/O subroutines
*
* Note : If bit flags are added, the "unused" value must be
* decremented accordingly !
*/
typedef struct _ioinfo {
typedef struct subchannel {
unsigned int irq; /* aka. subchannel number */
spinlock_t irq_lock; /* irq lock */
void *private_data; /* pointer to private data */
struct _ioinfo *prev;
struct _ioinfo *next;
__u8 st; /* subchannel type */
void *private_data; /* pointer to private data */
struct subchannel *prev;
struct subchannel *next;
union {
unsigned int info;
struct {
......@@ -78,8 +81,26 @@ typedef struct _ioinfo {
unsigned long qflag; /* queued flags */
__u8 qlpm; /* queued logical path mask */
ssd_info_t ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
} __attribute__ ((aligned(8))) ioinfo_t;
} __attribute__ ((aligned(8))) ioinfo_t;
/*
* There are four different subchannel types, but we are currently
* only interested in I/O subchannels. This means there is only
* one subchannel_driver, other subchannels belonging to css_bus_type
* are simply ignored.
*/
struct subchannel_driver {
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
SUBCHANNEL_TYPE_MESSAGE = 2,
SUBCHANNEL_TYPE_ADM = 3,
} st; /* subchannel type */
struct device_driver drv; /* entry in driver tree */
};
extern struct bus_type css_bus_type;
#define IOINFO_FLAGS_BUSY 0x80000000
#define IOINFO_FLAGS_OPER 0x40000000
......
......@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq,
const char *devname,
void *dev_id);
extern int s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
extern int set_cons_dev(int irq);
extern int wait_cons_dev(int irq);
extern schib_t *s390_get_schib( int irq );
......@@ -860,28 +866,8 @@ typedef struct {
__u32 vrdccrft : 8; /* real device feature (output) */
} __attribute__ ((packed,aligned(4))) diag210_t;
void VM_virtual_device_info( __u16 devno, /* device number */
senseid_t *ps ); /* ptr to senseID data */
extern __inline__ int diag210( diag210_t * addr)
{
int ccode;
extern int diag210( diag210_t * addr);
__asm__ __volatile__(
#ifdef CONFIG_ARCH_S390X
" sam31\n"
" diag %1,0,0x210\n"
" sam64\n"
#else
" diag %1,0,0x210\n"
#endif
" ipm %0\n"
" srl %0,28"
: "=d" (ccode)
: "a" (addr)
: "cc" );
return ccode;
}
extern __inline__ int chsc( chsc_area_t * chsc_area)
{
int cc;
......
......@@ -9,21 +9,24 @@
#ifndef __s390io_h
#define __s390io_h
#include <linux/device.h>
/*
* IRQ data structure used by I/O subroutines
*
* Note : If bit flags are added, the "unused" value must be
* decremented accordingly !
*/
typedef struct _ioinfo {
typedef struct subchannel {
unsigned int irq; /* aka. subchannel number */
spinlock_t irq_lock; /* irq lock */
void *private_data; /* pointer to private data */
struct _ioinfo *prev;
struct _ioinfo *next;
__u8 st; /* subchannel type */
void *private_data; /* pointer to private data */
__u8 st; /* subchannel type */
struct subchannel *prev;
struct subchannel *next;
union {
unsigned int info;
......@@ -78,8 +81,26 @@ typedef struct _ioinfo {
unsigned long qflag; /* queued flags */
__u8 qlpm; /* queued logical path mask */
ssd_info_t ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
} __attribute__ ((aligned(8))) ioinfo_t;
} __attribute__ ((aligned(8))) ioinfo_t;
/*
* There are four different subchannel types, but we are currently
* only interested in I/O subchannels. This means there is only
* one subchannel_driver, other subchannels belonging to css_bus_type
* are simply ignored.
*/
struct subchannel_driver {
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
SUBCHANNEL_TYPE_MESSAGE = 2,
SUBCHANNEL_TYPE_ADM = 3,
} st; /* subchannel type */
struct device_driver drv; /* entry in driver tree */
};
extern struct bus_type css_bus_type;
#define IOINFO_FLAGS_BUSY 0x80000000
#define IOINFO_FLAGS_OPER 0x40000000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment