Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: [S390] dcss: Initialize workqueue before using it. [S390] Remove BUILD_BUG_ON() in vmem code. [S390] sclp_tty/sclp_vt220: Fix scheduling while atomic [S390] dasd: fix panic caused by alias device offline [S390] dasd: add ifcc handling [S390] latencytop s390 support. [S390] Implement ext2_find_next_bit. [S390] Cleanup & optimize bitops. [S390] Define GENERIC_LOCKBREAK. [S390] console: allow vt220 console to be the only console [S390] Fix couple of section mismatches. [S390] Fix smp_call_function_mask semantics. [S390] Fix linker script. [S390] DEBUG_PAGEALLOC support for s390. [S390] cio: Add shutdown callback for ccwgroup. [S390] cio: Update documentation. [S390] cio: Clean up chsc response code handling. [S390] cio: make sense id procedure work with partial hardware response
This commit is contained in:
@@ -59,7 +59,7 @@
|
|||||||
<title>Introduction</title>
|
<title>Introduction</title>
|
||||||
<para>
|
<para>
|
||||||
This document describes the interfaces available for device drivers that
|
This document describes the interfaces available for device drivers that
|
||||||
drive s390 based channel attached devices. This includes interfaces for
|
drive s390 based channel attached I/O devices. This includes interfaces for
|
||||||
interaction with the hardware and interfaces for interacting with the
|
interaction with the hardware and interfaces for interacting with the
|
||||||
common driver core. Those interfaces are provided by the s390 common I/O
|
common driver core. Those interfaces are provided by the s390 common I/O
|
||||||
layer.
|
layer.
|
||||||
@@ -86,9 +86,10 @@
|
|||||||
The ccw bus typically contains the majority of devices available to
|
The ccw bus typically contains the majority of devices available to
|
||||||
a s390 system. Named after the channel command word (ccw), the basic
|
a s390 system. Named after the channel command word (ccw), the basic
|
||||||
command structure used to address its devices, the ccw bus contains
|
command structure used to address its devices, the ccw bus contains
|
||||||
so-called channel attached devices. They are addressed via subchannels,
|
so-called channel attached devices. They are addressed via I/O
|
||||||
visible on the css bus. A device driver, however, will never interact
|
subchannels, visible on the css bus. A device driver for
|
||||||
with the subchannel directly, but only via the device on the ccw bus,
|
channel-attached devices, however, will never interact with the
|
||||||
|
subchannel directly, but only via the I/O device on the ccw bus,
|
||||||
the ccw device.
|
the ccw device.
|
||||||
</para>
|
</para>
|
||||||
<sect1 id="channelIO">
|
<sect1 id="channelIO">
|
||||||
@@ -116,7 +117,6 @@
|
|||||||
!Iinclude/asm-s390/ccwdev.h
|
!Iinclude/asm-s390/ccwdev.h
|
||||||
!Edrivers/s390/cio/device.c
|
!Edrivers/s390/cio/device.c
|
||||||
!Edrivers/s390/cio/device_ops.c
|
!Edrivers/s390/cio/device_ops.c
|
||||||
!Edrivers/s390/cio/airq.c
|
|
||||||
</sect1>
|
</sect1>
|
||||||
<sect1 id="cmf">
|
<sect1 id="cmf">
|
||||||
<title>The channel-measurement facility</title>
|
<title>The channel-measurement facility</title>
|
||||||
@@ -147,4 +147,15 @@
|
|||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="genericinterfaces">
|
||||||
|
<title>Generic interfaces</title>
|
||||||
|
<para>
|
||||||
|
Some interfaces are available to other drivers that do not necessarily
|
||||||
|
have anything to do with the busses described above, but still are
|
||||||
|
indirectly using basic infrastructure in the common I/O layer.
|
||||||
|
One example is the support for adapter interrupts.
|
||||||
|
</para>
|
||||||
|
!Edrivers/s390/cio/airq.c
|
||||||
|
</chapter>
|
||||||
|
|
||||||
</book>
|
</book>
|
||||||
|
@@ -16,6 +16,9 @@ config LOCKDEP_SUPPORT
|
|||||||
config STACKTRACE_SUPPORT
|
config STACKTRACE_SUPPORT
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
config HAVE_LATENCYTOP_SUPPORT
|
||||||
|
def_bool y
|
||||||
|
|
||||||
config RWSEM_GENERIC_SPINLOCK
|
config RWSEM_GENERIC_SPINLOCK
|
||||||
bool
|
bool
|
||||||
|
|
||||||
@@ -47,6 +50,11 @@ config NO_IOMEM
|
|||||||
config NO_DMA
|
config NO_DMA
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
config GENERIC_LOCKBREAK
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on SMP && PREEMPT
|
||||||
|
|
||||||
mainmenu "Linux Kernel Configuration"
|
mainmenu "Linux Kernel Configuration"
|
||||||
|
|
||||||
config S390
|
config S390
|
||||||
|
@@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT
|
|||||||
|
|
||||||
source "lib/Kconfig.debug"
|
source "lib/Kconfig.debug"
|
||||||
|
|
||||||
|
config DEBUG_PAGEALLOC
|
||||||
|
bool "Debug page memory allocations"
|
||||||
|
depends on DEBUG_KERNEL
|
||||||
|
help
|
||||||
|
Unmap pages from the kernel linear mapping after free_pages().
|
||||||
|
This results in a slowdown, but helps to find certain types of
|
||||||
|
memory corruptions.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <linux/sys.h>
|
#include <linux/sys.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
#include <linux/init.h>
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
@@ -830,9 +831,7 @@ mcck_return:
|
|||||||
* Restart interruption handler, kick starter for additional CPUs
|
* Restart interruption handler, kick starter for additional CPUs
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
#ifndef CONFIG_HOTPLUG_CPU
|
__CPUINIT
|
||||||
.section .init.text,"ax"
|
|
||||||
#endif
|
|
||||||
.globl restart_int_handler
|
.globl restart_int_handler
|
||||||
restart_int_handler:
|
restart_int_handler:
|
||||||
l %r15,__LC_SAVE_AREA+60 # load ksp
|
l %r15,__LC_SAVE_AREA+60 # load ksp
|
||||||
@@ -845,9 +844,7 @@ restart_int_handler:
|
|||||||
br %r14 # branch to start_secondary
|
br %r14 # branch to start_secondary
|
||||||
restart_addr:
|
restart_addr:
|
||||||
.long start_secondary
|
.long start_secondary
|
||||||
#ifndef CONFIG_HOTPLUG_CPU
|
|
||||||
.previous
|
.previous
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* If we do not run with SMP enabled, let the new CPU crash ...
|
* If we do not run with SMP enabled, let the new CPU crash ...
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <linux/sys.h>
|
#include <linux/sys.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
#include <linux/init.h>
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
@@ -801,9 +802,7 @@ mcck_return:
|
|||||||
* Restart interruption handler, kick starter for additional CPUs
|
* Restart interruption handler, kick starter for additional CPUs
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
#ifndef CONFIG_HOTPLUG_CPU
|
__CPUINIT
|
||||||
.section .init.text,"ax"
|
|
||||||
#endif
|
|
||||||
.globl restart_int_handler
|
.globl restart_int_handler
|
||||||
restart_int_handler:
|
restart_int_handler:
|
||||||
lg %r15,__LC_SAVE_AREA+120 # load ksp
|
lg %r15,__LC_SAVE_AREA+120 # load ksp
|
||||||
@@ -814,9 +813,7 @@ restart_int_handler:
|
|||||||
lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
|
lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
|
||||||
stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
|
stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
|
||||||
jg start_secondary
|
jg start_secondary
|
||||||
#ifndef CONFIG_HOTPLUG_CPU
|
|
||||||
.previous
|
.previous
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* If we do not run with SMP enabled, let the new CPU crash ...
|
* If we do not run with SMP enabled, let the new CPU crash ...
|
||||||
|
@@ -439,7 +439,7 @@ static void ipl_run(struct shutdown_trigger *trigger)
|
|||||||
reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
|
reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipl_init(void)
|
static int __init ipl_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -471,8 +471,11 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
|
static struct shutdown_action __refdata ipl_action = {
|
||||||
ipl_init};
|
.name = SHUTDOWN_ACTION_IPL_STR,
|
||||||
|
.fn = ipl_run,
|
||||||
|
.init = ipl_init,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reipl shutdown action: Reboot Linux on shutdown.
|
* reipl shutdown action: Reboot Linux on shutdown.
|
||||||
@@ -792,7 +795,7 @@ static int __init reipl_fcp_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reipl_init(void)
|
static int __init reipl_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -819,8 +822,11 @@ static int reipl_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
|
static struct shutdown_action __refdata reipl_action = {
|
||||||
reipl_run, reipl_init};
|
.name = SHUTDOWN_ACTION_REIPL_STR,
|
||||||
|
.fn = reipl_run,
|
||||||
|
.init = reipl_init,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dump shutdown action: Dump Linux on shutdown.
|
* dump shutdown action: Dump Linux on shutdown.
|
||||||
@@ -998,7 +1004,7 @@ static int __init dump_fcp_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_init(void)
|
static int __init dump_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1020,8 +1026,11 @@ static int dump_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
|
static struct shutdown_action __refdata dump_action = {
|
||||||
dump_run, dump_init};
|
.name = SHUTDOWN_ACTION_DUMP_STR,
|
||||||
|
.fn = dump_run,
|
||||||
|
.init = dump_init,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vmcmd shutdown action: Trigger vm command on shutdown.
|
* vmcmd shutdown action: Trigger vm command on shutdown.
|
||||||
|
@@ -77,7 +77,7 @@ unsigned long machine_flags = 0;
|
|||||||
unsigned long elf_hwcap = 0;
|
unsigned long elf_hwcap = 0;
|
||||||
char elf_platform[ELF_PLATFORM_SIZE];
|
char elf_platform[ELF_PLATFORM_SIZE];
|
||||||
|
|
||||||
struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
|
struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
|
||||||
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
|
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
|
||||||
static unsigned long __initdata memory_end;
|
static unsigned long __initdata memory_end;
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ __setup("condev=", condev_setup);
|
|||||||
|
|
||||||
static int __init conmode_setup(char *str)
|
static int __init conmode_setup(char *str)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_SCLP_CONSOLE)
|
#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
|
||||||
if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
|
if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
|
||||||
SET_CONSOLE_SCLP;
|
SET_CONSOLE_SCLP;
|
||||||
#endif
|
#endif
|
||||||
@@ -183,7 +183,7 @@ static void __init conmode_default(void)
|
|||||||
*/
|
*/
|
||||||
cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
|
cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
#if defined(CONFIG_SCLP_CONSOLE)
|
#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
|
||||||
SET_CONSOLE_SCLP;
|
SET_CONSOLE_SCLP;
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
@@ -193,7 +193,7 @@ static void __init conmode_default(void)
|
|||||||
SET_CONSOLE_3270;
|
SET_CONSOLE_3270;
|
||||||
#elif defined(CONFIG_TN3215_CONSOLE)
|
#elif defined(CONFIG_TN3215_CONSOLE)
|
||||||
SET_CONSOLE_3215;
|
SET_CONSOLE_3215;
|
||||||
#elif defined(CONFIG_SCLP_CONSOLE)
|
#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
|
||||||
SET_CONSOLE_SCLP;
|
SET_CONSOLE_SCLP;
|
||||||
#endif
|
#endif
|
||||||
} else if (strncmp(ptr + 8, "3215", 4) == 0) {
|
} else if (strncmp(ptr + 8, "3215", 4) == 0) {
|
||||||
@@ -201,7 +201,7 @@ static void __init conmode_default(void)
|
|||||||
SET_CONSOLE_3215;
|
SET_CONSOLE_3215;
|
||||||
#elif defined(CONFIG_TN3270_CONSOLE)
|
#elif defined(CONFIG_TN3270_CONSOLE)
|
||||||
SET_CONSOLE_3270;
|
SET_CONSOLE_3270;
|
||||||
#elif defined(CONFIG_SCLP_CONSOLE)
|
#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
|
||||||
SET_CONSOLE_SCLP;
|
SET_CONSOLE_SCLP;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ static void __init conmode_default(void)
|
|||||||
SET_CONSOLE_3270;
|
SET_CONSOLE_3270;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(CONFIG_SCLP_CONSOLE)
|
#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
|
||||||
SET_CONSOLE_SCLP;
|
SET_CONSOLE_SCLP;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -528,7 +528,7 @@ static void __init setup_memory_end(void)
|
|||||||
memory_size = 0;
|
memory_size = 0;
|
||||||
memory_end &= PAGE_MASK;
|
memory_end &= PAGE_MASK;
|
||||||
|
|
||||||
max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
|
max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS;
|
||||||
memory_end = min(max_mem, memory_end);
|
memory_end = min(max_mem, memory_end);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -225,12 +225,11 @@ EXPORT_SYMBOL(smp_call_function_single);
|
|||||||
* You must not call this function with disabled interrupts or from a
|
* You must not call this function with disabled interrupts or from a
|
||||||
* hardware interrupt handler or from a bottom half handler.
|
* hardware interrupt handler or from a bottom half handler.
|
||||||
*/
|
*/
|
||||||
int
|
int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
|
||||||
smp_call_function_mask(cpumask_t mask,
|
int wait)
|
||||||
void (*func)(void *), void *info,
|
|
||||||
int wait)
|
|
||||||
{
|
{
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
cpu_clear(smp_processor_id(), mask);
|
||||||
__smp_call_function_map(func, info, 0, wait, mask);
|
__smp_call_function_map(func, info, 0, wait, mask);
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1008,7 +1007,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
|
|||||||
.notifier_call = smp_cpu_notify,
|
.notifier_call = smp_cpu_notify,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int smp_add_present_cpu(int cpu)
|
static int __devinit smp_add_present_cpu(int cpu)
|
||||||
{
|
{
|
||||||
struct cpu *c = &per_cpu(cpu_devices, cpu);
|
struct cpu *c = &per_cpu(cpu_devices, cpu);
|
||||||
struct sys_device *s = &c->sysdev;
|
struct sys_device *s = &c->sysdev;
|
||||||
@@ -1036,8 +1035,8 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
static ssize_t rescan_store(struct sys_device *dev, const char *buf,
|
static ssize_t __ref rescan_store(struct sys_device *dev,
|
||||||
size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
cpumask_t newcpus;
|
cpumask_t newcpus;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
@@ -14,7 +14,8 @@
|
|||||||
static unsigned long save_context_stack(struct stack_trace *trace,
|
static unsigned long save_context_stack(struct stack_trace *trace,
|
||||||
unsigned long sp,
|
unsigned long sp,
|
||||||
unsigned long low,
|
unsigned long low,
|
||||||
unsigned long high)
|
unsigned long high,
|
||||||
|
int savesched)
|
||||||
{
|
{
|
||||||
struct stack_frame *sf;
|
struct stack_frame *sf;
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
@@ -47,10 +48,12 @@ static unsigned long save_context_stack(struct stack_trace *trace,
|
|||||||
return sp;
|
return sp;
|
||||||
regs = (struct pt_regs *)sp;
|
regs = (struct pt_regs *)sp;
|
||||||
addr = regs->psw.addr & PSW_ADDR_INSN;
|
addr = regs->psw.addr & PSW_ADDR_INSN;
|
||||||
if (!trace->skip)
|
if (savesched || !in_sched_functions(addr)) {
|
||||||
trace->entries[trace->nr_entries++] = addr;
|
if (!trace->skip)
|
||||||
else
|
trace->entries[trace->nr_entries++] = addr;
|
||||||
trace->skip--;
|
else
|
||||||
|
trace->skip--;
|
||||||
|
}
|
||||||
if (trace->nr_entries >= trace->max_entries)
|
if (trace->nr_entries >= trace->max_entries)
|
||||||
return sp;
|
return sp;
|
||||||
low = sp;
|
low = sp;
|
||||||
@@ -66,15 +69,27 @@ void save_stack_trace(struct stack_trace *trace)
|
|||||||
orig_sp = sp & PSW_ADDR_INSN;
|
orig_sp = sp & PSW_ADDR_INSN;
|
||||||
new_sp = save_context_stack(trace, orig_sp,
|
new_sp = save_context_stack(trace, orig_sp,
|
||||||
S390_lowcore.panic_stack - PAGE_SIZE,
|
S390_lowcore.panic_stack - PAGE_SIZE,
|
||||||
S390_lowcore.panic_stack);
|
S390_lowcore.panic_stack, 1);
|
||||||
if (new_sp != orig_sp)
|
if (new_sp != orig_sp)
|
||||||
return;
|
return;
|
||||||
new_sp = save_context_stack(trace, new_sp,
|
new_sp = save_context_stack(trace, new_sp,
|
||||||
S390_lowcore.async_stack - ASYNC_SIZE,
|
S390_lowcore.async_stack - ASYNC_SIZE,
|
||||||
S390_lowcore.async_stack);
|
S390_lowcore.async_stack, 1);
|
||||||
if (new_sp != orig_sp)
|
if (new_sp != orig_sp)
|
||||||
return;
|
return;
|
||||||
save_context_stack(trace, new_sp,
|
save_context_stack(trace, new_sp,
|
||||||
S390_lowcore.thread_info,
|
S390_lowcore.thread_info,
|
||||||
S390_lowcore.thread_info + THREAD_SIZE);
|
S390_lowcore.thread_info + THREAD_SIZE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||||
|
{
|
||||||
|
unsigned long sp, low, high;
|
||||||
|
|
||||||
|
sp = tsk->thread.ksp & PSW_ADDR_INSN;
|
||||||
|
low = (unsigned long) task_stack_page(tsk);
|
||||||
|
high = (unsigned long) task_pt_regs(tsk);
|
||||||
|
save_context_stack(trace, sp, low, high, 0);
|
||||||
|
if (trace->nr_entries < trace->max_entries)
|
||||||
|
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||||
}
|
}
|
||||||
|
@@ -271,7 +271,10 @@ void die(const char * str, struct pt_regs * regs, long err)
|
|||||||
printk("PREEMPT ");
|
printk("PREEMPT ");
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
printk("SMP");
|
printk("SMP ");
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
|
printk("DEBUG_PAGEALLOC");
|
||||||
#endif
|
#endif
|
||||||
printk("\n");
|
printk("\n");
|
||||||
notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
|
notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
|
||||||
|
@@ -35,7 +35,7 @@ SECTIONS
|
|||||||
KPROBES_TEXT
|
KPROBES_TEXT
|
||||||
*(.fixup)
|
*(.fixup)
|
||||||
*(.gnu.warning)
|
*(.gnu.warning)
|
||||||
} = 0x0700
|
} :text = 0x0700
|
||||||
|
|
||||||
_etext = .; /* End of text section */
|
_etext = .; /* End of text section */
|
||||||
|
|
||||||
|
@@ -167,6 +167,33 @@ void __init mem_init(void)
|
|||||||
PFN_ALIGN((unsigned long)&_eshared) - 1);
|
PFN_ALIGN((unsigned long)&_eshared) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
|
void kernel_map_pages(struct page *page, int numpages, int enable)
|
||||||
|
{
|
||||||
|
pgd_t *pgd;
|
||||||
|
pud_t *pud;
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
unsigned long address;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < numpages; i++) {
|
||||||
|
address = page_to_phys(page + i);
|
||||||
|
pgd = pgd_offset_k(address);
|
||||||
|
pud = pud_offset(pgd, address);
|
||||||
|
pmd = pmd_offset(pud, address);
|
||||||
|
pte = pte_offset_kernel(pmd, address);
|
||||||
|
if (!enable) {
|
||||||
|
ptep_invalidate(address, pte);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
|
||||||
|
/* Flush cpu write queue. */
|
||||||
|
mb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void free_initmem(void)
|
void free_initmem(void)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
@@ -62,7 +62,7 @@ void __meminit memmap_init(unsigned long size, int nid, unsigned long zone,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init_refok *vmem_alloc_pages(unsigned int order)
|
static void __ref *vmem_alloc_pages(unsigned int order)
|
||||||
{
|
{
|
||||||
if (slab_is_available())
|
if (slab_is_available())
|
||||||
return (void *)__get_free_pages(GFP_KERNEL, order);
|
return (void *)__get_free_pages(GFP_KERNEL, order);
|
||||||
@@ -250,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg)
|
|||||||
{
|
{
|
||||||
struct memory_segment *tmp;
|
struct memory_segment *tmp;
|
||||||
|
|
||||||
if (seg->start + seg->size >= VMALLOC_START ||
|
if (seg->start + seg->size >= VMEM_MAX_PHYS ||
|
||||||
seg->start + seg->size < seg->start)
|
seg->start + seg->size < seg->start)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
@@ -360,7 +360,6 @@ void __init vmem_map_init(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
|
|
||||||
NODE_DATA(0)->node_mem_map = VMEM_MAP;
|
NODE_DATA(0)->node_mem_map = VMEM_MAP;
|
||||||
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
|
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
|
||||||
vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
|
vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
|
||||||
|
@@ -1057,12 +1057,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||||||
if (device->features & DASD_FEATURE_ERPLOG) {
|
if (device->features & DASD_FEATURE_ERPLOG) {
|
||||||
dasd_log_sense(cqr, irb);
|
dasd_log_sense(cqr, irb);
|
||||||
}
|
}
|
||||||
/* If we have no sense data, or we just don't want complex ERP
|
/*
|
||||||
* for this request, but if we have retries left, then just
|
* If we don't want complex ERP for this request, then just
|
||||||
* reset this request and retry it in the fastpath
|
* reset this and retry it in the fastpath
|
||||||
*/
|
*/
|
||||||
if (!(cqr->irb.esw.esw0.erw.cons &&
|
if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
|
||||||
test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
|
|
||||||
cqr->retries > 0) {
|
cqr->retries > 0) {
|
||||||
DEV_MESSAGE(KERN_DEBUG, device,
|
DEV_MESSAGE(KERN_DEBUG, device,
|
||||||
"default ERP in fastpath (%i retries left)",
|
"default ERP in fastpath (%i retries left)",
|
||||||
@@ -1707,7 +1706,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
|
|||||||
|
|
||||||
req = (struct request *) cqr->callback_data;
|
req = (struct request *) cqr->callback_data;
|
||||||
dasd_profile_end(cqr->block, cqr, req);
|
dasd_profile_end(cqr->block, cqr, req);
|
||||||
status = cqr->memdev->discipline->free_cp(cqr, req);
|
status = cqr->block->base->discipline->free_cp(cqr, req);
|
||||||
if (status <= 0)
|
if (status <= 0)
|
||||||
error = status ? status : -EIO;
|
error = status ? status : -EIO;
|
||||||
dasd_end_request(req, error);
|
dasd_end_request(req, error);
|
||||||
@@ -1742,12 +1741,8 @@ restart:
|
|||||||
|
|
||||||
/* Process requests that may be recovered */
|
/* Process requests that may be recovered */
|
||||||
if (cqr->status == DASD_CQR_NEED_ERP) {
|
if (cqr->status == DASD_CQR_NEED_ERP) {
|
||||||
if (cqr->irb.esw.esw0.erw.cons &&
|
erp_fn = base->discipline->erp_action(cqr);
|
||||||
test_bit(DASD_CQR_FLAGS_USE_ERP,
|
erp_fn(cqr);
|
||||||
&cqr->flags)) {
|
|
||||||
erp_fn = base->discipline->erp_action(cqr);
|
|
||||||
erp_fn(cqr);
|
|
||||||
}
|
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -164,7 +164,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
|
|||||||
|
|
||||||
/* reset status to submit the request again... */
|
/* reset status to submit the request again... */
|
||||||
erp->status = DASD_CQR_FILLED;
|
erp->status = DASD_CQR_FILLED;
|
||||||
erp->retries = 1;
|
erp->retries = 10;
|
||||||
} else {
|
} else {
|
||||||
DEV_MESSAGE(KERN_ERR, device,
|
DEV_MESSAGE(KERN_ERR, device,
|
||||||
"No alternate channel path left (lpum=%x / "
|
"No alternate channel path left (lpum=%x / "
|
||||||
@@ -301,8 +301,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
|
|||||||
erp->function = dasd_3990_erp_action_4;
|
erp->function = dasd_3990_erp_action_4;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if (sense && (sense[25] == 0x1D)) { /* state change pending */
|
||||||
if (sense[25] == 0x1D) { /* state change pending */
|
|
||||||
|
|
||||||
DEV_MESSAGE(KERN_INFO, device,
|
DEV_MESSAGE(KERN_INFO, device,
|
||||||
"waiting for state change pending "
|
"waiting for state change pending "
|
||||||
@@ -311,7 +310,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
|
|||||||
|
|
||||||
dasd_3990_erp_block_queue(erp, 30*HZ);
|
dasd_3990_erp_block_queue(erp, 30*HZ);
|
||||||
|
|
||||||
} else if (sense[25] == 0x1E) { /* busy */
|
} else if (sense && (sense[25] == 0x1E)) { /* busy */
|
||||||
DEV_MESSAGE(KERN_INFO, device,
|
DEV_MESSAGE(KERN_INFO, device,
|
||||||
"busy - redriving request later, "
|
"busy - redriving request later, "
|
||||||
"%d retries left",
|
"%d retries left",
|
||||||
@@ -2119,6 +2118,34 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
|
|||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DASD_3990_ERP_CONTROL_CHECK
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* Does a generic inspection if a control check occured and sets up
|
||||||
|
* the related error recovery procedure
|
||||||
|
*
|
||||||
|
* PARAMETER
|
||||||
|
* erp pointer to the currently created default ERP
|
||||||
|
*
|
||||||
|
* RETURN VALUES
|
||||||
|
* erp_filled pointer to the erp
|
||||||
|
*/
|
||||||
|
|
||||||
|
static struct dasd_ccw_req *
|
||||||
|
dasd_3990_erp_control_check(struct dasd_ccw_req *erp)
|
||||||
|
{
|
||||||
|
struct dasd_device *device = erp->startdev;
|
||||||
|
|
||||||
|
if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK
|
||||||
|
| SCHN_STAT_CHN_CTRL_CHK)) {
|
||||||
|
DEV_MESSAGE(KERN_DEBUG, device, "%s",
|
||||||
|
"channel or interface control check");
|
||||||
|
erp = dasd_3990_erp_action_4(erp, NULL);
|
||||||
|
}
|
||||||
|
return erp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DASD_3990_ERP_INSPECT
|
* DASD_3990_ERP_INSPECT
|
||||||
*
|
*
|
||||||
@@ -2145,8 +2172,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
|
|||||||
if (erp_new)
|
if (erp_new)
|
||||||
return erp_new;
|
return erp_new;
|
||||||
|
|
||||||
|
/* check if no concurrent sens is available */
|
||||||
|
if (!erp->refers->irb.esw.esw0.erw.cons)
|
||||||
|
erp_new = dasd_3990_erp_control_check(erp);
|
||||||
/* distinguish between 24 and 32 byte sense data */
|
/* distinguish between 24 and 32 byte sense data */
|
||||||
if (sense[27] & DASD_SENSE_BIT_0) {
|
else if (sense[27] & DASD_SENSE_BIT_0) {
|
||||||
|
|
||||||
/* inspect the 24 byte sense data */
|
/* inspect the 24 byte sense data */
|
||||||
erp_new = dasd_3990_erp_inspect_24(erp, sense);
|
erp_new = dasd_3990_erp_inspect_24(erp, sense);
|
||||||
@@ -2285,6 +2315,17 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
|
|||||||
// return 0; /* CCW doesn't match */
|
// return 0; /* CCW doesn't match */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((cqr1->irb.esw.esw0.erw.cons == 0) &&
|
||||||
|
(cqr2->irb.esw.esw0.erw.cons == 0)) {
|
||||||
|
if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
|
||||||
|
SCHN_STAT_CHN_CTRL_CHK)) ==
|
||||||
|
(cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
|
||||||
|
SCHN_STAT_CHN_CTRL_CHK)))
|
||||||
|
return 1; /* match with ifcc*/
|
||||||
|
}
|
||||||
/* check sense data; byte 0-2,25,27 */
|
/* check sense data; byte 0-2,25,27 */
|
||||||
if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) &&
|
if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) &&
|
||||||
(cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) &&
|
(cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) &&
|
||||||
@@ -2560,17 +2601,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
|
|||||||
|
|
||||||
return cqr;
|
return cqr;
|
||||||
}
|
}
|
||||||
/* check if sense data are available */
|
|
||||||
if (!cqr->irb.ecw) {
|
|
||||||
DEV_MESSAGE(KERN_DEBUG, device,
|
|
||||||
"ERP called witout sense data avail ..."
|
|
||||||
"request %p - NO ERP possible", cqr);
|
|
||||||
|
|
||||||
cqr->status = DASD_CQR_FAILED;
|
|
||||||
|
|
||||||
return cqr;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if error happened before */
|
/* check if error happened before */
|
||||||
erp = dasd_3990_erp_in_erp(cqr);
|
erp = dasd_3990_erp_in_erp(cqr);
|
||||||
|
@@ -415,6 +415,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
|
|||||||
dev_info->gd->queue = dev_info->dcssblk_queue;
|
dev_info->gd->queue = dev_info->dcssblk_queue;
|
||||||
dev_info->gd->private_data = dev_info;
|
dev_info->gd->private_data = dev_info;
|
||||||
dev_info->gd->driverfs_dev = &dev_info->dev;
|
dev_info->gd->driverfs_dev = &dev_info->dev;
|
||||||
|
blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
|
||||||
|
blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
|
||||||
/*
|
/*
|
||||||
* load the segment
|
* load the segment
|
||||||
*/
|
*/
|
||||||
@@ -472,9 +474,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto unregister_dev;
|
goto unregister_dev;
|
||||||
|
|
||||||
blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
|
|
||||||
blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
|
|
||||||
|
|
||||||
add_disk(dev_info->gd);
|
add_disk(dev_info->gd);
|
||||||
|
|
||||||
switch (dev_info->segment_type) {
|
switch (dev_info->segment_type) {
|
||||||
|
@@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count)
|
|||||||
if (sclp_ttybuf == NULL) {
|
if (sclp_ttybuf == NULL) {
|
||||||
while (list_empty(&sclp_tty_pages)) {
|
while (list_empty(&sclp_tty_pages)) {
|
||||||
spin_unlock_irqrestore(&sclp_tty_lock, flags);
|
spin_unlock_irqrestore(&sclp_tty_lock, flags);
|
||||||
if (in_interrupt())
|
if (in_atomic())
|
||||||
sclp_sync_wait();
|
sclp_sync_wait();
|
||||||
else
|
else
|
||||||
wait_event(sclp_tty_waitq,
|
wait_event(sclp_tty_waitq,
|
||||||
|
@@ -400,7 +400,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
|
|||||||
while (list_empty(&sclp_vt220_empty)) {
|
while (list_empty(&sclp_vt220_empty)) {
|
||||||
spin_unlock_irqrestore(&sclp_vt220_lock,
|
spin_unlock_irqrestore(&sclp_vt220_lock,
|
||||||
flags);
|
flags);
|
||||||
if (in_interrupt())
|
if (in_atomic())
|
||||||
sclp_sync_wait();
|
sclp_sync_wait();
|
||||||
else
|
else
|
||||||
wait_event(sclp_vt220_waitq,
|
wait_event(sclp_vt220_waitq,
|
||||||
|
@@ -391,12 +391,24 @@ ccwgroup_remove (struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ccwgroup_shutdown(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ccwgroup_device *gdev;
|
||||||
|
struct ccwgroup_driver *gdrv;
|
||||||
|
|
||||||
|
gdev = to_ccwgroupdev(dev);
|
||||||
|
gdrv = to_ccwgroupdrv(dev->driver);
|
||||||
|
if (gdrv && gdrv->shutdown)
|
||||||
|
gdrv->shutdown(gdev);
|
||||||
|
}
|
||||||
|
|
||||||
static struct bus_type ccwgroup_bus_type = {
|
static struct bus_type ccwgroup_bus_type = {
|
||||||
.name = "ccwgroup",
|
.name = "ccwgroup",
|
||||||
.match = ccwgroup_bus_match,
|
.match = ccwgroup_bus_match,
|
||||||
.uevent = ccwgroup_uevent,
|
.uevent = ccwgroup_uevent,
|
||||||
.probe = ccwgroup_probe,
|
.probe = ccwgroup_probe,
|
||||||
.remove = ccwgroup_remove,
|
.remove = ccwgroup_remove,
|
||||||
|
.shutdown = ccwgroup_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -26,6 +26,25 @@
|
|||||||
|
|
||||||
static void *sei_page;
|
static void *sei_page;
|
||||||
|
|
||||||
|
static int chsc_error_from_response(int response)
|
||||||
|
{
|
||||||
|
switch (response) {
|
||||||
|
case 0x0001:
|
||||||
|
return 0;
|
||||||
|
case 0x0002:
|
||||||
|
case 0x0003:
|
||||||
|
case 0x0006:
|
||||||
|
case 0x0007:
|
||||||
|
case 0x0008:
|
||||||
|
case 0x000a:
|
||||||
|
return -EINVAL;
|
||||||
|
case 0x0004:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
default:
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct chsc_ssd_area {
|
struct chsc_ssd_area {
|
||||||
struct chsc_header request;
|
struct chsc_header request;
|
||||||
u16 :10;
|
u16 :10;
|
||||||
@@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
|
|||||||
ret = (ccode == 3) ? -ENODEV : -EBUSY;
|
ret = (ccode == 3) ? -ENODEV : -EBUSY;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
if (ssd_area->response.code != 0x0001) {
|
ret = chsc_error_from_response(ssd_area->response.code);
|
||||||
|
if (ret != 0) {
|
||||||
CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
|
CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
|
||||||
schid.ssid, schid.sch_no,
|
schid.ssid, schid.sch_no,
|
||||||
ssd_area->response.code);
|
ssd_area->response.code);
|
||||||
ret = -EIO;
|
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
if (!ssd_area->sch_valid) {
|
if (!ssd_area->sch_valid) {
|
||||||
@@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
|
|||||||
return (ccode == 3) ? -ENODEV : -EBUSY;
|
return (ccode == 3) ? -ENODEV : -EBUSY;
|
||||||
|
|
||||||
switch (secm_area->response.code) {
|
switch (secm_area->response.code) {
|
||||||
case 0x0001: /* Success. */
|
case 0x0102:
|
||||||
ret = 0;
|
case 0x0103:
|
||||||
break;
|
|
||||||
case 0x0003: /* Invalid block. */
|
|
||||||
case 0x0007: /* Invalid format. */
|
|
||||||
case 0x0008: /* Other invalid block. */
|
|
||||||
CIO_CRW_EVENT(2, "Error in chsc request block!\n");
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
|
||||||
case 0x0004: /* Command not provided in model. */
|
|
||||||
CIO_CRW_EVENT(2, "Model does not provide secm\n");
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
case 0x0102: /* cub adresses incorrect */
|
|
||||||
CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
case 0x0103: /* key error */
|
|
||||||
CIO_CRW_EVENT(2, "Access key error in secm\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
case 0x0105: /* error while starting */
|
|
||||||
CIO_CRW_EVENT(2, "Error while starting channel measurement\n");
|
|
||||||
ret = -EIO;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
|
ret = chsc_error_from_response(secm_area->response.code);
|
||||||
secm_area->response.code);
|
|
||||||
ret = -EIO;
|
|
||||||
}
|
}
|
||||||
|
if (ret != 0)
|
||||||
|
CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
|
||||||
|
secm_area->response.code);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (scpd_area->response.code) {
|
ret = chsc_error_from_response(scpd_area->response.code);
|
||||||
case 0x0001: /* Success. */
|
if (ret == 0)
|
||||||
|
/* Success. */
|
||||||
memcpy(desc, &scpd_area->desc,
|
memcpy(desc, &scpd_area->desc,
|
||||||
sizeof(struct channel_path_desc));
|
sizeof(struct channel_path_desc));
|
||||||
ret = 0;
|
else
|
||||||
break;
|
CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
|
||||||
case 0x0003: /* Invalid block. */
|
|
||||||
case 0x0007: /* Invalid format. */
|
|
||||||
case 0x0008: /* Other invalid block. */
|
|
||||||
CIO_CRW_EVENT(2, "Error in chsc request block!\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
case 0x0004: /* Command not provided in model. */
|
|
||||||
CIO_CRW_EVENT(2, "Model does not provide scpd\n");
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
|
|
||||||
scpd_area->response.code);
|
scpd_area->response.code);
|
||||||
ret = -EIO;
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
free_page((unsigned long)scpd_area);
|
free_page((unsigned long)scpd_area);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (scmc_area->response.code) {
|
ret = chsc_error_from_response(scmc_area->response.code);
|
||||||
case 0x0001: /* Success. */
|
if (ret == 0) {
|
||||||
|
/* Success. */
|
||||||
if (!scmc_area->not_valid) {
|
if (!scmc_area->not_valid) {
|
||||||
chp->cmg = scmc_area->cmg;
|
chp->cmg = scmc_area->cmg;
|
||||||
chp->shared = scmc_area->shared;
|
chp->shared = scmc_area->shared;
|
||||||
@@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
|
|||||||
chp->cmg = -1;
|
chp->cmg = -1;
|
||||||
chp->shared = -1;
|
chp->shared = -1;
|
||||||
}
|
}
|
||||||
ret = 0;
|
} else {
|
||||||
break;
|
CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
|
||||||
case 0x0003: /* Invalid block. */
|
|
||||||
case 0x0007: /* Invalid format. */
|
|
||||||
case 0x0008: /* Invalid bit combination. */
|
|
||||||
CIO_CRW_EVENT(2, "Error in chsc request block!\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
case 0x0004: /* Command not provided. */
|
|
||||||
CIO_CRW_EVENT(2, "Model does not provide scmc\n");
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
|
|
||||||
scmc_area->response.code);
|
scmc_area->response.code);
|
||||||
ret = -EIO;
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
free_page((unsigned long)scmc_area);
|
free_page((unsigned long)scmc_area);
|
||||||
@@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code)
|
|||||||
ret = (ret == 3) ? -ENODEV : -EBUSY;
|
ret = (ret == 3) ? -ENODEV : -EBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sda_area->response.code) {
|
switch (sda_area->response.code) {
|
||||||
case 0x0001: /* everything ok */
|
case 0x0101:
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
case 0x0003: /* invalid request block */
|
|
||||||
case 0x0007:
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
case 0x0004: /* command not provided */
|
|
||||||
case 0x0101: /* facility not provided */
|
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
break;
|
break;
|
||||||
default: /* something went wrong */
|
default:
|
||||||
ret = -EIO;
|
ret = chsc_error_from_response(sda_area->response.code);
|
||||||
}
|
}
|
||||||
|
if (ret != 0)
|
||||||
|
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
|
||||||
|
operation_code, sda_area->response.code);
|
||||||
out:
|
out:
|
||||||
free_page((unsigned long)sda_area);
|
free_page((unsigned long)sda_area);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void)
|
|||||||
} __attribute__ ((packed)) *scsc_area;
|
} __attribute__ ((packed)) *scsc_area;
|
||||||
|
|
||||||
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
|
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
|
||||||
if (!scsc_area) {
|
if (!scsc_area)
|
||||||
CIO_MSG_EVENT(0, "Was not able to determine available "
|
|
||||||
"CHSCs due to no memory.\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
scsc_area->request.length = 0x0010;
|
scsc_area->request.length = 0x0010;
|
||||||
scsc_area->request.code = 0x0010;
|
scsc_area->request.code = 0x0010;
|
||||||
|
|
||||||
result = chsc(scsc_area);
|
result = chsc(scsc_area);
|
||||||
if (result) {
|
if (result) {
|
||||||
CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
|
result = (result == 3) ? -ENODEV : -EBUSY;
|
||||||
"cc=%i.\n", result);
|
|
||||||
result = -EIO;
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scsc_area->response.code != 1) {
|
result = chsc_error_from_response(scsc_area->response.code);
|
||||||
CIO_MSG_EVENT(0, "Was not able to determine "
|
if (result == 0) {
|
||||||
"available CHSCs.\n");
|
memcpy(&css_general_characteristics, scsc_area->general_char,
|
||||||
result = -EIO;
|
sizeof(css_general_characteristics));
|
||||||
goto exit;
|
memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
|
||||||
}
|
sizeof(css_chsc_characteristics));
|
||||||
memcpy(&css_general_characteristics, scsc_area->general_char,
|
} else
|
||||||
sizeof(css_general_characteristics));
|
CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
|
||||||
memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
|
scsc_area->response.code);
|
||||||
sizeof(css_chsc_characteristics));
|
|
||||||
exit:
|
exit:
|
||||||
free_page ((unsigned long) scsc_area);
|
free_page ((unsigned long) scsc_area);
|
||||||
return result;
|
return result;
|
||||||
|
@@ -26,17 +26,18 @@
|
|||||||
#include "ioasm.h"
|
#include "ioasm.h"
|
||||||
#include "io_sch.h"
|
#include "io_sch.h"
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Input :
|
* vm_vdev_to_cu_type - Convert vm virtual device into control unit type
|
||||||
* devno - device number
|
* for certain devices.
|
||||||
* ps - pointer to sense ID data area
|
* @class: virtual device class
|
||||||
* Output : none
|
* @type: virtual device type
|
||||||
|
*
|
||||||
|
* Returns control unit type if a match was made or %0xffff otherwise.
|
||||||
*/
|
*/
|
||||||
static void
|
static int vm_vdev_to_cu_type(int class, int type)
|
||||||
VM_virtual_device_info (__u16 devno, struct senseid *ps)
|
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
int vrdcvcla, vrdcvtyp, cu_type;
|
int class, type, cu_type;
|
||||||
} vm_devices[] = {
|
} vm_devices[] = {
|
||||||
{ 0x08, 0x01, 0x3480 },
|
{ 0x08, 0x01, 0x3480 },
|
||||||
{ 0x08, 0x02, 0x3430 },
|
{ 0x08, 0x02, 0x3430 },
|
||||||
@@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
|
|||||||
{ 0x40, 0xc0, 0x5080 },
|
{ 0x40, 0xc0, 0x5080 },
|
||||||
{ 0x80, 0x00, 0x3215 },
|
{ 0x80, 0x00, 0x3215 },
|
||||||
};
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
|
||||||
|
if (class == vm_devices[i].class && type == vm_devices[i].type)
|
||||||
|
return vm_devices[i].cu_type;
|
||||||
|
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* diag_get_dev_info - retrieve device information via DIAG X'210'
|
||||||
|
* @devno: device number
|
||||||
|
* @ps: pointer to sense ID data area
|
||||||
|
*
|
||||||
|
* Returns zero on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
static int diag_get_dev_info(u16 devno, struct senseid *ps)
|
||||||
|
{
|
||||||
struct diag210 diag_data;
|
struct diag210 diag_data;
|
||||||
int ccode, i;
|
int ccode;
|
||||||
|
|
||||||
CIO_TRACE_EVENT (4, "VMvdinf");
|
CIO_TRACE_EVENT (4, "VMvdinf");
|
||||||
|
|
||||||
@@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
|
|||||||
};
|
};
|
||||||
|
|
||||||
ccode = diag210 (&diag_data);
|
ccode = diag210 (&diag_data);
|
||||||
ps->reserved = 0xff;
|
if ((ccode == 0) || (ccode == 2)) {
|
||||||
|
ps->reserved = 0xff;
|
||||||
|
|
||||||
/* Special case for bloody osa devices. */
|
/* Special case for osa devices. */
|
||||||
if (diag_data.vrdcvcla == 0x02 &&
|
if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
|
||||||
diag_data.vrdcvtyp == 0x20) {
|
ps->cu_type = 0x3088;
|
||||||
ps->cu_type = 0x3088;
|
ps->cu_model = 0x60;
|
||||||
ps->cu_model = 0x60;
|
return 0;
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
|
|
||||||
if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla &&
|
|
||||||
diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) {
|
|
||||||
ps->cu_type = vm_devices[i].cu_type;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
|
||||||
|
diag_data.vrdcvtyp);
|
||||||
|
if (ps->cu_type != 0xffff)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
|
CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
|
||||||
"vdev class : %02X, vdev type : %04X \n ... "
|
"vdev class : %02X, vdev type : %04X \n ... "
|
||||||
"rdev class : %02X, rdev type : %04X, "
|
"rdev class : %02X, rdev type : %04X, "
|
||||||
@@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
|
|||||||
diag_data.vrdcvcla, diag_data.vrdcvtyp,
|
diag_data.vrdcvcla, diag_data.vrdcvtyp,
|
||||||
diag_data.vrdcrccl, diag_data.vrdccrty,
|
diag_data.vrdcrccl, diag_data.vrdccrty,
|
||||||
diag_data.vrdccrmd);
|
diag_data.vrdccrmd);
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
|
|||||||
/* Try on every path. */
|
/* Try on every path. */
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
while (cdev->private->imask != 0) {
|
while (cdev->private->imask != 0) {
|
||||||
|
cdev->private->senseid.cu_type = 0xFFFF;
|
||||||
if ((sch->opm & cdev->private->imask) != 0 &&
|
if ((sch->opm & cdev->private->imask) != 0 &&
|
||||||
cdev->private->iretry > 0) {
|
cdev->private->iretry > 0) {
|
||||||
cdev->private->iretry--;
|
cdev->private->iretry--;
|
||||||
@@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset (&cdev->private->senseid, 0, sizeof (struct senseid));
|
memset (&cdev->private->senseid, 0, sizeof (struct senseid));
|
||||||
cdev->private->senseid.cu_type = 0xFFFF;
|
|
||||||
cdev->private->imask = 0x80;
|
cdev->private->imask = 0x80;
|
||||||
cdev->private->iretry = 5;
|
cdev->private->iretry = 5;
|
||||||
ret = __ccw_device_sense_id_start(cdev);
|
ret = __ccw_device_sense_id_start(cdev);
|
||||||
@@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
|
|||||||
|
|
||||||
sch = to_subchannel(cdev->dev.parent);
|
sch = to_subchannel(cdev->dev.parent);
|
||||||
irb = &cdev->private->irb;
|
irb = &cdev->private->irb;
|
||||||
/* Did we get a proper answer ? */
|
|
||||||
if (cdev->private->senseid.cu_type != 0xFFFF &&
|
|
||||||
cdev->private->senseid.reserved == 0xFF) {
|
|
||||||
if (irb->scsw.count < sizeof (struct senseid) - 8)
|
|
||||||
cdev->private->flags.esid = 1;
|
|
||||||
return 0; /* Success */
|
|
||||||
}
|
|
||||||
/* Check the error cases. */
|
/* Check the error cases. */
|
||||||
if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
|
if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
|
||||||
/* Retry Sense ID if requested. */
|
/* Retry Sense ID if requested. */
|
||||||
@@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
|
|||||||
sch->schid.ssid, sch->schid.sch_no);
|
sch->schid.ssid, sch->schid.sch_no);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Did we get a proper answer ? */
|
||||||
|
if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
|
||||||
|
cdev->private->senseid.reserved == 0xFF) {
|
||||||
|
if (irb->scsw.count < sizeof(struct senseid) - 8)
|
||||||
|
cdev->private->flags.esid = 1;
|
||||||
|
return 0; /* Success */
|
||||||
|
}
|
||||||
|
|
||||||
/* Hmm, whatever happened, try again. */
|
/* Hmm, whatever happened, try again. */
|
||||||
CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
|
CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
|
||||||
"subchannel 0.%x.%04x returns status %02X%02X\n",
|
"subchannel 0.%x.%04x returns status %02X%02X\n",
|
||||||
@@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
|
|||||||
break;
|
break;
|
||||||
/* fall through. */
|
/* fall through. */
|
||||||
default: /* Sense ID failed. Try asking VM. */
|
default: /* Sense ID failed. Try asking VM. */
|
||||||
if (MACHINE_IS_VM) {
|
if (MACHINE_IS_VM)
|
||||||
VM_virtual_device_info (cdev->private->dev_id.devno,
|
ret = diag_get_dev_info(cdev->private->dev_id.devno,
|
||||||
&cdev->private->senseid);
|
&cdev->private->senseid);
|
||||||
if (cdev->private->senseid.cu_type != 0xFFFF) {
|
else
|
||||||
/* Got the device information from VM. */
|
/*
|
||||||
ccw_device_sense_id_done(cdev, 0);
|
* If we can't couldn't identify the device type we
|
||||||
return;
|
* consider the device "not operational".
|
||||||
}
|
*/
|
||||||
}
|
ret = -ENODEV;
|
||||||
/*
|
|
||||||
* If we can't couldn't identify the device type we
|
ccw_device_sense_id_done(cdev, ret);
|
||||||
* consider the device "not operational".
|
|
||||||
*/
|
|
||||||
ccw_device_sense_id_done(cdev, -ENODEV);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -440,242 +440,256 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
|
|||||||
__test_bit((nr),(addr)) )
|
__test_bit((nr),(addr)) )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ffz = Find First Zero in word. Undefined if no zero exists,
|
* Optimized find bit helper functions.
|
||||||
* so code should check against ~0UL first..
|
|
||||||
*/
|
*/
|
||||||
static inline unsigned long ffz(unsigned long word)
|
|
||||||
{
|
|
||||||
unsigned long bit = 0;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __ffz_word_loop - find byte offset of first long != -1UL
|
||||||
|
* @addr: pointer to array of unsigned long
|
||||||
|
* @size: size of the array in bits
|
||||||
|
*/
|
||||||
|
static inline unsigned long __ffz_word_loop(const unsigned long *addr,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
||||||
|
unsigned long bytes = 0;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
#ifndef __s390x__
|
||||||
|
" ahi %1,31\n"
|
||||||
|
" srl %1,5\n"
|
||||||
|
"0: c %2,0(%0,%3)\n"
|
||||||
|
" jne 1f\n"
|
||||||
|
" la %0,4(%0)\n"
|
||||||
|
" brct %1,0b\n"
|
||||||
|
"1:\n"
|
||||||
|
#else
|
||||||
|
" aghi %1,63\n"
|
||||||
|
" srlg %1,%1,6\n"
|
||||||
|
"0: cg %2,0(%0,%3)\n"
|
||||||
|
" jne 1f\n"
|
||||||
|
" la %0,8(%0)\n"
|
||||||
|
" brct %1,0b\n"
|
||||||
|
"1:\n"
|
||||||
|
#endif
|
||||||
|
: "+a" (bytes), "+d" (size)
|
||||||
|
: "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr)
|
||||||
|
: "cc" );
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __ffs_word_loop - find byte offset of first long != 0UL
|
||||||
|
* @addr: pointer to array of unsigned long
|
||||||
|
* @size: size of the array in bits
|
||||||
|
*/
|
||||||
|
static inline unsigned long __ffs_word_loop(const unsigned long *addr,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
||||||
|
unsigned long bytes = 0;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
#ifndef __s390x__
|
||||||
|
" ahi %1,31\n"
|
||||||
|
" srl %1,5\n"
|
||||||
|
"0: c %2,0(%0,%3)\n"
|
||||||
|
" jne 1f\n"
|
||||||
|
" la %0,4(%0)\n"
|
||||||
|
" brct %1,0b\n"
|
||||||
|
"1:\n"
|
||||||
|
#else
|
||||||
|
" aghi %1,63\n"
|
||||||
|
" srlg %1,%1,6\n"
|
||||||
|
"0: cg %2,0(%0,%3)\n"
|
||||||
|
" jne 1f\n"
|
||||||
|
" la %0,8(%0)\n"
|
||||||
|
" brct %1,0b\n"
|
||||||
|
"1:\n"
|
||||||
|
#endif
|
||||||
|
: "+a" (bytes), "+a" (size)
|
||||||
|
: "d" (0UL), "a" (addr), "m" (*(addrtype *) addr)
|
||||||
|
: "cc" );
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __ffz_word - add number of the first unset bit
|
||||||
|
* @nr: base value the bit number is added to
|
||||||
|
* @word: the word that is searched for unset bits
|
||||||
|
*/
|
||||||
|
static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)
|
||||||
|
{
|
||||||
#ifdef __s390x__
|
#ifdef __s390x__
|
||||||
if (likely((word & 0xffffffff) == 0xffffffff)) {
|
if (likely((word & 0xffffffff) == 0xffffffff)) {
|
||||||
word >>= 32;
|
word >>= 32;
|
||||||
bit += 32;
|
nr += 32;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (likely((word & 0xffff) == 0xffff)) {
|
if (likely((word & 0xffff) == 0xffff)) {
|
||||||
word >>= 16;
|
word >>= 16;
|
||||||
bit += 16;
|
nr += 16;
|
||||||
}
|
}
|
||||||
if (likely((word & 0xff) == 0xff)) {
|
if (likely((word & 0xff) == 0xff)) {
|
||||||
word >>= 8;
|
word >>= 8;
|
||||||
bit += 8;
|
nr += 8;
|
||||||
}
|
}
|
||||||
return bit + _zb_findmap[word & 0xff];
|
return nr + _zb_findmap[(unsigned char) word];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* __ffs = find first bit in word. Undefined if no bit exists,
|
* __ffs_word - add number of the first set bit
|
||||||
* so code should check against 0UL first..
|
* @nr: base value the bit number is added to
|
||||||
|
* @word: the word that is searched for set bits
|
||||||
*/
|
*/
|
||||||
static inline unsigned long __ffs (unsigned long word)
|
static inline unsigned long __ffs_word(unsigned long nr, unsigned long word)
|
||||||
{
|
{
|
||||||
unsigned long bit = 0;
|
|
||||||
|
|
||||||
#ifdef __s390x__
|
#ifdef __s390x__
|
||||||
if (likely((word & 0xffffffff) == 0)) {
|
if (likely((word & 0xffffffff) == 0)) {
|
||||||
word >>= 32;
|
word >>= 32;
|
||||||
bit += 32;
|
nr += 32;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (likely((word & 0xffff) == 0)) {
|
if (likely((word & 0xffff) == 0)) {
|
||||||
word >>= 16;
|
word >>= 16;
|
||||||
bit += 16;
|
nr += 16;
|
||||||
}
|
}
|
||||||
if (likely((word & 0xff) == 0)) {
|
if (likely((word & 0xff) == 0)) {
|
||||||
word >>= 8;
|
word >>= 8;
|
||||||
bit += 8;
|
nr += 8;
|
||||||
}
|
}
|
||||||
return bit + _sb_findmap[word & 0xff];
|
return nr + _sb_findmap[(unsigned char) word];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __load_ulong_be - load big endian unsigned long
|
||||||
|
* @p: pointer to array of unsigned long
|
||||||
|
* @offset: byte offset of source value in the array
|
||||||
|
*/
|
||||||
|
static inline unsigned long __load_ulong_be(const unsigned long *p,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
p = (unsigned long *)((unsigned long) p + offset);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __load_ulong_le - load little endian unsigned long
|
||||||
|
* @p: pointer to array of unsigned long
|
||||||
|
* @offset: byte offset of source value in the array
|
||||||
|
*/
|
||||||
|
static inline unsigned long __load_ulong_le(const unsigned long *p,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
unsigned long word;
|
||||||
|
|
||||||
|
p = (unsigned long *)((unsigned long) p + offset);
|
||||||
|
#ifndef __s390x__
|
||||||
|
asm volatile(
|
||||||
|
" ic %0,0(%1)\n"
|
||||||
|
" icm %0,2,1(%1)\n"
|
||||||
|
" icm %0,4,2(%1)\n"
|
||||||
|
" icm %0,8,3(%1)"
|
||||||
|
: "=&d" (word) : "a" (p), "m" (*p) : "cc");
|
||||||
|
#else
|
||||||
|
asm volatile(
|
||||||
|
" lrvg %0,%1"
|
||||||
|
: "=d" (word) : "m" (*p) );
|
||||||
|
#endif
|
||||||
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find-bit routines..
|
* The various find bit functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __s390x__
|
/*
|
||||||
|
* ffz - find first zero in word.
|
||||||
static inline int
|
* @word: The word to search
|
||||||
find_first_zero_bit(const unsigned long * addr, unsigned long size)
|
*
|
||||||
|
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||||
|
*/
|
||||||
|
static inline unsigned long ffz(unsigned long word)
|
||||||
{
|
{
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
return __ffz_word(0, word);
|
||||||
unsigned long cmp, count;
|
}
|
||||||
unsigned int res;
|
|
||||||
|
/**
|
||||||
|
* __ffs - find first bit in word.
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no bit exists, so code should check against 0 first.
|
||||||
|
*/
|
||||||
|
static inline unsigned long __ffs (unsigned long word)
|
||||||
|
{
|
||||||
|
return __ffs_word(0, word);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ffs - find first bit set
|
||||||
|
* @x: the word to search
|
||||||
|
*
|
||||||
|
* This is defined the same way as
|
||||||
|
* the libc and compiler builtin ffs routines, therefore
|
||||||
|
* differs in spirit from the above ffz (man ffs).
|
||||||
|
*/
|
||||||
|
static inline int ffs(int x)
|
||||||
|
{
|
||||||
|
if (!x)
|
||||||
|
return 0;
|
||||||
|
return __ffs_word(1, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_first_zero_bit - find the first zero bit in a memory region
|
||||||
|
* @addr: The address to start the search at
|
||||||
|
* @size: The maximum size to search
|
||||||
|
*
|
||||||
|
* Returns the bit-number of the first zero bit, not the number of the byte
|
||||||
|
* containing a bit.
|
||||||
|
*/
|
||||||
|
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long bytes, bits;
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
asm volatile(
|
bytes = __ffz_word_loop(addr, size);
|
||||||
" lhi %1,-1\n"
|
bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
|
||||||
" lr %2,%3\n"
|
return (bits < size) ? bits : size;
|
||||||
" slr %0,%0\n"
|
|
||||||
" ahi %2,31\n"
|
|
||||||
" srl %2,5\n"
|
|
||||||
"0: c %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" la %0,4(%0)\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lr %0,%3\n"
|
|
||||||
" j 4f\n"
|
|
||||||
"1: l %2,0(%0,%4)\n"
|
|
||||||
" sll %0,3\n"
|
|
||||||
" lhi %1,0xff\n"
|
|
||||||
" tml %2,0xffff\n"
|
|
||||||
" jno 2f\n"
|
|
||||||
" ahi %0,16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"2: tml %2,0x00ff\n"
|
|
||||||
" jno 3f\n"
|
|
||||||
" ahi %0,8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"3: nr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" alr %0,%2\n"
|
|
||||||
"4:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (addr), "a" (&_zb_findmap),
|
|
||||||
"m" (*(addrtype *) addr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
/**
|
||||||
find_first_bit(const unsigned long * addr, unsigned long size)
|
* find_first_bit - find the first set bit in a memory region
|
||||||
|
* @addr: The address to start the search at
|
||||||
|
* @size: The maximum size to search
|
||||||
|
*
|
||||||
|
* Returns the bit-number of the first set bit, not the number of the byte
|
||||||
|
* containing a bit.
|
||||||
|
*/
|
||||||
|
static inline unsigned long find_first_bit(const unsigned long * addr,
|
||||||
|
unsigned long size)
|
||||||
{
|
{
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
unsigned long bytes, bits;
|
||||||
unsigned long cmp, count;
|
|
||||||
unsigned int res;
|
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
asm volatile(
|
bytes = __ffs_word_loop(addr, size);
|
||||||
" slr %1,%1\n"
|
bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
|
||||||
" lr %2,%3\n"
|
return (bits < size) ? bits : size;
|
||||||
" slr %0,%0\n"
|
|
||||||
" ahi %2,31\n"
|
|
||||||
" srl %2,5\n"
|
|
||||||
"0: c %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" la %0,4(%0)\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lr %0,%3\n"
|
|
||||||
" j 4f\n"
|
|
||||||
"1: l %2,0(%0,%4)\n"
|
|
||||||
" sll %0,3\n"
|
|
||||||
" lhi %1,0xff\n"
|
|
||||||
" tml %2,0xffff\n"
|
|
||||||
" jnz 2f\n"
|
|
||||||
" ahi %0,16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"2: tml %2,0x00ff\n"
|
|
||||||
" jnz 3f\n"
|
|
||||||
" ahi %0,8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"3: nr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" alr %0,%2\n"
|
|
||||||
"4:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (addr), "a" (&_sb_findmap),
|
|
||||||
"m" (*(addrtype *) addr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* __s390x__ */
|
/**
|
||||||
|
* find_next_zero_bit - find the first zero bit in a memory region
|
||||||
static inline unsigned long
|
* @addr: The address to base the search on
|
||||||
find_first_zero_bit(const unsigned long * addr, unsigned long size)
|
* @offset: The bitnumber to start searching at
|
||||||
{
|
* @size: The maximum size to search
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
*/
|
||||||
unsigned long res, cmp, count;
|
static inline int find_next_zero_bit (const unsigned long * addr,
|
||||||
|
unsigned long size,
|
||||||
if (!size)
|
unsigned long offset)
|
||||||
return 0;
|
|
||||||
asm volatile(
|
|
||||||
" lghi %1,-1\n"
|
|
||||||
" lgr %2,%3\n"
|
|
||||||
" slgr %0,%0\n"
|
|
||||||
" aghi %2,63\n"
|
|
||||||
" srlg %2,%2,6\n"
|
|
||||||
"0: cg %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" la %0,8(%0)\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lgr %0,%3\n"
|
|
||||||
" j 5f\n"
|
|
||||||
"1: lg %2,0(%0,%4)\n"
|
|
||||||
" sllg %0,%0,3\n"
|
|
||||||
" clr %2,%1\n"
|
|
||||||
" jne 2f\n"
|
|
||||||
" aghi %0,32\n"
|
|
||||||
" srlg %2,%2,32\n"
|
|
||||||
"2: lghi %1,0xff\n"
|
|
||||||
" tmll %2,0xffff\n"
|
|
||||||
" jno 3f\n"
|
|
||||||
" aghi %0,16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"3: tmll %2,0x00ff\n"
|
|
||||||
" jno 4f\n"
|
|
||||||
" aghi %0,8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"4: ngr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" algr %0,%2\n"
|
|
||||||
"5:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (addr), "a" (&_zb_findmap),
|
|
||||||
"m" (*(addrtype *) addr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned long
|
|
||||||
find_first_bit(const unsigned long * addr, unsigned long size)
|
|
||||||
{
|
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
|
||||||
unsigned long res, cmp, count;
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
return 0;
|
|
||||||
asm volatile(
|
|
||||||
" slgr %1,%1\n"
|
|
||||||
" lgr %2,%3\n"
|
|
||||||
" slgr %0,%0\n"
|
|
||||||
" aghi %2,63\n"
|
|
||||||
" srlg %2,%2,6\n"
|
|
||||||
"0: cg %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" aghi %0,8\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lgr %0,%3\n"
|
|
||||||
" j 5f\n"
|
|
||||||
"1: lg %2,0(%0,%4)\n"
|
|
||||||
" sllg %0,%0,3\n"
|
|
||||||
" clr %2,%1\n"
|
|
||||||
" jne 2f\n"
|
|
||||||
" aghi %0,32\n"
|
|
||||||
" srlg %2,%2,32\n"
|
|
||||||
"2: lghi %1,0xff\n"
|
|
||||||
" tmll %2,0xffff\n"
|
|
||||||
" jnz 3f\n"
|
|
||||||
" aghi %0,16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"3: tmll %2,0x00ff\n"
|
|
||||||
" jnz 4f\n"
|
|
||||||
" aghi %0,8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"4: ngr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" algr %0,%2\n"
|
|
||||||
"5:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (addr), "a" (&_sb_findmap),
|
|
||||||
"m" (*(addrtype *) addr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __s390x__ */
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
find_next_zero_bit (const unsigned long * addr, unsigned long size,
|
|
||||||
unsigned long offset)
|
|
||||||
{
|
{
|
||||||
const unsigned long *p;
|
const unsigned long *p;
|
||||||
unsigned long bit, set;
|
unsigned long bit, set;
|
||||||
@@ -688,10 +702,10 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size,
|
|||||||
p = addr + offset / __BITOPS_WORDSIZE;
|
p = addr + offset / __BITOPS_WORDSIZE;
|
||||||
if (bit) {
|
if (bit) {
|
||||||
/*
|
/*
|
||||||
* s390 version of ffz returns __BITOPS_WORDSIZE
|
* __ffz_word returns __BITOPS_WORDSIZE
|
||||||
* if no zero bit is present in the word.
|
* if no zero bit is present in the word.
|
||||||
*/
|
*/
|
||||||
set = ffz(*p >> bit) + bit;
|
set = __ffz_word(0, *p >> bit) + bit;
|
||||||
if (set >= size)
|
if (set >= size)
|
||||||
return size + offset;
|
return size + offset;
|
||||||
if (set < __BITOPS_WORDSIZE)
|
if (set < __BITOPS_WORDSIZE)
|
||||||
@@ -703,9 +717,15 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size,
|
|||||||
return offset + find_first_zero_bit(p, size);
|
return offset + find_first_zero_bit(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
/**
|
||||||
find_next_bit (const unsigned long * addr, unsigned long size,
|
* find_next_bit - find the first set bit in a memory region
|
||||||
unsigned long offset)
|
* @addr: The address to base the search on
|
||||||
|
* @offset: The bitnumber to start searching at
|
||||||
|
* @size: The maximum size to search
|
||||||
|
*/
|
||||||
|
static inline int find_next_bit (const unsigned long * addr,
|
||||||
|
unsigned long size,
|
||||||
|
unsigned long offset)
|
||||||
{
|
{
|
||||||
const unsigned long *p;
|
const unsigned long *p;
|
||||||
unsigned long bit, set;
|
unsigned long bit, set;
|
||||||
@@ -718,10 +738,10 @@ find_next_bit (const unsigned long * addr, unsigned long size,
|
|||||||
p = addr + offset / __BITOPS_WORDSIZE;
|
p = addr + offset / __BITOPS_WORDSIZE;
|
||||||
if (bit) {
|
if (bit) {
|
||||||
/*
|
/*
|
||||||
* s390 version of __ffs returns __BITOPS_WORDSIZE
|
* __ffs_word returns __BITOPS_WORDSIZE
|
||||||
* if no one bit is present in the word.
|
* if no one bit is present in the word.
|
||||||
*/
|
*/
|
||||||
set = __ffs(*p & (~0UL << bit));
|
set = __ffs_word(0, *p & (~0UL << bit));
|
||||||
if (set >= size)
|
if (set >= size)
|
||||||
return size + offset;
|
return size + offset;
|
||||||
if (set < __BITOPS_WORDSIZE)
|
if (set < __BITOPS_WORDSIZE)
|
||||||
@@ -744,8 +764,6 @@ static inline int sched_find_first_bit(unsigned long *b)
|
|||||||
return find_first_bit(b, 140);
|
return find_first_bit(b, 140);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <asm-generic/bitops/ffs.h>
|
|
||||||
|
|
||||||
#include <asm-generic/bitops/fls.h>
|
#include <asm-generic/bitops/fls.h>
|
||||||
#include <asm-generic/bitops/fls64.h>
|
#include <asm-generic/bitops/fls64.h>
|
||||||
|
|
||||||
@@ -772,108 +790,23 @@ static inline int sched_find_first_bit(unsigned long *b)
|
|||||||
test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
|
test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
|
||||||
#define ext2_test_bit(nr, addr) \
|
#define ext2_test_bit(nr, addr) \
|
||||||
test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
|
test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
|
||||||
#define ext2_find_next_bit(addr, size, off) \
|
|
||||||
generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
|
|
||||||
|
|
||||||
#ifndef __s390x__
|
static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size)
|
||||||
|
|
||||||
static inline int
|
|
||||||
ext2_find_first_zero_bit(void *vaddr, unsigned int size)
|
|
||||||
{
|
{
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
unsigned long bytes, bits;
|
||||||
unsigned long cmp, count;
|
|
||||||
unsigned int res;
|
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
asm volatile(
|
bytes = __ffz_word_loop(vaddr, size);
|
||||||
" lhi %1,-1\n"
|
bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
|
||||||
" lr %2,%3\n"
|
return (bits < size) ? bits : size;
|
||||||
" ahi %2,31\n"
|
|
||||||
" srl %2,5\n"
|
|
||||||
" slr %0,%0\n"
|
|
||||||
"0: cl %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" ahi %0,4\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lr %0,%3\n"
|
|
||||||
" j 4f\n"
|
|
||||||
"1: l %2,0(%0,%4)\n"
|
|
||||||
" sll %0,3\n"
|
|
||||||
" ahi %0,24\n"
|
|
||||||
" lhi %1,0xff\n"
|
|
||||||
" tmh %2,0xffff\n"
|
|
||||||
" jo 2f\n"
|
|
||||||
" ahi %0,-16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"2: tml %2,0xff00\n"
|
|
||||||
" jo 3f\n"
|
|
||||||
" ahi %0,-8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"3: nr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" alr %0,%2\n"
|
|
||||||
"4:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (vaddr), "a" (&_zb_findmap),
|
|
||||||
"m" (*(addrtype *) vaddr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* __s390x__ */
|
static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size,
|
||||||
|
unsigned long offset)
|
||||||
static inline unsigned long
|
|
||||||
ext2_find_first_zero_bit(void *vaddr, unsigned long size)
|
|
||||||
{
|
|
||||||
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
|
|
||||||
unsigned long res, cmp, count;
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
return 0;
|
|
||||||
asm volatile(
|
|
||||||
" lghi %1,-1\n"
|
|
||||||
" lgr %2,%3\n"
|
|
||||||
" aghi %2,63\n"
|
|
||||||
" srlg %2,%2,6\n"
|
|
||||||
" slgr %0,%0\n"
|
|
||||||
"0: clg %1,0(%0,%4)\n"
|
|
||||||
" jne 1f\n"
|
|
||||||
" aghi %0,8\n"
|
|
||||||
" brct %2,0b\n"
|
|
||||||
" lgr %0,%3\n"
|
|
||||||
" j 5f\n"
|
|
||||||
"1: cl %1,0(%0,%4)\n"
|
|
||||||
" jne 2f\n"
|
|
||||||
" aghi %0,4\n"
|
|
||||||
"2: l %2,0(%0,%4)\n"
|
|
||||||
" sllg %0,%0,3\n"
|
|
||||||
" aghi %0,24\n"
|
|
||||||
" lghi %1,0xff\n"
|
|
||||||
" tmlh %2,0xffff\n"
|
|
||||||
" jo 3f\n"
|
|
||||||
" aghi %0,-16\n"
|
|
||||||
" srl %2,16\n"
|
|
||||||
"3: tmll %2,0xff00\n"
|
|
||||||
" jo 4f\n"
|
|
||||||
" aghi %0,-8\n"
|
|
||||||
" srl %2,8\n"
|
|
||||||
"4: ngr %2,%1\n"
|
|
||||||
" ic %2,0(%2,%5)\n"
|
|
||||||
" algr %0,%2\n"
|
|
||||||
"5:"
|
|
||||||
: "=&a" (res), "=&d" (cmp), "=&a" (count)
|
|
||||||
: "a" (size), "a" (vaddr), "a" (&_zb_findmap),
|
|
||||||
"m" (*(addrtype *) vaddr) : "cc");
|
|
||||||
return (res < size) ? res : size;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __s390x__ */
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
|
|
||||||
{
|
{
|
||||||
unsigned long *addr = vaddr, *p;
|
unsigned long *addr = vaddr, *p;
|
||||||
unsigned long word, bit, set;
|
unsigned long bit, set;
|
||||||
|
|
||||||
if (offset >= size)
|
if (offset >= size)
|
||||||
return size;
|
return size;
|
||||||
@@ -882,23 +815,11 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
|
|||||||
size -= offset;
|
size -= offset;
|
||||||
p = addr + offset / __BITOPS_WORDSIZE;
|
p = addr + offset / __BITOPS_WORDSIZE;
|
||||||
if (bit) {
|
if (bit) {
|
||||||
#ifndef __s390x__
|
|
||||||
asm volatile(
|
|
||||||
" ic %0,0(%1)\n"
|
|
||||||
" icm %0,2,1(%1)\n"
|
|
||||||
" icm %0,4,2(%1)\n"
|
|
||||||
" icm %0,8,3(%1)"
|
|
||||||
: "=&a" (word) : "a" (p), "m" (*p) : "cc");
|
|
||||||
#else
|
|
||||||
asm volatile(
|
|
||||||
" lrvg %0,%1"
|
|
||||||
: "=a" (word) : "m" (*p) );
|
|
||||||
#endif
|
|
||||||
/*
|
/*
|
||||||
* s390 version of ffz returns __BITOPS_WORDSIZE
|
* s390 version of ffz returns __BITOPS_WORDSIZE
|
||||||
* if no zero bit is present in the word.
|
* if no zero bit is present in the word.
|
||||||
*/
|
*/
|
||||||
set = ffz(word >> bit) + bit;
|
set = ffz(__load_ulong_le(p, 0) >> bit) + bit;
|
||||||
if (set >= size)
|
if (set >= size)
|
||||||
return size + offset;
|
return size + offset;
|
||||||
if (set < __BITOPS_WORDSIZE)
|
if (set < __BITOPS_WORDSIZE)
|
||||||
@@ -910,6 +831,47 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
|
|||||||
return offset + ext2_find_first_zero_bit(p, size);
|
return offset + ext2_find_first_zero_bit(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned long ext2_find_first_bit(void *vaddr,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long bytes, bits;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
bytes = __ffs_word_loop(vaddr, size);
|
||||||
|
bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
|
||||||
|
return (bits < size) ? bits : size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ext2_find_next_bit(void *vaddr, unsigned long size,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
unsigned long *addr = vaddr, *p;
|
||||||
|
unsigned long bit, set;
|
||||||
|
|
||||||
|
if (offset >= size)
|
||||||
|
return size;
|
||||||
|
bit = offset & (__BITOPS_WORDSIZE - 1);
|
||||||
|
offset -= bit;
|
||||||
|
size -= offset;
|
||||||
|
p = addr + offset / __BITOPS_WORDSIZE;
|
||||||
|
if (bit) {
|
||||||
|
/*
|
||||||
|
* s390 version of ffz returns __BITOPS_WORDSIZE
|
||||||
|
* if no zero bit is present in the word.
|
||||||
|
*/
|
||||||
|
set = ffs(__load_ulong_le(p, 0) >> bit) + bit;
|
||||||
|
if (set >= size)
|
||||||
|
return size + offset;
|
||||||
|
if (set < __BITOPS_WORDSIZE)
|
||||||
|
return set + offset;
|
||||||
|
offset += __BITOPS_WORDSIZE;
|
||||||
|
size -= __BITOPS_WORDSIZE;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return offset + ext2_find_first_bit(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
#include <asm-generic/bitops/minix.h>
|
#include <asm-generic/bitops/minix.h>
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
@@ -24,4 +24,8 @@
|
|||||||
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
|
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
|
||||||
memcpy(dst, src, len)
|
memcpy(dst, src, len)
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
|
void kernel_map_pages(struct page *page, int numpages, int enable);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _S390_CACHEFLUSH_H */
|
#endif /* _S390_CACHEFLUSH_H */
|
||||||
|
@@ -37,6 +37,7 @@ struct ccwgroup_device {
|
|||||||
* @remove: function called on remove
|
* @remove: function called on remove
|
||||||
* @set_online: function called when device is set online
|
* @set_online: function called when device is set online
|
||||||
* @set_offline: function called when device is set offline
|
* @set_offline: function called when device is set offline
|
||||||
|
* @shutdown: function called when device is shut down
|
||||||
* @driver: embedded driver structure
|
* @driver: embedded driver structure
|
||||||
*/
|
*/
|
||||||
struct ccwgroup_driver {
|
struct ccwgroup_driver {
|
||||||
@@ -49,6 +50,7 @@ struct ccwgroup_driver {
|
|||||||
void (*remove) (struct ccwgroup_device *);
|
void (*remove) (struct ccwgroup_device *);
|
||||||
int (*set_online) (struct ccwgroup_device *);
|
int (*set_online) (struct ccwgroup_device *);
|
||||||
int (*set_offline) (struct ccwgroup_device *);
|
int (*set_offline) (struct ccwgroup_device *);
|
||||||
|
void (*shutdown)(struct ccwgroup_device *);
|
||||||
|
|
||||||
struct device_driver driver;
|
struct device_driver driver;
|
||||||
};
|
};
|
||||||
|
@@ -115,15 +115,21 @@ extern char empty_zero_page[PAGE_SIZE];
|
|||||||
#ifndef __s390x__
|
#ifndef __s390x__
|
||||||
#define VMALLOC_START 0x78000000UL
|
#define VMALLOC_START 0x78000000UL
|
||||||
#define VMALLOC_END 0x7e000000UL
|
#define VMALLOC_END 0x7e000000UL
|
||||||
#define VMEM_MAP_MAX 0x80000000UL
|
#define VMEM_MAP_END 0x80000000UL
|
||||||
#else /* __s390x__ */
|
#else /* __s390x__ */
|
||||||
#define VMALLOC_START 0x3e000000000UL
|
#define VMALLOC_START 0x3e000000000UL
|
||||||
#define VMALLOC_END 0x3e040000000UL
|
#define VMALLOC_END 0x3e040000000UL
|
||||||
#define VMEM_MAP_MAX 0x40000000000UL
|
#define VMEM_MAP_END 0x40000000000UL
|
||||||
#endif /* __s390x__ */
|
#endif /* __s390x__ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1
|
||||||
|
* mapping. This needs to be calculated at compile time since the size of the
|
||||||
|
* VMEM_MAP is static but the size of struct page can change.
|
||||||
|
*/
|
||||||
|
#define VMEM_MAX_PHYS min(VMALLOC_START, ((VMEM_MAP_END - VMALLOC_END) / \
|
||||||
|
sizeof(struct page) * PAGE_SIZE) & ~((16 << 20) - 1))
|
||||||
#define VMEM_MAP ((struct page *) VMALLOC_END)
|
#define VMEM_MAP ((struct page *) VMALLOC_END)
|
||||||
#define VMEM_MAP_SIZE ((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A 31 bit pagetable entry of S390 has following format:
|
* A 31 bit pagetable entry of S390 has following format:
|
||||||
|
Reference in New Issue
Block a user