Commit 39ce941e authored by Linus Torvalds's avatar Linus Torvalds

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
parents 3d412f60 c5411dba
...@@ -59,7 +59,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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: ...@@ -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: ...@@ -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 @@ ...@@ -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: ...@@ -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: ...@@ -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) ...@@ -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 @@ static int ipl_init(void) ...@@ -471,8 +471,11 @@ static int ipl_init(void)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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; ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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 = { ...@@ -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 @@ static int smp_add_present_cpu(int cpu) ...@@ -1036,8 +1035,8 @@ static int smp_add_present_cpu(int cpu)
} }
#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 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ static void __dasd_process_block_ccw_queue(struct dasd_block *block, ...@@ -1742,12 +1741,8 @@ static void __dasd_process_block_ccw_queue(struct dasd_block *block,
/* 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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;
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; 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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) { ...@@ -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)
/**
* __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)
{ {
unsigned long bit = 0; 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];
} }
/*
* Find-bit routines..
*/
#ifndef __s390x__ /**
* __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;
}
static inline int /**
find_first_zero_bit(const unsigned long * addr, unsigned long size) * __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)
{ {
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; unsigned long word;
unsigned long cmp, count;
unsigned int res;
if (!size) p = (unsigned long *)((unsigned long) p + offset);
return 0; #ifndef __s390x__
asm volatile( asm volatile(
" lhi %1,-1\n" " ic %0,0(%1)\n"
" lr %2,%3\n" " icm %0,2,1(%1)\n"
" slr %0,%0\n" " icm %0,4,2(%1)\n"
" ahi %2,31\n" " icm %0,8,3(%1)"
" srl %2,5\n" : "=&d" (word) : "a" (p), "m" (*p) : "cc");
"0: c %1,0(%0,%4)\n" #else
" jne 1f\n" asm volatile(
" la %0,4(%0)\n" " lrvg %0,%1"
" brct %2,0b\n" : "=d" (word) : "m" (*p) );
" lr %0,%3\n" #endif
" j 4f\n" return word;
"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) * The various find bit functions.
*/
/*
* ffz - find first zero in word.
* @word: The word to search
*
* 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;
if (!size) /**
return 0; * __ffs - find first bit in word.
asm volatile( * @word: The word to search
" slr %1,%1\n" *
" lr %2,%3\n" * Undefined if no bit exists, so code should check against 0 first.
" slr %0,%0\n" */
" ahi %2,31\n" static inline unsigned long __ffs (unsigned long word)
" srl %2,5\n" {
"0: c %1,0(%0,%4)\n" return __ffs_word(0, word);
" 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__ */ /**
* 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);
}
static inline unsigned long /**
find_first_zero_bit(const unsigned long * addr, unsigned long size) * 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)
{ {
typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; unsigned long bytes, bits;
unsigned long res, cmp, count;
if (!size) if (!size)
return 0; return 0;
asm volatile( bytes = __ffz_word_loop(addr, size);
" lghi %1,-1\n" bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
" lgr %2,%3\n" return (bits < size) ? bits : size;
" slgr %0,%0\n" }
" aghi %2,63\n"
" srlg %2,%2,6\n" /**
"0: cg %1,0(%0,%4)\n" * find_first_bit - find the first set bit in a memory region
" jne 1f\n" * @addr: The address to start the search at
" la %0,8(%0)\n" * @size: The maximum size to search
" brct %2,0b\n" *
" lgr %0,%3\n" * Returns the bit-number of the first set bit, not the number of the byte
" j 5f\n" * containing a bit.
"1: lg %2,0(%0,%4)\n" */
" sllg %0,%0,3\n" static inline unsigned long find_first_bit(const unsigned long * addr,
" clr %2,%1\n" unsigned long size)
" 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 bytes, bits;
unsigned long res, cmp, count;
if (!size) if (!size)
return 0; return 0;
asm volatile( bytes = __ffs_word_loop(addr, size);
" slgr %1,%1\n" bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
" lgr %2,%3\n" return (bits < size) ? bits : size;
" 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__ */ /**
* find_next_zero_bit - find the first zero bit in a memory region
static inline int * @addr: The address to base the search on
find_next_zero_bit (const unsigned long * addr, unsigned long size, * @offset: The bitnumber to start searching at
unsigned long offset) * @size: The maximum size to search
*/
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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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]; ...@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment