From 661ca0da3e1fa60c9e56f995fd83772ffa9ffe90 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Sat, 26 Jan 2008 14:10:36 +0100 Subject: [S390] Cleanup in Documentation/kernel-parameters.txt. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- Documentation/kernel-parameters.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 65de5ba7b74c..d29b6d926a42 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -370,8 +370,6 @@ and is between 256 and 4096 characters. It is defined in the file configured. Potentially dangerous and should only be used if you are entirely sure of the consequences. - chandev= [HW,NET] Generic channel device initialisation - checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text. @@ -382,6 +380,12 @@ and is between 256 and 4096 characters. It is defined in the file Value can be changed at runtime via /selinux/checkreqprot. + cio_ignore= [S390] + See Documentation/s390/CommonIO for details. + + cio_msg= [S390] + See Documentation/s390/CommonIO for details. + clock= [BUGS=X86-32, HW] gettimeofday clocksource override. [Deprecated] Forces specified clocksource (if available) to be used -- cgit v1.2.3-59-g8ed1b From 14ff56bbb3422cc465a12e81f5e1b5f06168aeda Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Sat, 26 Jan 2008 14:10:37 +0100 Subject: [S390] cio: Dump ccw device information in case of timeout. Information about a ccw device will be dumped in case of a ccw timeout. This can be enabled with the kernel parameter ccw_timeout_log. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- Documentation/kernel-parameters.txt | 3 +++ Documentation/s390/CommonIO | 5 ++++ drivers/s390/cio/device_fsm.c | 50 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d29b6d926a42..880f882160e2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -370,6 +370,9 @@ and is between 256 and 4096 characters. It is defined in the file configured. Potentially dangerous and should only be used if you are entirely sure of the consequences. + ccw_timeout_log [S390] + See Documentation/s390/CommonIO for details. + checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text. diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index 86320aa3fb0b..8fbc0a852870 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -4,6 +4,11 @@ S/390 common I/O-Layer - command line parameters, procfs and debugfs entries Command line parameters ----------------------- +* ccw_timeout_log + + Enable logging of debug information in case of ccw device timeouts. + + * cio_msg = yes | no Determines whether information on found devices and sensed device diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index bfad421cda66..31c0f7885161 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -25,6 +25,8 @@ #include "ioasm.h" #include "chp.h" +static int timeout_log_enabled; + int device_is_online(struct subchannel *sch) { @@ -82,6 +84,52 @@ int device_trigger_verify(struct subchannel *sch) return 0; } +static int __init ccw_timeout_log_setup(char *unused) +{ + timeout_log_enabled = 1; + return 1; +} + +__setup("ccw_timeout_log", ccw_timeout_log_setup); + +static void ccw_timeout_log(struct ccw_device *cdev) +{ + struct schib schib; + struct subchannel *sch; + int cc; + + sch = to_subchannel(cdev->dev.parent); + cc = stsch(sch->schid, &schib); + + printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " + "device information:\n", get_clock()); + printk(KERN_WARNING "cio: orb:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &sch->orb, sizeof(sch->orb), 0); + printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); + printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); + printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " + "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); + + if ((void *)(addr_t)sch->orb.cpa == &sch->sense_ccw || + (void *)(addr_t)sch->orb.cpa == cdev->private->iccws) + printk(KERN_WARNING "cio: last channel program (intern):\n"); + else + printk(KERN_WARNING "cio: last channel program:\n"); + + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + (void *)(addr_t)sch->orb.cpa, sizeof(struct ccw1), 0); + printk(KERN_WARNING "cio: ccw device state: %d\n", + cdev->private->state); + printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); + printk(KERN_WARNING "cio: schib:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &schib, sizeof(schib), 0); + printk(KERN_WARNING "cio: ccw device flags:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &cdev->private->flags, sizeof(cdev->private->flags), 0); +} + /* * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. */ @@ -92,6 +140,8 @@ ccw_device_timeout(unsigned long data) cdev = (struct ccw_device *) data; spin_lock_irq(cdev->ccwlock); + if (timeout_log_enabled) + ccw_timeout_log(cdev); dev_fsm_event(cdev, DEV_EVENT_TIMEOUT); spin_unlock_irq(cdev->ccwlock); } -- cgit v1.2.3-59-g8ed1b From 4e8e56c6713398f417317d449f50c08bf2756c66 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Sat, 26 Jan 2008 14:10:44 +0100 Subject: [S390] cio: Extend adapter interrupt interface. From: Cornelia Huck Change the adapter interrupt interface in order to allow multiple adapter interrupt handlers to be registered. Indicators are now allocated by cio instead of the device driver. The qdio parts have been Acked-by: Ursula Braun Signed-off-by: Peter Oberparleiter Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- Documentation/DocBook/s390-drivers.tmpl | 1 + drivers/s390/cio/airq.c | 171 +++++++++++++++++++++----------- drivers/s390/cio/airq.h | 10 -- drivers/s390/cio/cio.c | 2 +- drivers/s390/cio/cio.h | 1 + drivers/s390/cio/qdio.c | 35 ++++--- include/asm-s390/airq.h | 19 ++++ 7 files changed, 154 insertions(+), 85 deletions(-) delete mode 100644 drivers/s390/cio/airq.h create mode 100644 include/asm-s390/airq.h (limited to 'Documentation') diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl index 254e769282a4..3d2f31b99dd9 100644 --- a/Documentation/DocBook/s390-drivers.tmpl +++ b/Documentation/DocBook/s390-drivers.tmpl @@ -116,6 +116,7 @@ !Iinclude/asm-s390/ccwdev.h !Edrivers/s390/cio/device.c !Edrivers/s390/cio/device_ops.c +!Edrivers/s390/cio/airq.c The channel-measurement facility diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 5287631fbfc8..b7a07a866291 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -1,12 +1,12 @@ /* * drivers/s390/cio/airq.c - * S/390 common I/O routines -- support for adapter interruptions + * Support for adapter interruptions * - * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) - * Arnd Bergmann (arndb@de.ibm.com) + * Copyright IBM Corp. 1999,2007 + * Author(s): Ingo Adlung + * Cornelia Huck + * Arnd Bergmann + * Peter Oberparleiter */ #include @@ -14,72 +14,131 @@ #include #include +#include + +#include "cio.h" #include "cio_debug.h" -#include "airq.h" -static adapter_int_handler_t adapter_handler; +#define NR_AIRQS 32 +#define NR_AIRQS_PER_WORD sizeof(unsigned long) +#define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD) -/* - * register for adapter interrupts - * - * With HiperSockets the zSeries architecture provides for - * means of adapter interrups, pseudo I/O interrupts that are - * not tied to an I/O subchannel, but to an adapter. However, - * it doesn't disclose the info how to enable/disable them, but - * to recognize them only. Perhaps we should consider them - * being shared interrupts, and thus build a linked list - * of adapter handlers ... to be evaluated ... - */ -int -s390_register_adapter_interrupt (adapter_int_handler_t handler) -{ - int ret; - char dbf_txt[15]; +union indicator_t { + unsigned long word[NR_AIRQ_WORDS]; + unsigned char byte[NR_AIRQS]; +} __attribute__((packed)); - CIO_TRACE_EVENT (4, "rgaint"); +struct airq_t { + adapter_int_handler_t handler; + void *drv_data; +}; - if (handler == NULL) - ret = -EINVAL; - else - ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0); - if (!ret) - synchronize_sched(); /* Allow interrupts to complete. */ +static union indicator_t indicators; +static struct airq_t *airqs[NR_AIRQS]; - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (4, dbf_txt); +static int register_airq(struct airq_t *airq) +{ + int i; - return ret; + for (i = 0; i < NR_AIRQS; i++) + if (!cmpxchg(&airqs[i], NULL, airq)) + return i; + return -ENOMEM; } -int -s390_unregister_adapter_interrupt (adapter_int_handler_t handler) +/** + * s390_register_adapter_interrupt() - register adapter interrupt handler + * @handler: adapter handler to be registered + * @drv_data: driver data passed with each call to the handler + * + * Returns: + * Pointer to the indicator to be used on success + * ERR_PTR() if registration failed + */ +void *s390_register_adapter_interrupt(adapter_int_handler_t handler, + void *drv_data) { + struct airq_t *airq; + char dbf_txt[16]; int ret; - char dbf_txt[15]; - CIO_TRACE_EVENT (4, "urgaint"); - - if (handler == NULL) - ret = -EINVAL; - else { - adapter_handler = NULL; - synchronize_sched(); /* Allow interrupts to complete. */ - ret = 0; + airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); + if (!airq) { + ret = -ENOMEM; + goto out; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (4, dbf_txt); - - return ret; + airq->handler = handler; + airq->drv_data = drv_data; + ret = register_airq(airq); + if (ret < 0) + kfree(airq); +out: + snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); + CIO_TRACE_EVENT(4, dbf_txt); + if (ret < 0) + return ERR_PTR(ret); + else + return &indicators.byte[ret]; } +EXPORT_SYMBOL(s390_register_adapter_interrupt); -void -do_adapter_IO (void) +/** + * s390_unregister_adapter_interrupt - unregister adapter interrupt handler + * @ind: indicator for which the handler is to be unregistered + */ +void s390_unregister_adapter_interrupt(void *ind) { - CIO_TRACE_EVENT (6, "doaio"); + struct airq_t *airq; + char dbf_txt[16]; + int i; - if (adapter_handler) - (*adapter_handler) (); + i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]); + snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); + CIO_TRACE_EVENT(4, dbf_txt); + indicators.byte[i] = 0; + airq = xchg(&airqs[i], NULL); + /* + * Allow interrupts to complete. This will ensure that the airq handle + * is no longer referenced by any interrupt handler. + */ + synchronize_sched(); + kfree(airq); } +EXPORT_SYMBOL(s390_unregister_adapter_interrupt); + +#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) -EXPORT_SYMBOL (s390_register_adapter_interrupt); -EXPORT_SYMBOL (s390_unregister_adapter_interrupt); +void do_adapter_IO(void) +{ + int w; + int i; + unsigned long word; + struct airq_t *airq; + + /* + * Access indicator array in word-sized chunks to minimize storage + * fetch operations. + */ + for (w = 0; w < NR_AIRQ_WORDS; w++) { + word = indicators.word[w]; + i = w * NR_AIRQS_PER_WORD; + /* + * Check bytes within word for active indicators. + */ + while (word) { + if (word & INDICATOR_MASK) { + airq = airqs[i]; + if (likely(airq)) + airq->handler(&indicators.byte[i], + airq->drv_data); + else + /* + * Reset ill-behaved indicator. + */ + indicators.byte[i] = 0; + } + word <<= 8; + i++; + } + } +} diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h deleted file mode 100644 index 7d6be3fdcd66..000000000000 --- a/drivers/s390/cio/airq.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef S390_AINTERRUPT_H -#define S390_AINTERRUPT_H - -typedef int (*adapter_int_handler_t)(void); - -extern int s390_register_adapter_interrupt(adapter_int_handler_t handler); -extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler); -extern void do_adapter_IO (void); - -#endif diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index d0bcebde3fa2..89ced3408138 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -23,7 +23,7 @@ #include #include #include -#include "airq.h" +#include #include "cio.h" #include "css.h" #include "chsc.h" diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index a6ef218defbe..d1483d65049c 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -99,6 +99,7 @@ extern int cio_get_options (struct subchannel *); extern int cio_modify (struct subchannel *); int cio_create_sch_lock(struct subchannel *); +void do_adapter_IO(void); /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 40a3208c7cf3..7a353db8564f 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -48,11 +48,11 @@ #include #include #include +#include #include "cio.h" #include "css.h" #include "device.h" -#include "airq.h" #include "qdio.h" #include "ioasm.h" #include "chsc.h" @@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in; static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change during a while loop */ static DEFINE_SPINLOCK(ttiq_list_lock); -static int register_thinint_result; +static void *tiqdio_ind; static void tiqdio_tl(unsigned long); static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0); @@ -399,7 +399,7 @@ qdio_get_indicator(void) { int i; - for (i=1;idev_st_chg_ind); } @@ -3740,23 +3738,25 @@ static void tiqdio_register_thinints(void) { char dbf_text[20]; - register_thinint_result= - s390_register_adapter_interrupt(&tiqdio_thinint_handler); - if (register_thinint_result) { - sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff)); + + tiqdio_ind = + s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL); + if (IS_ERR(tiqdio_ind)) { + sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind)); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_PRINT_ERR("failed to register adapter handler " \ - "(rc=%i).\nAdapter interrupts might " \ + "(rc=%li).\nAdapter interrupts might " \ "not work. Continuing.\n", - register_thinint_result); + PTR_ERR(tiqdio_ind)); + tiqdio_ind = NULL; } } static void tiqdio_unregister_thinints(void) { - if (!register_thinint_result) - s390_unregister_adapter_interrupt(&tiqdio_thinint_handler); + if (tiqdio_ind) + s390_unregister_adapter_interrupt(tiqdio_ind); } static int @@ -3768,8 +3768,8 @@ qdio_get_qdio_memory(void) for (i=1;i + * Cornelia Huck + * Arnd Bergmann + * Peter Oberparleiter + */ + +#ifndef _ASM_S390_AIRQ_H +#define _ASM_S390_AIRQ_H + +typedef void (*adapter_int_handler_t)(void *, void *); + +void *s390_register_adapter_interrupt(adapter_int_handler_t, void *); +void s390_unregister_adapter_interrupt(void *); + +#endif /* _ASM_S390_AIRQ_H */ -- cgit v1.2.3-59-g8ed1b From 48483b3290988952a593c6e66ca354c19f1a4350 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 26 Jan 2008 14:11:05 +0100 Subject: [S390] Get rid of additional_cpus kernel parameter. It caused only a lot of confusion. From now on cpu hotplug of up to NR_CPUS will work by default. If somebody wants to limit that then the possible_cpus parameter can be used. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- Documentation/cpu-hotplug.txt | 2 +- arch/s390/kernel/early.c | 1 - arch/s390/kernel/setup.c | 1 - arch/s390/kernel/smp.c | 180 ++++++++++++++++++------------------------ drivers/s390/char/sclp_cmd.c | 46 +---------- include/asm-s390/sclp.h | 1 - include/asm-s390/smp.h | 3 - 7 files changed, 79 insertions(+), 155 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt index fb94f5a71b68..ba0aacde94fb 100644 --- a/Documentation/cpu-hotplug.txt +++ b/Documentation/cpu-hotplug.txt @@ -50,7 +50,7 @@ additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets cpu_possible_map = cpu_present_map + additional_cpus (*) Option valid only for following architectures -- x86_64, ia64, s390 +- x86_64, ia64 ia64 and x86_64 use the number of disabled local apics in ACPI tables MADT to determine the number of potentially hot-pluggable cpus. The implementation diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index c7cbb0114147..9f7b73b180f0 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -278,7 +278,6 @@ void __init startup_init(void) setup_lowcore_early(); sclp_read_info_early(); sclp_facilities_detect(); - sclp_read_cpu_info_early(); memsize = sclp_memory_detect(); #ifndef CONFIG_64BIT /* diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 3a61bfc2c4fb..cbdf3fb05e81 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -922,7 +922,6 @@ setup_arch(char **cmdline_p) cpu_init(); __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; - smp_setup_cpu_possible_map(); /* * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 66fe28930d82..320e4e97bf52 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -54,7 +54,7 @@ EXPORT_SYMBOL(lowcore_ptr); cpumask_t cpu_online_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); -cpumask_t cpu_possible_map = CPU_MASK_NONE; +cpumask_t cpu_possible_map = CPU_MASK_ALL; EXPORT_SYMBOL(cpu_possible_map); static struct task_struct *current_set[NR_CPUS]; @@ -399,7 +399,7 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS); return; } - zfcpdump_save_areas[cpu] = alloc_bootmem(sizeof(union save_area)); + zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL); __cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu; while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) == sigp_busy) @@ -435,67 +435,6 @@ static int cpu_stopped(int cpu) return 0; } -/* - * Lets check how many CPUs we have. - */ -static void __init smp_count_cpus(unsigned int *configured_cpus, - unsigned int *standby_cpus) -{ - unsigned int cpu; - struct sclp_cpu_info *info; - u16 boot_cpu_addr, cpu_addr; - - boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; - current_thread_info()->cpu = 0; - *configured_cpus = 1; - *standby_cpus = 0; - - info = alloc_bootmem_pages(sizeof(*info)); - if (!info) - disabled_wait((unsigned long) __builtin_return_address(0)); - - /* Use sigp detection algorithm if sclp doesn't work. */ - if (sclp_get_cpu_info(info)) { - smp_use_sigp_detection = 1; - for (cpu = 0; cpu <= 65535; cpu++) { - if (cpu == boot_cpu_addr) - continue; - __cpu_logical_map[CPU_INIT_NO] = cpu; - if (cpu_stopped(CPU_INIT_NO)) - (*configured_cpus)++; - } - goto out; - } - - if (info->has_cpu_type) { - for (cpu = 0; cpu < info->combined; cpu++) { - if (info->cpu[cpu].address == boot_cpu_addr) { - smp_cpu_type = info->cpu[cpu].type; - break; - } - } - } - /* Count cpus. */ - for (cpu = 0; cpu < info->combined; cpu++) { - if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type) - continue; - cpu_addr = info->cpu[cpu].address; - if (cpu_addr == boot_cpu_addr) - continue; - __cpu_logical_map[CPU_INIT_NO] = cpu_addr; - if (!cpu_stopped(CPU_INIT_NO)) { - (*standby_cpus)++; - continue; - } - smp_get_save_area(*configured_cpus, cpu_addr); - (*configured_cpus)++; - } -out: - printk(KERN_INFO "CPUs: %d configured, %d standby\n", - *configured_cpus, *standby_cpus); - free_bootmem((unsigned long) info, sizeof(*info)); -} - static int cpu_known(int cpu_id) { int cpu; @@ -529,7 +468,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) return 0; } -static int __init_refok smp_rescan_cpus_sclp(cpumask_t avail) +static int smp_rescan_cpus_sclp(cpumask_t avail) { struct sclp_cpu_info *info; int cpu_id, logical_cpu, cpu; @@ -538,10 +477,7 @@ static int __init_refok smp_rescan_cpus_sclp(cpumask_t avail) logical_cpu = first_cpu(avail); if (logical_cpu == NR_CPUS) return 0; - if (slab_is_available()) - info = kmalloc(sizeof(*info), GFP_KERNEL); - else - info = alloc_bootmem(sizeof(*info)); + info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; rc = sclp_get_cpu_info(info); @@ -564,10 +500,7 @@ static int __init_refok smp_rescan_cpus_sclp(cpumask_t avail) break; } out: - if (slab_is_available()) - kfree(info); - else - free_bootmem((unsigned long) info, sizeof(*info)); + kfree(info); return rc; } @@ -575,15 +508,71 @@ static int smp_rescan_cpus(void) { cpumask_t avail; - cpus_setall(avail); - cpus_and(avail, avail, cpu_possible_map); - cpus_andnot(avail, avail, cpu_present_map); + cpus_xor(avail, cpu_possible_map, cpu_present_map); if (smp_use_sigp_detection) return smp_rescan_cpus_sigp(avail); else return smp_rescan_cpus_sclp(avail); } +static void __init smp_detect_cpus(void) +{ + unsigned int cpu, c_cpus, s_cpus; + struct sclp_cpu_info *info; + u16 boot_cpu_addr, cpu_addr; + + c_cpus = 1; + s_cpus = 0; + boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + panic("smp_detect_cpus failed to allocate memory\n"); + /* Use sigp detection algorithm if sclp doesn't work. */ + if (sclp_get_cpu_info(info)) { + smp_use_sigp_detection = 1; + for (cpu = 0; cpu <= 65535; cpu++) { + if (cpu == boot_cpu_addr) + continue; + __cpu_logical_map[CPU_INIT_NO] = cpu; + if (!cpu_stopped(CPU_INIT_NO)) + continue; + smp_get_save_area(c_cpus, cpu); + c_cpus++; + } + goto out; + } + + if (info->has_cpu_type) { + for (cpu = 0; cpu < info->combined; cpu++) { + if (info->cpu[cpu].address == boot_cpu_addr) { + smp_cpu_type = info->cpu[cpu].type; + break; + } + } + } + + for (cpu = 0; cpu < info->combined; cpu++) { + if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type) + continue; + cpu_addr = info->cpu[cpu].address; + if (cpu_addr == boot_cpu_addr) + continue; + __cpu_logical_map[CPU_INIT_NO] = cpu_addr; + if (!cpu_stopped(CPU_INIT_NO)) { + s_cpus++; + continue; + } + smp_get_save_area(c_cpus, cpu_addr); + c_cpus++; + } +out: + kfree(info); + printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus); + lock_cpu_hotplug(); + smp_rescan_cpus(); + unlock_cpu_hotplug(); +} + /* * Activate a secondary processor. */ @@ -674,41 +663,20 @@ int __cpu_up(unsigned int cpu) return 0; } -static unsigned int __initdata additional_cpus; -static unsigned int __initdata possible_cpus; - -void __init smp_setup_cpu_possible_map(void) -{ - unsigned int pos_cpus, cpu; - unsigned int configured_cpus, standby_cpus; - - smp_count_cpus(&configured_cpus, &standby_cpus); - pos_cpus = min(configured_cpus + standby_cpus + additional_cpus, - (unsigned int) NR_CPUS); - if (possible_cpus) - pos_cpus = min(possible_cpus, (unsigned int) NR_CPUS); - for (cpu = 0; cpu < pos_cpus; cpu++) - cpu_set(cpu, cpu_possible_map); - cpu_present_map = cpumask_of_cpu(0); - smp_rescan_cpus(); -} - -#ifdef CONFIG_HOTPLUG_CPU - -static int __init setup_additional_cpus(char *s) -{ - additional_cpus = simple_strtoul(s, NULL, 0); - return 0; -} -early_param("additional_cpus", setup_additional_cpus); - static int __init setup_possible_cpus(char *s) { - possible_cpus = simple_strtoul(s, NULL, 0); + int pcpus, cpu; + + pcpus = simple_strtoul(s, NULL, 0); + cpu_possible_map = cpumask_of_cpu(0); + for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++) + cpu_set(cpu, cpu_possible_map); return 0; } early_param("possible_cpus", setup_possible_cpus); +#ifdef CONFIG_HOTPLUG_CPU + int __cpu_disable(void) { struct ec_creg_mask_parms cr_parms; @@ -768,6 +736,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) unsigned int cpu; int i; + smp_detect_cpus(); + /* request the 0x1201 emergency signal external interrupt */ if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1201"); @@ -816,6 +786,8 @@ void __init smp_prepare_boot_cpu(void) { BUG_ON(smp_processor_id() != 0); + current_thread_info()->cpu = 0; + cpu_set(0, cpu_present_map); cpu_set(0, cpu_online_map); S390_lowcore.percpu_offset = __per_cpu_offset[0]; current_set[0] = current; diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index d7e6f4d65b78..b5c23396f8fe 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -191,9 +191,6 @@ struct read_cpu_info_sccb { u8 reserved[4096 - 16]; } __attribute__((packed, aligned(PAGE_SIZE))); -static struct read_cpu_info_sccb __initdata early_read_cpu_info_sccb; -static struct sclp_cpu_info __initdata sclp_cpu_info; - static void sclp_fill_cpu_info(struct sclp_cpu_info *info, struct read_cpu_info_sccb *sccb) { @@ -208,48 +205,16 @@ static void sclp_fill_cpu_info(struct sclp_cpu_info *info, info->combined * sizeof(struct sclp_cpu_entry)); } -void __init sclp_read_cpu_info_early(void) -{ - int rc; - struct read_cpu_info_sccb *sccb; - - if (!SCLP_HAS_CPU_INFO) - return; - - sccb = &early_read_cpu_info_sccb; - do { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb); - } while (rc == -EBUSY); - - if (rc) - return; - if (sccb->header.response_code != 0x10) - return; - sclp_fill_cpu_info(&sclp_cpu_info, sccb); -} - -static int __init sclp_get_cpu_info_early(struct sclp_cpu_info *info) -{ - if (!SCLP_HAS_CPU_INFO) - return -EOPNOTSUPP; - *info = sclp_cpu_info; - return 0; -} - -static int sclp_get_cpu_info_late(struct sclp_cpu_info *info) +int sclp_get_cpu_info(struct sclp_cpu_info *info) { int rc; struct read_cpu_info_sccb *sccb; if (!SCLP_HAS_CPU_INFO) return -EOPNOTSUPP; - sccb = (struct read_cpu_info_sccb *) __get_free_page(GFP_KERNEL - | GFP_DMA); + sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) return -ENOMEM; - memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); if (rc) @@ -266,13 +231,6 @@ out: return rc; } -int __init_refok sclp_get_cpu_info(struct sclp_cpu_info *info) -{ - if (slab_is_available()) - return sclp_get_cpu_info_late(info); - return sclp_get_cpu_info_early(info); -} - struct cpu_configure_sccb { struct sccb_header header; } __attribute__((packed, aligned(8))); diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h index b8c7695cd4c8..b5f2843013a3 100644 --- a/include/asm-s390/sclp.h +++ b/include/asm-s390/sclp.h @@ -46,7 +46,6 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info); int sclp_cpu_configure(u8 cpu); int sclp_cpu_deconfigure(u8 cpu); void sclp_read_info_early(void); -void sclp_read_cpu_info_early(void); void sclp_facilities_detect(void); unsigned long long sclp_memory_detect(void); int sclp_sdias_blk_count(void); diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index 07708c07701e..218454b91862 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -35,8 +35,6 @@ extern void machine_restart_smp(char *); extern void machine_halt_smp(void); extern void machine_power_off_smp(void); -extern void smp_setup_cpu_possible_map(void); - #define NO_PROC_ID 0xFF /* No processor magic marker */ /* @@ -103,7 +101,6 @@ static inline void smp_send_stop(void) #define hard_smp_processor_id() 0 #define smp_cpu_not_running(cpu) 1 -#define smp_setup_cpu_possible_map() do { } while (0) #endif extern union save_area *zfcpdump_save_areas[NR_CPUS + 1]; -- cgit v1.2.3-59-g8ed1b