Commit 38eb0df2 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: common i/o layer

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Common i/o layer changes:
 - qdio: Lose the adapter lock for thin interrupts to improve performance
   and do unregister of the adapter interrupt handler with rcu.
 - ccwgroup: Fix error handling when creating a ccwgroup device.
 - Convert the slow crw kernel thread to a single threaded workqueue.
 - Use the slow crw workqueue to unregister a subchannel after it was
   found not operational to serialize it with other possible unregister/
   register events coming in via machine checks.
 - Trigger a rescan of the css via the slow path if a missing channel path
   is found in __recover_lost_chpids.
 - Use saner default levels for the debug feature, add some debugging code.
 - Remove request_irq and free_irq stubs.
 - Remove bogus inlines.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 67e26dda
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* drivers/s390/cio/airq.c * drivers/s390/cio/airq.c
* S/390 common I/O routines -- support for adapter interruptions * S/390 common I/O routines -- support for adapter interruptions
* *
* $Revision: 1.11 $ * $Revision: 1.12 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -14,11 +14,11 @@ ...@@ -14,11 +14,11 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rcupdate.h>
#include "cio_debug.h" #include "cio_debug.h"
#include "airq.h" #include "airq.h"
static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED;
static adapter_int_handler_t adapter_handler; static adapter_int_handler_t adapter_handler;
/* /*
...@@ -40,23 +40,17 @@ s390_register_adapter_interrupt (adapter_int_handler_t handler) ...@@ -40,23 +40,17 @@ s390_register_adapter_interrupt (adapter_int_handler_t handler)
CIO_TRACE_EVENT (4, "rgaint"); CIO_TRACE_EVENT (4, "rgaint");
spin_lock (&adapter_lock);
if (handler == NULL) if (handler == NULL)
ret = -EINVAL; ret = -EINVAL;
else if (adapter_handler) else
ret = -EBUSY; ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
else { if (!ret)
adapter_handler = handler; synchronize_kernel();
ret = 0;
}
spin_unlock (&adapter_lock);
sprintf (dbf_txt, "ret:%d", ret); sprintf (dbf_txt, "ret:%d", ret);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
return (ret); return ret;
} }
int int
...@@ -67,38 +61,26 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler) ...@@ -67,38 +61,26 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
CIO_TRACE_EVENT (4, "urgaint"); CIO_TRACE_EVENT (4, "urgaint");
spin_lock (&adapter_lock);
if (handler == NULL) if (handler == NULL)
ret = -EINVAL; ret = -EINVAL;
else if (handler != adapter_handler)
ret = -EINVAL;
else { else {
adapter_handler = NULL; adapter_handler = NULL;
synchronize_kernel();
ret = 0; ret = 0;
} }
spin_unlock (&adapter_lock);
sprintf (dbf_txt, "ret:%d", ret); sprintf (dbf_txt, "ret:%d", ret);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
return (ret); return ret;
} }
void void
do_adapter_IO (void) do_adapter_IO (void)
{ {
CIO_TRACE_EVENT (4, "doaio"); CIO_TRACE_EVENT (6, "doaio");
spin_lock (&adapter_lock);
if (adapter_handler) if (adapter_handler)
(*adapter_handler) (); (*adapter_handler) ();
spin_unlock (&adapter_lock);
return;
} }
EXPORT_SYMBOL (s390_register_adapter_interrupt); EXPORT_SYMBOL (s390_register_adapter_interrupt);
......
/* /*
* drivers/s390/cio/ccwgroup.c * drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup * bus driver for ccwgroup
* $Revision: 1.27 $ * $Revision: 1.28 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -179,12 +179,12 @@ ccwgroup_create(struct device *root, ...@@ -179,12 +179,12 @@ ccwgroup_create(struct device *root,
|| gdev->cdev[i]->id.driver_info != || gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) { gdev->cdev[0]->id.driver_info) {
rc = -EINVAL; rc = -EINVAL;
goto error; goto free_dev;
} }
/* Don't allow a device to belong to more than one group. */ /* Don't allow a device to belong to more than one group. */
if (gdev->cdev[i]->dev.driver_data) { if (gdev->cdev[i]->dev.driver_data) {
rc = -EINVAL; rc = -EINVAL;
goto error; goto free_dev;
} }
} }
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
...@@ -207,8 +207,8 @@ ccwgroup_create(struct device *root, ...@@ -207,8 +207,8 @@ ccwgroup_create(struct device *root,
rc = device_register(&gdev->dev); rc = device_register(&gdev->dev);
if (rc) if (rc)
goto error; goto free_dev;
get_device(&gdev->dev);
rc = device_create_file(&gdev->dev, &dev_attr_ungroup); rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
if (rc) { if (rc) {
...@@ -217,12 +217,21 @@ ccwgroup_create(struct device *root, ...@@ -217,12 +217,21 @@ ccwgroup_create(struct device *root,
} }
rc = __ccwgroup_create_symlinks(gdev); rc = __ccwgroup_create_symlinks(gdev);
if (!rc) if (!rc) {
put_device(&gdev->dev);
return 0; return 0;
}
device_remove_file(&gdev->dev, &dev_attr_ungroup); device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev); device_unregister(&gdev->dev);
error: error:
for (i = 0; i < argc; i++)
if (gdev->cdev[i]) {
put_device(&gdev->cdev[i]->dev);
gdev->cdev[i]->dev.driver_data = NULL;
}
put_device(&gdev->dev);
return rc;
free_dev:
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
if (gdev->cdev[i]) { if (gdev->cdev[i]) {
put_device(&gdev->cdev[i]->dev); put_device(&gdev->cdev[i]->dev);
...@@ -230,7 +239,6 @@ ccwgroup_create(struct device *root, ...@@ -230,7 +239,6 @@ ccwgroup_create(struct device *root,
gdev->cdev[i]->dev.driver_data = NULL; gdev->cdev[i]->dev.driver_data = NULL;
} }
kfree(gdev); kfree(gdev);
return rc; return rc;
} }
......
/* /*
* 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.110 $ * $Revision: 1.111 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -62,11 +62,11 @@ chpid_is_actually_online(int chp) ...@@ -62,11 +62,11 @@ chpid_is_actually_online(int chp)
int state; int state;
state = get_chp_status(chp); state = get_chp_status(chp);
if (state < 0) if (state < 0) {
new_channel_path(chp); need_rescan = 1;
else queue_work(slow_path_wq, &slow_path_work);
} else
WARN_ON(!state); WARN_ON(!state);
/* FIXME: should notify other subchannels here */
} }
/* FIXME: this is _always_ called for every subchannel. shouldn't we /* FIXME: this is _always_ called for every subchannel. shouldn't we
...@@ -285,8 +285,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) ...@@ -285,8 +285,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
out_unreg: out_unreg:
spin_unlock(&sch->lock); spin_unlock(&sch->lock);
sch->lpm = 0; sch->lpm = 0;
/* We can't block here. */ if (css_enqueue_subchannel_slow(sch->irq)) {
device_call_nopath_notify(sch); css_clear_subchannel_slow_list();
need_rescan = 1;
}
return 0; return 0;
} }
...@@ -303,6 +305,9 @@ s390_set_chpid_offline( __u8 chpid) ...@@ -303,6 +305,9 @@ s390_set_chpid_offline( __u8 chpid)
bus_for_each_dev(&css_bus_type, NULL, &chpid, bus_for_each_dev(&css_bus_type, NULL, &chpid,
s390_subchannel_remove_chpid); s390_subchannel_remove_chpid);
if (need_rescan || css_slow_subchannels_exist())
queue_work(slow_path_wq, &slow_path_work);
} }
static int static int
...@@ -737,10 +742,12 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) ...@@ -737,10 +742,12 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
* can successfully terminate, even using the * can successfully terminate, even using the
* just varied off path. Then kill it. * just varied off path. Then kill it.
*/ */
if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
/* Get over with it now. */ if (css_enqueue_subchannel_slow(sch->irq)) {
device_call_nopath_notify(sch); css_clear_subchannel_slow_list();
else if (sch->driver && sch->driver->verify) need_rescan = 1;
}
} else if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev); sch->driver->verify(&sch->dev);
} }
break; break;
...@@ -773,11 +780,6 @@ s390_subchannel_vary_chpid_on(struct device *dev, void *data) ...@@ -773,11 +780,6 @@ s390_subchannel_vary_chpid_on(struct device *dev, void *data)
return 0; return 0;
} }
extern void css_trigger_slow_path(void);
typedef void (*workfunc)(void *);
static DECLARE_WORK(varyonoff_work, (workfunc)css_trigger_slow_path,
NULL);
/* /*
* Function: s390_vary_chpid * Function: s390_vary_chpid
* Varies the specified chpid online or offline * Varies the specified chpid online or offline
...@@ -813,7 +815,7 @@ s390_vary_chpid( __u8 chpid, int on) ...@@ -813,7 +815,7 @@ s390_vary_chpid( __u8 chpid, int on)
s390_subchannel_vary_chpid_on : s390_subchannel_vary_chpid_on :
s390_subchannel_vary_chpid_off); s390_subchannel_vary_chpid_off);
if (!on) if (!on)
return 0; goto out;
/* Scan for new devices on varied on path. */ /* Scan for new devices on varied on path. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
struct schib schib; struct schib schib;
...@@ -835,8 +837,9 @@ s390_vary_chpid( __u8 chpid, int on) ...@@ -835,8 +837,9 @@ s390_vary_chpid( __u8 chpid, int on)
need_rescan = 1; need_rescan = 1;
} }
} }
out:
if (need_rescan || css_slow_subchannels_exist()) if (need_rescan || css_slow_subchannels_exist())
schedule_work(&varyonoff_work); queue_work(slow_path_wq, &slow_path_work);
return 0; return 0;
} }
......
/* /*
* drivers/s390/cio/cio.c * drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls * S/390 common I/O routines -- low level i/o calls
* $Revision: 1.121 $ * $Revision: 1.123 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -67,17 +67,17 @@ cio_debug_init (void) ...@@ -67,17 +67,17 @@ cio_debug_init (void)
if (!cio_debug_msg_id) if (!cio_debug_msg_id)
goto out_unregister; goto out_unregister;
debug_register_view (cio_debug_msg_id, &debug_sprintf_view); debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
debug_set_level (cio_debug_msg_id, 6); debug_set_level (cio_debug_msg_id, 2);
cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8); cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);
if (!cio_debug_trace_id) if (!cio_debug_trace_id)
goto out_unregister; goto out_unregister;
debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
debug_set_level (cio_debug_trace_id, 6); debug_set_level (cio_debug_trace_id, 2);
cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long)); cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long));
if (!cio_debug_crw_id) if (!cio_debug_crw_id)
goto out_unregister; goto out_unregister;
debug_register_view (cio_debug_crw_id, &debug_sprintf_view); debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
debug_set_level (cio_debug_crw_id, 6); debug_set_level (cio_debug_crw_id, 2);
pr_debug("debugging initialized\n"); pr_debug("debugging initialized\n");
return 0; return 0;
......
/* /*
* drivers/s390/cio/css.c * drivers/s390/cio/css.c
* driver for channel subsystem * driver for channel subsystem
* $Revision: 1.74 $ * $Revision: 1.77 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -166,10 +166,12 @@ css_get_subchannel_status(struct subchannel *sch, int schid) ...@@ -166,10 +166,12 @@ css_get_subchannel_status(struct subchannel *sch, int schid)
if (sch && sch->schib.pmcw.dnv && if (sch && sch->schib.pmcw.dnv &&
(schib.pmcw.dev != sch->schib.pmcw.dev)) (schib.pmcw.dev != sch->schib.pmcw.dev))
return CIO_REVALIDATE; return CIO_REVALIDATE;
if (sch && !sch->lpm)
return CIO_NO_PATH;
return CIO_OPER; return CIO_OPER;
} }
static inline int static int
css_evaluate_subchannel(int irq, int slow) css_evaluate_subchannel(int irq, int slow)
{ {
int event, ret, disc; int event, ret, disc;
...@@ -188,7 +190,11 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -188,7 +190,11 @@ css_evaluate_subchannel(int irq, int slow)
return -EAGAIN; /* Will be done on the slow path. */ return -EAGAIN; /* Will be done on the slow path. */
} }
event = css_get_subchannel_status(sch, irq); event = css_get_subchannel_status(sch, irq);
CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n",
irq, event, sch?(disc?"disconnected":"normal"):"unknown",
slow?"slow":"fast");
switch (event) { switch (event) {
case CIO_NO_PATH:
case CIO_GONE: case CIO_GONE:
if (!sch) { if (!sch) {
/* Never used this subchannel. Ignore. */ /* Never used this subchannel. Ignore. */
...@@ -196,7 +202,8 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -196,7 +202,8 @@ css_evaluate_subchannel(int irq, int slow)
break; break;
} }
if (sch->driver && sch->driver->notify && if (sch->driver && sch->driver->notify &&
sch->driver->notify(&sch->dev, CIO_GONE)) { sch->driver->notify(&sch->dev, event)) {
cio_disable_subchannel(sch);
device_set_disconnected(sch); device_set_disconnected(sch);
ret = 0; ret = 0;
break; break;
...@@ -205,6 +212,7 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -205,6 +212,7 @@ css_evaluate_subchannel(int irq, int slow)
* Unregister subchannel. * Unregister subchannel.
* The device will be killed automatically. * The device will be killed automatically.
*/ */
cio_disable_subchannel(sch);
device_unregister(&sch->dev); device_unregister(&sch->dev);
/* Reset intparm to zeroes. */ /* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0; sch->schib.pmcw.intparm = 0;
...@@ -266,23 +274,44 @@ css_rescan_devices(void) ...@@ -266,23 +274,44 @@ css_rescan_devices(void)
} }
} }
static void struct slow_subchannel {
css_evaluate_slow_subchannel(unsigned long schid) struct list_head slow_list;
{ unsigned long schid;
css_evaluate_subchannel(schid, 1); };
}
void static LIST_HEAD(slow_subchannels_head);
static spinlock_t slow_subchannel_lock = SPIN_LOCK_UNLOCKED;
static void
css_trigger_slow_path(void) css_trigger_slow_path(void)
{ {
CIO_TRACE_EVENT(4, "slowpath");
if (need_rescan) { if (need_rescan) {
need_rescan = 0; need_rescan = 0;
css_rescan_devices(); css_rescan_devices();
return; return;
} }
css_walk_subchannel_slow_list(css_evaluate_slow_subchannel);
spin_lock_irq(&slow_subchannel_lock);
while (!list_empty(&slow_subchannels_head)) {
struct slow_subchannel *slow_sch =
list_entry(slow_subchannels_head.next,
struct slow_subchannel, slow_list);
list_del_init(slow_subchannels_head.next);
spin_unlock_irq(&slow_subchannel_lock);
css_evaluate_subchannel(slow_sch->schid, 1);
spin_lock_irq(&slow_subchannel_lock);
kfree(slow_sch);
}
spin_unlock_irq(&slow_subchannel_lock);
} }
typedef void (*workfunc)(void *);
DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
struct workqueue_struct *slow_path_wq;
/* /*
* Rescan for new devices. FIXME: This is slow. * Rescan for new devices. FIXME: This is slow.
* This function is called when we have lost CRWs due to overflows and we have * This function is called when we have lost CRWs due to overflows and we have
...@@ -443,14 +472,6 @@ s390_root_dev_unregister(struct device *dev) ...@@ -443,14 +472,6 @@ s390_root_dev_unregister(struct device *dev)
device_unregister(dev); device_unregister(dev);
} }
struct slow_subchannel {
struct list_head slow_list;
unsigned long schid;
};
static LIST_HEAD(slow_subchannels_head);
static spinlock_t slow_subchannel_lock = SPIN_LOCK_UNLOCKED;
int int
css_enqueue_subchannel_slow(unsigned long schid) css_enqueue_subchannel_slow(unsigned long schid)
{ {
...@@ -484,25 +505,7 @@ css_clear_subchannel_slow_list(void) ...@@ -484,25 +505,7 @@ css_clear_subchannel_slow_list(void)
spin_unlock_irqrestore(&slow_subchannel_lock, flags); spin_unlock_irqrestore(&slow_subchannel_lock, flags);
} }
void
css_walk_subchannel_slow_list(void (*fn)(unsigned long))
{
unsigned long flags;
spin_lock_irqsave(&slow_subchannel_lock, flags);
while (!list_empty(&slow_subchannels_head)) {
struct slow_subchannel *slow_sch =
list_entry(slow_subchannels_head.next,
struct slow_subchannel, slow_list);
list_del_init(slow_subchannels_head.next);
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
fn(slow_sch->schid);
spin_lock_irqsave(&slow_subchannel_lock, flags);
kfree(slow_sch);
}
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
}
int int
css_slow_subchannels_exist(void) css_slow_subchannels_exist(void)
......
...@@ -136,7 +136,6 @@ void device_trigger_reprobe(struct subchannel *); ...@@ -136,7 +136,6 @@ void device_trigger_reprobe(struct subchannel *);
/* Helper functions for vary on/off. */ /* Helper functions for vary on/off. */
void device_set_waiting(struct subchannel *); void device_set_waiting(struct subchannel *);
void device_call_nopath_notify(struct subchannel *);
/* Helper functions to build lists for the slow path. */ /* Helper functions to build lists for the slow path. */
int css_enqueue_subchannel_slow(unsigned long schid); int css_enqueue_subchannel_slow(unsigned long schid);
...@@ -144,4 +143,7 @@ void css_walk_subchannel_slow_list(void (*fn)(unsigned long)); ...@@ -144,4 +143,7 @@ void css_walk_subchannel_slow_list(void (*fn)(unsigned long));
void css_clear_subchannel_slow_list(void); void css_clear_subchannel_slow_list(void);
int css_slow_subchannels_exist(void); int css_slow_subchannels_exist(void);
extern int need_rescan; extern int need_rescan;
extern struct workqueue_struct *slow_path_wq;
extern struct work_struct slow_path_work;
#endif #endif
/* /*
* drivers/s390/cio/device.c * drivers/s390/cio/device.c
* bus driver for ccw devices * bus driver for ccw devices
* $Revision: 1.117 $ * $Revision: 1.119 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -159,6 +159,11 @@ init_ccw_bus_type (void) ...@@ -159,6 +159,11 @@ init_ccw_bus_type (void)
ret = -ENOMEM; /* FIXME: better errno ? */ ret = -ENOMEM; /* FIXME: better errno ? */
goto out_err; goto out_err;
} }
slow_path_wq = create_singlethread_workqueue("kslowcrw");
if (!slow_path_wq) {
ret = -ENOMEM; /* FIXME: better errno ? */
goto out_err;
}
if ((ret = bus_register (&ccw_bus_type))) if ((ret = bus_register (&ccw_bus_type)))
goto out_err; goto out_err;
...@@ -174,6 +179,8 @@ init_ccw_bus_type (void) ...@@ -174,6 +179,8 @@ init_ccw_bus_type (void)
destroy_workqueue(ccw_device_work); destroy_workqueue(ccw_device_work);
if (ccw_device_notify_work) if (ccw_device_notify_work)
destroy_workqueue(ccw_device_notify_work); destroy_workqueue(ccw_device_notify_work);
if (slow_path_wq)
destroy_workqueue(slow_path_wq);
return ret; return ret;
} }
...@@ -646,8 +653,6 @@ ccw_device_call_sch_unregister(void *data) ...@@ -646,8 +653,6 @@ ccw_device_call_sch_unregister(void *data)
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
/* Check if device is registered. */
if (!list_empty(&sch->dev.node))
device_unregister(&sch->dev); device_unregister(&sch->dev);
/* Reset intparm to zeroes. */ /* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0; sch->schib.pmcw.intparm = 0;
...@@ -677,7 +682,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) ...@@ -677,7 +682,7 @@ io_subchannel_recog_done(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
INIT_WORK(&cdev->private->kick_work, INIT_WORK(&cdev->private->kick_work,
ccw_device_call_sch_unregister, (void *) cdev); ccw_device_call_sch_unregister, (void *) cdev);
queue_work(ccw_device_work, &cdev->private->kick_work); queue_work(slow_path_wq, &cdev->private->kick_work);
break; break;
case DEV_STATE_BOXED: case DEV_STATE_BOXED:
/* Device did not respond in time. */ /* Device did not respond in time. */
......
...@@ -458,20 +458,6 @@ ccw_device_nopath_notify(void *data) ...@@ -458,20 +458,6 @@ ccw_device_nopath_notify(void *data)
} }
} }
void
device_call_nopath_notify(struct subchannel *sch)
{
struct ccw_device *cdev;
if (!sch->dev.driver_data)
return;
cdev = sch->dev.driver_data;
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_nopath_notify, (void *)cdev);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
}
void void
ccw_device_verify_done(struct ccw_device *cdev, int err) ccw_device_verify_done(struct ccw_device *cdev, int err)
{ {
......
/* /*
* drivers/s390/cio/requestirq.c * drivers/s390/cio/requestirq.c
* S/390 common I/O routines -- enabling and disabling of devices * S/390 common I/O routines -- enabling and disabling of devices
* $Revision: 1.45 $ * $Revision: 1.46 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -18,21 +18,6 @@ ...@@ -18,21 +18,6 @@
#include "css.h" #include "css.h"
/* for compatiblity only... */
int
request_irq (unsigned int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags, const char *devname, void *dev_id)
{
return -EINVAL;
}
/* for compatiblity only... */
void
free_irq (unsigned int irq, void *dev_id)
{
}
struct pgid global_pgid; struct pgid global_pgid;
EXPORT_SYMBOL_GPL(global_pgid); EXPORT_SYMBOL_GPL(global_pgid);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/workqueue.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
...@@ -21,13 +22,14 @@ ...@@ -21,13 +22,14 @@
// #define DBG(args,...) do {} while (0); // #define DBG(args,...) do {} while (0);
static struct semaphore m_sem; static struct semaphore m_sem;
static struct semaphore s_sem;
extern int css_process_crw(int); extern int css_process_crw(int);
extern int chsc_process_crw(void); extern int chsc_process_crw(void);
extern int chp_process_crw(int, int); extern int chp_process_crw(int, int);
extern void css_reiterate_subchannels(void); extern void css_reiterate_subchannels(void);
extern void css_trigger_slow_path(void);
extern struct workqueue_struct *slow_path_wq;
extern struct work_struct slow_path_work;
static void static void
s390_handle_damage(char *msg) s390_handle_damage(char *msg)
...@@ -39,21 +41,6 @@ s390_handle_damage(char *msg) ...@@ -39,21 +41,6 @@ s390_handle_damage(char *msg)
disabled_wait((unsigned long) __builtin_return_address(0)); disabled_wait((unsigned long) __builtin_return_address(0));
} }
static int
s390_mchk_slow_path(void *param)
{
struct semaphore *sem;
sem = (struct semaphore *)param;
/* Set a nice name. */
daemonize("kslowcrw");
repeat:
down_interruptible(sem);
css_trigger_slow_path();
goto repeat;
return 0;
}
/* /*
* Retrieve CRWs and call function to handle event. * Retrieve CRWs and call function to handle event.
* *
...@@ -130,7 +117,7 @@ s390_collect_crw_info(void *param) ...@@ -130,7 +117,7 @@ s390_collect_crw_info(void *param)
} }
} }
if (slow) if (slow)
up(&s_sem); queue_work(slow_path_wq, &slow_path_work);
goto repeat; goto repeat;
return 0; return 0;
} }
...@@ -202,7 +189,6 @@ static int ...@@ -202,7 +189,6 @@ static int
machine_check_init(void) machine_check_init(void)
{ {
init_MUTEX_LOCKED(&m_sem); init_MUTEX_LOCKED(&m_sem);
init_MUTEX_LOCKED( &s_sem );
ctl_clear_bit(14, 25); /* disable damage MCH */ ctl_clear_bit(14, 25); /* disable damage MCH */
ctl_set_bit(14, 26); /* enable degradation MCH */ ctl_set_bit(14, 26); /* enable degradation MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */
...@@ -226,7 +212,6 @@ static int __init ...@@ -226,7 +212,6 @@ static int __init
machine_check_crw_init (void) machine_check_crw_init (void)
{ {
kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES); kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES);
kernel_thread(s390_mchk_slow_path, &s_sem, CLONE_FS|CLONE_FILES);
ctl_set_bit(14, 28); /* enable channel report MCH */ ctl_set_bit(14, 28); /* enable channel report MCH */
return 0; return 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