Commit 17db3da8 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: comon i/o layer

From: Utz Bacher <utz.bacher@de.ibm.com>
From: Cornelia Huck <cohuck@de.ibm.com>

Common i/o layer changes:
 - Consolidate store channel subsystem characteristics from its three
   users (css, cmf and qdio) to a single location.
 - Always use new stipd format and move creation of global path group
   to channel subsystem init function. Add dummy init_IRQ to setup.c
   and remove requestirq.c.
 - Remove bogus CHPID_LONGS define.
 - Add more magic to catch chpids coming online again without generating
   machine checks.
 - Fix check for unsolicited interrupts. Deferred cc=1 indicates a
   solicited interrupt.
 - Fix progress indication in qdio summary bytes to avoid loosing interrupts.
 - Rename console_device to console_devno to avoid naming conflict.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3fb67b11
...@@ -613,10 +613,6 @@ startup:basr %r13,0 # get base ...@@ -613,10 +613,6 @@ startup:basr %r13,0 # get base
bne .Lnop390-.LPG1(%r13) bne .Lnop390-.LPG1(%r13)
oi 3(%r12),4 # set P/390 flag oi 3(%r12),4 # set P/390 flag
.Lnop390: .Lnop390:
chi %r0,0x2084 # new stidp format?
bne .Loldfmt-.LPG1(%r13)
oi 3(%r12),64 # set new stidp flag
.Loldfmt:
# #
# find out if we have an IEEE fpu # find out if we have an IEEE fpu
......
...@@ -623,10 +623,6 @@ startup:basr %r13,0 # get base ...@@ -623,10 +623,6 @@ startup:basr %r13,0 # get base
bne 1f-.LPG1(%r13) bne 1f-.LPG1(%r13)
oi 7(%r12),4 # set P/390 flag oi 7(%r12),4 # set P/390 flag
1: 1:
chi %r0,0x2084 # new stidp format?
bne 2f-.LPG1(%r13)
oi 7(%r12),64 # set new stidp flag
2:
# #
# find out if we have the MVPG instruction # find out if we have the MVPG instruction
......
...@@ -72,7 +72,8 @@ EXPORT_SYMBOL(__udelay); ...@@ -72,7 +72,8 @@ EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(csum_fold);
EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_mode);
EXPORT_SYMBOL(console_device); EXPORT_SYMBOL(console_devno);
EXPORT_SYMBOL(console_irq);
EXPORT_SYMBOL_NOVERS(do_call_softirq); EXPORT_SYMBOL_NOVERS(do_call_softirq);
EXPORT_SYMBOL(sys_wait4); EXPORT_SYMBOL(sys_wait4);
EXPORT_SYMBOL(cpcmd); EXPORT_SYMBOL(cpcmd);
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* Machine setup.. * Machine setup..
*/ */
unsigned int console_mode = 0; unsigned int console_mode = 0;
unsigned int console_device = -1; unsigned int console_devno = -1;
unsigned int console_irq = -1; unsigned int console_irq = -1;
unsigned long memory_size = 0; unsigned long memory_size = 0;
unsigned long machine_flags = 0; unsigned long machine_flags = 0;
...@@ -160,7 +160,7 @@ static int __init condev_setup(char *str) ...@@ -160,7 +160,7 @@ static int __init condev_setup(char *str)
vdev = simple_strtoul(str, &str, 0); vdev = simple_strtoul(str, &str, 0);
if (vdev >= 0 && vdev < 65536) { if (vdev >= 0 && vdev < 65536) {
console_device = vdev; console_devno = vdev;
console_irq = -1; console_irq = -1;
} }
return 1; return 1;
...@@ -194,7 +194,7 @@ static void __init conmode_default(void) ...@@ -194,7 +194,7 @@ static void __init conmode_default(void)
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {
cpcmd("QUERY CONSOLE", query_buffer, 1024); cpcmd("QUERY CONSOLE", query_buffer, 1024);
console_device = simple_strtoul(query_buffer + 5, NULL, 16); console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
ptr = strstr(query_buffer, "SUBCHANNEL ="); ptr = strstr(query_buffer, "SUBCHANNEL =");
console_irq = simple_strtoul(ptr + 13, NULL, 16); console_irq = simple_strtoul(ptr + 13, NULL, 16);
cpcmd("QUERY TERM", query_buffer, 1024); cpcmd("QUERY TERM", query_buffer, 1024);
...@@ -649,3 +649,13 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -649,3 +649,13 @@ int show_interrupts(struct seq_file *p, void *v)
return 0; return 0;
} }
/*
* For compatibilty only. S/390 specific setup of interrupts et al. is done
* much later in init_channel_subsystem().
*/
void __init
init_IRQ(void)
{
/* nothing... */
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the S/390 common i/o drivers # Makefile for the S/390 common i/o drivers
# #
obj-y += airq.o blacklist.o chsc.o cio.o css.o requestirq.o obj-y += airq.o blacklist.o chsc.o cio.o css.o
ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o obj-y += ccw_device.o cmf.o
......
/* /*
* drivers/s390/cio/chsc.c * drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call * S/390 common I/O routines -- channel subsystem call
* $Revision: 1.112 $ * $Revision: 1.114 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -942,3 +942,59 @@ chsc_alloc_sei_area(void) ...@@ -942,3 +942,59 @@ chsc_alloc_sei_area(void)
} }
subsys_initcall(chsc_alloc_sei_area); subsys_initcall(chsc_alloc_sei_area);
struct css_general_char css_general_characteristics;
struct css_chsc_char css_chsc_characteristics;
int __init
chsc_determine_css_characteristics(void)
{
int result;
struct {
struct chsc_header request;
u32 reserved1;
u32 reserved2;
u32 reserved3;
struct chsc_header response;
u32 reserved4;
u32 general_char[510];
u32 chsc_char[518];
} *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
printk(KERN_WARNING"cio: Was not able to determine available" \
"CHSCs due to no memory.\n");
return -ENOMEM;
}
scsc_area->request = (struct chsc_header) {
.length = 0x0010,
.code = 0x0010,
};
result = chsc(scsc_area);
if (result) {
printk(KERN_WARNING"cio: Was not able to determine " \
"available CHSCs, cc=%i.\n", result);
result = -EIO;
goto exit;
}
if (scsc_area->response.code != 1) {
printk(KERN_WARNING"cio: Was not able to determine " \
"available CHSCs.\n");
result = -EIO;
goto exit;
}
memcpy(&css_general_characteristics, scsc_area->general_char,
sizeof(css_general_characteristics));
memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
sizeof(css_chsc_characteristics));
exit:
free_page ((unsigned long) scsc_area);
return result;
}
EXPORT_SYMBOL_GPL(css_general_characteristics);
EXPORT_SYMBOL_GPL(css_chsc_characteristics);
...@@ -23,4 +23,32 @@ extern struct channel_path *chps[]; ...@@ -23,4 +23,32 @@ extern struct channel_path *chps[];
extern void s390_process_css( void ); extern void s390_process_css( void );
extern void chsc_validate_chpids(struct subchannel *); extern void chsc_validate_chpids(struct subchannel *);
extern void chpid_is_actually_online(int); extern void chpid_is_actually_online(int);
struct css_general_char {
u64 : 41;
u32 aif : 1; /* bit 41 */
u32 : 3;
u32 mcss : 1; /* bit 45 */
u32 : 2;
u32 ext_mb : 1; /* bit 48 */
u32 : 7;
u32 aif_tdd : 1; /* bit 56 */
u32 : 10;
u32 aif_osa : 1; /* bit 67 */
u32 : 28;
}__attribute__((packed));
struct css_chsc_char {
u64 res;
u64 : 43;
u32 scssc : 1; /* bit 107 */
u32 scsscf : 1; /* bit 108 */
u32 : 19;
}__attribute__((packed));
extern struct css_general_char css_general_characteristics;
extern struct css_chsc_char css_chsc_characteristics;
extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail;
#endif #endif
...@@ -688,15 +688,15 @@ cio_console_irq(void) ...@@ -688,15 +688,15 @@ cio_console_irq(void)
if (stsch(console_irq, &console_subchannel.schib) != 0 || if (stsch(console_irq, &console_subchannel.schib) != 0 ||
!console_subchannel.schib.pmcw.dnv) !console_subchannel.schib.pmcw.dnv)
return -1; return -1;
console_device = console_subchannel.schib.pmcw.dev; console_devno = console_subchannel.schib.pmcw.dev;
} else if (console_device != -1) { } else if (console_devno != -1) {
/* At least the console device number is known. */ /* At least the console device number is known. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
if (stsch(irq, &console_subchannel.schib) != 0) if (stsch(irq, &console_subchannel.schib) != 0)
break; break;
if (console_subchannel.schib.pmcw.dnv && if (console_subchannel.schib.pmcw.dnv &&
console_subchannel.schib.pmcw.dev == console_subchannel.schib.pmcw.dev ==
console_device) { console_devno) {
console_irq = irq; console_irq = irq;
break; break;
} }
......
/* /*
* linux/drivers/s390/cio/cmf.c ($Revision: 1.13 $) * linux/drivers/s390/cio/cmf.c ($Revision: 1.15 $)
* *
* Linux on zSeries Channel Measurement Facility support * Linux on zSeries Channel Measurement Facility support
* *
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "css.h" #include "css.h"
#include "device.h" #include "device.h"
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h"
/* parameter to enable cmf during boot, possible uses are: /* parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
...@@ -996,7 +997,8 @@ init_cmf(void) ...@@ -996,7 +997,8 @@ init_cmf(void)
see if we are running on z990 or up, otherwise fall back to basic mode. */ see if we are running on z990 or up, otherwise fall back to basic mode. */
if (format == CMF_AUTODETECT) { if (format == CMF_AUTODETECT) {
if (!MACHINE_NEW_STIDP) { if (!css_characteristics_avail ||
!css_general_characteristics.ext_mb) {
format = CMF_BASIC; format = CMF_BASIC;
} else { } else {
format = CMF_EXTENDED; format = CMF_EXTENDED;
......
/* /*
* drivers/s390/cio/css.c * drivers/s390/cio/css.c
* driver for channel subsystem * driver for channel subsystem
* $Revision: 1.77 $ * $Revision: 1.80 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -19,11 +19,15 @@ ...@@ -19,11 +19,15 @@
#include "cio.h" #include "cio.h"
#include "cio_debug.h" #include "cio_debug.h"
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h"
unsigned int highest_subchannel; unsigned int highest_subchannel;
int need_rescan = 0; int need_rescan = 0;
int css_init_done = 0; int css_init_done = 0;
struct pgid global_pgid;
int css_characteristics_avail = 0;
struct device css_bus_device = { struct device css_bus_device = {
.bus_id = "css0", .bus_id = "css0",
}; };
...@@ -201,6 +205,20 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -201,6 +205,20 @@ css_evaluate_subchannel(int irq, int slow)
ret = 0; ret = 0;
break; break;
} }
if (disc && (event == CIO_NO_PATH)) {
/*
* Uargh, hack again. Because we don't get a machine
* check on configure on, our path bookkeeping can
* be out of date here (it's fine while we only do
* logical varying or get chsc machine checks). We
* need to force reprobing or we might miss devices
* coming operational again. It won't do harm in real
* no path situations.
*/
device_trigger_reprobe(sch);
ret = 0;
break;
}
if (sch->driver && sch->driver->notify && if (sch->driver && sch->driver->notify &&
sch->driver->notify(&sch->dev, event)) { sch->driver->notify(&sch->dev, event)) {
cio_disable_subchannel(sch); cio_disable_subchannel(sch);
...@@ -352,9 +370,26 @@ css_process_crw(int irq) ...@@ -352,9 +370,26 @@ css_process_crw(int irq)
return ret; return ret;
} }
static void __init
css_generate_pgid(void)
{
/* Let's build our path group ID here. */
if (css_characteristics_avail && css_general_characteristics.mcss)
global_pgid.cpu_addr = 0x8000;
else {
#ifdef CONFIG_SMP
global_pgid.cpu_addr = hard_smp_processor_id();
#else
global_pgid.cpu_addr = 0;
#endif
}
global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
global_pgid.tod_high = (__u32) (get_clock() >> 32);
}
/* /*
* some of the initialization has already been done from init_IRQ(), * Now that the driver core is running, we can setup our channel subsystem.
* here we do the rest now that the driver core is running.
* The struct subchannel's are created during probing (except for the * The struct subchannel's are created during probing (except for the
* static console subchannel). * static console subchannel).
*/ */
...@@ -363,6 +398,11 @@ init_channel_subsystem (void) ...@@ -363,6 +398,11 @@ init_channel_subsystem (void)
{ {
int ret, irq; int ret, irq;
if (chsc_determine_css_characteristics() == 0)
css_characteristics_avail = 1;
css_generate_pgid();
if ((ret = bus_register(&css_bus_type))) if ((ret = bus_register(&css_bus_type)))
goto out; goto out;
if ((ret = device_register (&css_bus_device))) if ((ret = device_register (&css_bus_device)))
...@@ -517,3 +557,4 @@ MODULE_LICENSE("GPL"); ...@@ -517,3 +557,4 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(css_bus_type); EXPORT_SYMBOL(css_bus_type);
EXPORT_SYMBOL(s390_root_dev_register); EXPORT_SYMBOL(s390_root_dev_register);
EXPORT_SYMBOL(s390_root_dev_unregister); EXPORT_SYMBOL(s390_root_dev_unregister);
EXPORT_SYMBOL_GPL(css_characteristics_avail);
...@@ -672,8 +672,20 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -672,8 +672,20 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */ /* Check for unsolicited interrupt. */
if (irb->scsw.stctl == if ((irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
&& (!irb->scsw.cc)) {
if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
!irb->esw.esw0.erw.cons) {
/* Unit check but no sense data. Need basic sense. */
if (ccw_device_do_sense(cdev, irb) != 0)
goto call_handler_unsol;
memcpy(irb, &cdev->private->irb, sizeof(struct irb));
cdev->private->state = DEV_STATE_W4SENSE;
cdev->private->intparm = 0;
return;
}
call_handler_unsol:
if (cdev->handler) if (cdev->handler)
cdev->handler (cdev, 0, irb); cdev->handler (cdev, 0, irb);
return; return;
...@@ -735,11 +747,15 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -735,11 +747,15 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Check for unsolicited interrupt. */ /* Check for unsolicited interrupt. */
if (irb->scsw.stctl == if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (cdev->handler)
cdev->handler (cdev, 0, irb);
if (irb->scsw.cc == 1) if (irb->scsw.cc == 1)
/* Basic sense hasn't started. Try again. */ /* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb); ccw_device_do_sense(cdev, irb);
else {
printk("Huh? %s(%s): unsolicited interrupt...\n",
__FUNCTION__, cdev->dev.bus_id);
if (cdev->handler)
cdev->handler (cdev, 0, irb);
}
return; return;
} }
/* Add basic sense info to irb. */ /* Add basic sense info to irb. */
...@@ -762,13 +778,6 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -762,13 +778,6 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
struct irb *irb; struct irb *irb;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (cdev->handler)
cdev->handler (cdev, 0, irb);
return;
}
/* Accumulate status. We don't do basic sense. */ /* Accumulate status. We don't do basic sense. */
ccw_device_accumulate_irb(cdev, irb); ccw_device_accumulate_irb(cdev, irb);
/* Try to start delayed device verification. */ /* Try to start delayed device verification. */
...@@ -834,15 +843,6 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -834,15 +843,6 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch; struct subchannel *sch;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (cdev->handler)
cdev->handler (cdev, 0, irb);
if (irb->scsw.cc == 1)
goto call_handler;
return;
}
/* /*
* Accumulate status and find out if a basic sense is needed. * Accumulate status and find out if a basic sense is needed.
* This is fine since we have already adapted the lpm. * This is fine since we have already adapted the lpm.
...@@ -854,7 +854,7 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -854,7 +854,7 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
} }
return; return;
} }
call_handler:
/* Iff device is idle, reset timeout. */ /* Iff device is idle, reset timeout. */
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!stsch(sch->irq, &sch->schib)) if (!stsch(sch->irq, &sch->schib))
...@@ -923,8 +923,9 @@ ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -923,8 +923,9 @@ ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event)
case DEV_EVENT_INTERRUPT: case DEV_EVENT_INTERRUPT:
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */ /* Check for unsolicited interrupt. */
if (irb->scsw.stctl == if ((irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
(!irb->scsw.cc))
/* FIXME: we should restart stlck here, but this /* FIXME: we should restart stlck here, but this
* is extremely unlikely ... */ * is extremely unlikely ... */
goto out_wakeup; goto out_wakeup;
......
...@@ -303,15 +303,14 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -303,15 +303,14 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* /* Retry sense id for cc=1. */
* Unsolicited interrupts may pertain to an earlier status pending or
* busy condition on the subchannel. Retry sense id.
*/
if (irb->scsw.stctl == if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
ret = __ccw_device_sense_id_start(cdev); if (irb->scsw.cc == 1) {
if (ret && ret != -EBUSY) ret = __ccw_device_sense_id_start(cdev);
ccw_device_sense_id_done(cdev, ret); if (ret && ret != -EBUSY)
ccw_device_sense_id_done(cdev, ret);
}
return; return;
} }
if (ccw_device_accumulate_and_sense(cdev, irb) != 0) if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
......
/* /*
* drivers/s390/cio/device_ops.c * drivers/s390/cio/device_ops.c
* *
* $Revision: 1.34 $ * $Revision: 1.47 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
......
...@@ -143,15 +143,14 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -143,15 +143,14 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
int ret; int ret;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* /* Retry sense pgid for cc=1. */
* Unsolicited interrupts may pertain to an earlier status pending or
* busy condition on the subchannel. Retry sense pgid.
*/
if (irb->scsw.stctl == if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
ret = __ccw_device_sense_pgid_start(cdev); if (irb->scsw.cc == 1) {
if (ret && ret != -EBUSY) ret = __ccw_device_sense_pgid_start(cdev);
ccw_device_sense_pgid_done(cdev, ret); if (ret && ret != -EBUSY)
ccw_device_sense_pgid_done(cdev, ret);
}
return; return;
} }
if (ccw_device_accumulate_and_sense(cdev, irb) != 0) if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
...@@ -310,13 +309,11 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -310,13 +309,11 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
struct irb *irb; struct irb *irb;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* /* Retry set pgid for cc=1. */
* Unsolicited interrupts may pertain to an earlier status pending or
* busy condition on the subchannel. Restart path verification.
*/
if (irb->scsw.stctl == if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
__ccw_device_verify_start(cdev); if (irb->scsw.cc == 1)
__ccw_device_verify_start(cdev);
return; return;
} }
if (ccw_device_accumulate_and_sense(cdev, irb) != 0) if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
...@@ -397,10 +394,13 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -397,10 +394,13 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
int ret; int ret;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Ignore unsolicited interrupts. */ /* Retry set pgid for cc=1. */
if (irb->scsw.stctl == if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (irb->scsw.cc == 1)
__ccw_device_disband_start(cdev);
return; return;
}
if (ccw_device_accumulate_and_sense(cdev, irb) != 0) if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return; return;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
......
...@@ -35,7 +35,7 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) ...@@ -35,7 +35,7 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
return; return;
CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
"received\n" "received"
" ... device %04X on subchannel %04X, dev_stat " " ... device %04X on subchannel %04X, dev_stat "
": %02X sch_stat : %02X\n", ": %02X sch_stat : %02X\n",
cdev->private->devno, cdev->private->irq, cdev->private->devno, cdev->private->irq,
...@@ -216,8 +216,9 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) ...@@ -216,8 +216,9 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
/* /*
* Don't accumulate unsolicited interrupts. * Don't accumulate unsolicited interrupts.
*/ */
if (irb->scsw.stctl == if ((irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
(!irb->scsw.cc))
return; return;
cdev_irb = &cdev->private->irb; cdev_irb = &cdev->private->irb;
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h" #include "chsc.h"
#define VERSION_QDIO_C "$Revision: 1.80 $" #define VERSION_QDIO_C "$Revision: 1.83 $"
/****************** MODULE PARAMETER VARIABLES ********************/ /****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
...@@ -354,7 +354,8 @@ qdio_stop_polling(struct qdio_q *q) ...@@ -354,7 +354,8 @@ qdio_stop_polling(struct qdio_q *q)
SLSB_P_INPUT_NOT_INIT); SLSB_P_INPUT_NOT_INIT);
/* /*
* we don't issue this SYNC_MEMORY, as we trust Rick T and * we don't issue this SYNC_MEMORY, as we trust Rick T and
* moreover will not use the PROCESSING state, so q->polling was 0 * moreover will not use the PROCESSING state under VM, so
* q->polling was 0 anyway
*/ */
/*SYNC_MEMORY;*/ /*SYNC_MEMORY;*/
if (q->slsb.acc.val[gsf]!=SLSB_P_INPUT_PRIMED) if (q->slsb.acc.val[gsf]!=SLSB_P_INPUT_PRIMED)
...@@ -732,6 +733,9 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -732,6 +733,9 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
volatile char *slsb; volatile char *slsb;
int first_not_to_check; int first_not_to_check;
char dbf_text[15]; char dbf_text[15];
#ifdef QDIO_USE_PROCESSING_STATE
int last_position=-1;
#endif /* QDIO_USE_PROCESSING_STATE */
QDIO_DBF_TEXT4(0,trace,"getibfro"); QDIO_DBF_TEXT4(0,trace,"getibfro");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
...@@ -774,8 +778,14 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -774,8 +778,14 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
if (q->siga_sync) { if (q->siga_sync) {
set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT); set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
} else { } else {
set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_PROCESSING); /* set the previous buffer to NOT_INIT. The current
* buffer will be set to PROCESSING at the end of
* this function to avoid further interrupts. */
if (last_position>=0)
set_slsb(&slsb[last_position],
SLSB_P_INPUT_NOT_INIT);
atomic_set(&q->polling,1); atomic_set(&q->polling,1);
last_position=f_mod_no;
} }
#else /* QDIO_USE_PROCESSING_STATE */ #else /* QDIO_USE_PROCESSING_STATE */
set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT); set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
...@@ -814,6 +824,10 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -814,6 +824,10 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1); f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
atomic_dec(&q->number_of_buffers_used); atomic_dec(&q->number_of_buffers_used);
#ifdef QDIO_USE_PROCESSING_STATE
last_position=-1;
#endif /* QDIO_USE_PROCESSING_STATE */
break; break;
/* everything else means frontier not changed (HALTED or so) */ /* everything else means frontier not changed (HALTED or so) */
...@@ -823,6 +837,11 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -823,6 +837,11 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q)
out: out:
q->first_to_check=f_mod_no; q->first_to_check=f_mod_no;
#ifdef QDIO_USE_PROCESSING_STATE
if (last_position>=0)
set_slsb(&slsb[last_position],SLSB_P_INPUT_PROCESSING);
#endif /* QDIO_USE_PROCESSING_STATE */
QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int)); QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
return q->first_to_check; return q->first_to_check;
...@@ -1160,7 +1179,7 @@ qdio_inbound_processing(struct qdio_q *q) ...@@ -1160,7 +1179,7 @@ qdio_inbound_processing(struct qdio_q *q)
#ifdef QDIO_USE_PROCESSING_STATE #ifdef QDIO_USE_PROCESSING_STATE
static inline int static inline int
tiqdio_do_inbound_checks(struct qdio_q *q, int q_laps) tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
{ {
if (!q) { if (!q) {
tiqdio_sched_tl(); tiqdio_sched_tl();
...@@ -1247,7 +1266,7 @@ tiqdio_inbound_checks(void) ...@@ -1247,7 +1266,7 @@ tiqdio_inbound_checks(void)
do { do {
int ret; int ret;
ret = tiqdio_do_inbound_checks(q, q_laps); ret = tiqdio_reset_processing_state(q, q_laps);
switch (ret) { switch (ret) {
case 0: case 0:
return; return;
...@@ -1971,77 +1990,36 @@ qdio_check_siga_needs(int sch) ...@@ -1971,77 +1990,36 @@ qdio_check_siga_needs(int sch)
static unsigned int static unsigned int
tiqdio_check_chsc_availability(void) tiqdio_check_chsc_availability(void)
{ {
int result;
char dbf_text[15]; char dbf_text[15];
struct { if (!css_characteristics_avail)
struct chsc_header request; return -EIO;
u32 reserved1;
u32 reserved2;
u32 reserved3;
struct chsc_header response;
u32 reserved4;
u32 general_char[510];
u32 chsc_char[518];
} *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
QDIO_PRINT_WARN("Was not able to determine available" \
"CHSCs due to no memory.\n");
return -ENOMEM;
}
scsc_area->request = (struct chsc_header) {
.length = 0x0010,
.code = 0x0010,
};
result=chsc(scsc_area);
if (result) {
QDIO_PRINT_WARN("Was not able to determine " \
"available CHSCs, cc=%i.\n",
result);
result=-EIO;
goto exit;
}
if (scsc_area->response.code != 1) {
QDIO_PRINT_WARN("Was not able to determine " \
"available CHSCs.\n");
result=-EIO;
goto exit;
}
/* Check for bit 41. */ /* Check for bit 41. */
if ((scsc_area->general_char[1] & 0x00400000) != 0x00400000) { if (!css_general_characteristics.aif) {
QDIO_PRINT_WARN("Adapter interruption facility not " \ QDIO_PRINT_WARN("Adapter interruption facility not " \
"installed.\n"); "installed.\n");
result=-ENOENT; return -ENOENT;
goto exit;
} }
/* Check for bits 107 and 108. */ /* Check for bits 107 and 108. */
if ((scsc_area->chsc_char[3] & 0x00180000) != 0x00180000) { if (!css_chsc_characteristics.scssc ||
!css_chsc_characteristics.scsscf) {
QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \ QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \
"not available.\n"); "not available.\n");
result=-ENOENT; return -ENOENT;
goto exit;
} }
/* Check for OSA/FCP thin interrupts (bit 67). */ /* Check for OSA/FCP thin interrupts (bit 67). */
hydra_thinints = ((scsc_area->general_char[2] & 0x10000000) hydra_thinints = css_general_characteristics.aif_osa;
== 0x10000000);
sprintf(dbf_text,"hydrati%1x", hydra_thinints); sprintf(dbf_text,"hydrati%1x", hydra_thinints);
QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text);
/* Check for aif time delay disablement fac (bit 56). If installed, /* Check for aif time delay disablement fac (bit 56). If installed,
* omit svs even under lpar (good point by rick again) */ * omit svs even under lpar (good point by rick again) */
omit_svs = ((scsc_area->general_char[1] & 0x00000080) omit_svs = css_general_characteristics.aif_tdd;
== 0x00000080);
sprintf(dbf_text,"omitsvs%1x", omit_svs); sprintf(dbf_text,"omitsvs%1x", omit_svs);
QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text);
exit: return 0;
free_page ((unsigned long) scsc_area);
return result;
} }
......
#ifndef _CIO_QDIO_H #ifndef _CIO_QDIO_H
#define _CIO_QDIO_H #define _CIO_QDIO_H
#define VERSION_CIO_QDIO_H "$Revision: 1.23 $" #define VERSION_CIO_QDIO_H "$Revision: 1.24 $"
//#define QDIO_DBF_LIKE_HELL //#define QDIO_DBF_LIKE_HELL
...@@ -518,6 +518,8 @@ struct qdio_perf_stats { ...@@ -518,6 +518,8 @@ struct qdio_perf_stats {
struct qdio_q { struct qdio_q {
volatile struct slsb slsb; volatile struct slsb slsb;
char unused[QDIO_MAX_BUFFERS_PER_Q];
__u32 * volatile dev_st_chg_ind; __u32 * volatile dev_st_chg_ind;
int is_input_q; int is_input_q;
......
/*
* drivers/s390/cio/requestirq.c
* S/390 common I/O routines -- enabling and disabling of devices
* $Revision: 1.46 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cohuck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/device.h>
#include <linux/init.h>
#include <asm/lowcore.h>
#include "css.h"
struct pgid global_pgid;
EXPORT_SYMBOL_GPL(global_pgid);
/*
* init_IRQ is now only used to set the pgid as early as possible
*/
void __init
init_IRQ(void)
{
/*
* Let's build our path group ID here.
*/
if (MACHINE_NEW_STIDP)
global_pgid.cpu_addr = 0x8000;
else {
#ifdef CONFIG_SMP
global_pgid.cpu_addr = hard_smp_processor_id();
#else
global_pgid.cpu_addr = 0;
#endif
}
global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
global_pgid.tod_high = (__u32) (get_clock() >> 32);
}
...@@ -36,7 +36,6 @@ extern unsigned long machine_flags; ...@@ -36,7 +36,6 @@ extern unsigned long machine_flags;
#define MACHINE_IS_P390 (machine_flags & 4) #define MACHINE_IS_P390 (machine_flags & 4)
#define MACHINE_HAS_MVPG (machine_flags & 16) #define MACHINE_HAS_MVPG (machine_flags & 16)
#define MACHINE_HAS_DIAG44 (machine_flags & 32) #define MACHINE_HAS_DIAG44 (machine_flags & 32)
#define MACHINE_NEW_STIDP (machine_flags & 64)
#define MACHINE_HAS_IDTE (machine_flags & 128) #define MACHINE_HAS_IDTE (machine_flags & 128)
#ifndef __s390x__ #ifndef __s390x__
...@@ -54,7 +53,7 @@ extern unsigned long machine_flags; ...@@ -54,7 +53,7 @@ extern unsigned long machine_flags;
* Console mode. Override with conmode= * Console mode. Override with conmode=
*/ */
extern unsigned int console_mode; extern unsigned int console_mode;
extern unsigned int console_device; extern unsigned int console_devno;
extern unsigned int console_irq; extern unsigned int console_irq;
#define CONSOLE_IS_UNDEFINED (console_mode == 0) #define CONSOLE_IS_UNDEFINED (console_mode == 0)
......
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