mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] s390 (4/6): common i/o layer.
@ 2003-07-17 16:38 Martin Schwidefsky
  0 siblings, 0 replies; only message in thread
From: Martin Schwidefsky @ 2003-07-17 16:38 UTC (permalink / raw)
  To: linux-kernel, torvalds

 - Fix two memory leaks.
 - Clear pending status in cio_enable_subchannel.
 - Don't call device_unregister from interrupt context.
 - Fix refcounting problems on static device structures for the ccw console.
 - Delete timeouts for qdio after successful startup.

diffstat:
 drivers/s390/cio/chsc.c       |   10 +++---
 drivers/s390/cio/cio.c        |    7 +++-
 drivers/s390/cio/device.c     |   66 ++++++++++++++++++++++++++++++------------
 drivers/s390/cio/device.h     |    2 +
 drivers/s390/cio/device_fsm.c |   12 +++++--
 drivers/s390/cio/qdio.c       |   48 +++++++++---------------------
 6 files changed, 85 insertions(+), 60 deletions(-)

diff -urN linux-2.6.0-test1/drivers/s390/cio/chsc.c linux-2.6.0-s390/drivers/s390/cio/chsc.c
--- linux-2.6.0-test1/drivers/s390/cio/chsc.c	Mon Jul 14 05:34:40 2003
+++ linux-2.6.0-s390/drivers/s390/cio/chsc.c	Thu Jul 17 17:27:33 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.73 $
+ *   $Revision: 1.74 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -206,6 +206,7 @@
 	if (!page)
 		return -ENOMEM;
 
+	err = 0;
 	for (irq = 0; irq <= highest_subchannel; irq++) {
 		/*
 		 * retrieve information for each sch
@@ -222,13 +223,14 @@
 				       "not work\n", err);
 				cio_chsc_err_msg = 1;
 			}
-			return err;
+			goto out;
 		}
 		clear_page(page);
 	}
 	cio_chsc_desc_avail = 1;
+out:
 	free_page((unsigned long)page);
-	return 0;
+	return err;
 }
 
 __initcall(chsc_get_sch_descriptions);
@@ -428,7 +430,7 @@
 			ret = css_probe_device(irq);
 			if (ret == -ENXIO)
 				/* We're through */
-				return;
+				break;
 			continue;
 		}
 	
diff -urN linux-2.6.0-test1/drivers/s390/cio/cio.c linux-2.6.0-s390/drivers/s390/cio/cio.c
--- linux-2.6.0-test1/drivers/s390/cio/cio.c	Thu Jul 17 17:27:30 2003
+++ linux-2.6.0-s390/drivers/s390/cio/cio.c	Thu Jul 17 17:27:33 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.98 $
+ *   $Revision: 1.100 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -444,6 +444,11 @@
 			if (sch->schib.pmcw.ena)
 				break;
 		}
+		if (ret == -EBUSY) {
+			struct irb irb;
+			if (tsch(sch->irq, &irb) != 0)
+				break;
+		}
 	}
 	sprintf (dbf_txt, "ret:%d", ret);
 	CIO_TRACE_EVENT (2, dbf_txt);
diff -urN linux-2.6.0-test1/drivers/s390/cio/device.c linux-2.6.0-s390/drivers/s390/cio/device.c
--- linux-2.6.0-test1/drivers/s390/cio/device.c	Mon Jul 14 05:36:42 2003
+++ linux-2.6.0-s390/drivers/s390/cio/device.c	Thu Jul 17 17:27:33 2003
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.58 $
+ *   $Revision: 1.60 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -434,6 +434,13 @@
 	return ret;
 }
 
+void
+ccw_device_unregister(void *data)
+{
+	device_unregister((struct device *)data);
+}
+	
+
 static void
 ccw_device_release(struct device *dev)
 {
@@ -513,17 +520,11 @@
 		wake_up(&ccw_device_init_wq);
 }
 
-static void
+static int
 io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
 {
 	int rc;
 
-	if (!get_device(&sch->dev)) {
-		if (cdev->dev.release)
-			cdev->dev.release(&cdev->dev);
-		return;
-	}
-
 	sch->dev.driver_data = cdev;
 	sch->driver = &io_subchannel_driver;
 	cdev->ccwlock = &sch->lock;
@@ -540,9 +541,6 @@
 	snprintf (cdev->dev.bus_id, DEVICE_ID_SIZE, "0:%04x",
 		  sch->schib.pmcw.dev);
 
-	/* Do first half of device_register. */
-	device_initialize(&cdev->dev);
-
 	/* Increase counter of devices currently in recognition. */
 	atomic_inc(&ccw_device_init_count);
 
@@ -551,13 +549,10 @@
 	rc = ccw_device_recognition(cdev);
 	spin_unlock_irq(cdev->ccwlock);
 	if (rc) {
-		sch->dev.driver_data = 0;
-		put_device(&sch->dev);
-		if (cdev->dev.release)
-			cdev->dev.release(&cdev->dev);
 		if (atomic_dec_and_test(&ccw_device_init_count))
 			wake_up(&ccw_device_init_wq);
 	}
+	return rc;
 }
 
 static int
@@ -565,6 +560,7 @@
 {
 	struct subchannel *sch;
 	struct ccw_device *cdev;
+	int rc;
 
 	sch = to_subchannel(pdev);
 	if (sch->dev.driver_data) {
@@ -573,8 +569,20 @@
 		 * Register it and exit. This happens for all early
 		 * device, e.g. the console.
 		 */
-		ccw_device_register(sch->dev.driver_data);
+		cdev = sch->dev.driver_data;
+		device_initialize(&cdev->dev);
+		ccw_device_register(cdev);
 		subchannel_add_files(&sch->dev);
+		/*
+		 * Check if the device is already online. If it is
+		 * the reference count needs to be corrected
+		 * (see ccw_device_online and css_init_done for the
+		 * ugly details).
+		 */
+		if (cdev->private->state != DEV_STATE_NOT_OPER &&
+		    cdev->private->state != DEV_STATE_OFFLINE &&
+		    cdev->private->state != DEV_STATE_BOXED)
+			get_device(&cdev->dev);
 		return 0;
 	}
 	cdev  = kmalloc (sizeof(*cdev), GFP_KERNEL);
@@ -592,7 +600,23 @@
 		.parent = pdev,
 		.release = ccw_device_release,
 	};
-	io_subchannel_recog(cdev, to_subchannel(pdev));
+	/* Do first half of device_register. */
+	device_initialize(&cdev->dev);
+
+	if (!get_device(&sch->dev)) {
+		if (cdev->dev.release)
+			cdev->dev.release(&cdev->dev);
+		return 0;
+	}
+
+	rc = io_subchannel_recog(cdev, to_subchannel(pdev));
+	if (rc) {
+		sch->dev.driver_data = 0;
+		put_device(&sch->dev);
+		if (cdev->dev.release)
+			cdev->dev.release(&cdev->dev);
+	}
+
 	return 0;
 }
 
@@ -604,6 +628,8 @@
 static int
 ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
 {
+	int rc;
+
 	/* Initialize the ccw_device structure. */
 	cdev->dev = (struct device) {
 		.parent = &sch->dev,
@@ -613,7 +639,11 @@
 		.parent = &css_bus_device,
 		.bus	= &css_bus_type,
 	};
-	io_subchannel_recog(cdev, sch);
+
+	rc = io_subchannel_recog(cdev, sch);
+	if (rc)
+		return rc;
+
 	/* Now wait for the async. recognition to come to an end. */
 	while (!dev_fsm_final_state(cdev))
 		wait_cons_dev();
diff -urN linux-2.6.0-test1/drivers/s390/cio/device.h linux-2.6.0-s390/drivers/s390/cio/device.h
--- linux-2.6.0-test1/drivers/s390/cio/device.h	Mon Jul 14 05:37:13 2003
+++ linux-2.6.0-s390/drivers/s390/cio/device.h	Thu Jul 17 17:27:33 2003
@@ -65,6 +65,8 @@
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
+void ccw_device_unregister(void *);
+
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
diff -urN linux-2.6.0-test1/drivers/s390/cio/device_fsm.c linux-2.6.0-s390/drivers/s390/cio/device_fsm.c
--- linux-2.6.0-test1/drivers/s390/cio/device_fsm.c	Mon Jul 14 05:34:32 2003
+++ linux-2.6.0-s390/drivers/s390/cio/device_fsm.c	Thu Jul 17 17:27:33 2003
@@ -188,7 +188,7 @@
 
 	wake_up(&cdev->private->wait_q);
 
-	if (state != DEV_STATE_ONLINE)
+	if (css_init_done && state != DEV_STATE_ONLINE)
 		put_device (&cdev->dev);
 }
 
@@ -293,7 +293,7 @@
 	if (cdev->private->state != DEV_STATE_OFFLINE)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	if (!get_device(&cdev->dev))
+	if (css_init_done && !get_device(&cdev->dev))
 		return -ENODEV;
 	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0) {
 		/* Couldn't enable the subchannel for i/o. Sick device. */
@@ -384,7 +384,9 @@
 ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
 {
 	cdev->private->state = DEV_STATE_NOT_OPER;
-	device_unregister(&cdev->dev);
+	INIT_WORK(&cdev->private->kick_work,
+		  ccw_device_unregister, (void *) &cdev->dev);
+	queue_work(ccw_device_work, &cdev->private->kick_work);
 	wake_up(&cdev->private->wait_q);
 }
 
@@ -403,8 +405,10 @@
 		// FIXME: not-oper indication to device driver ?
 		ccw_device_call_handler(cdev);
 	}
+	INIT_WORK(&cdev->private->kick_work,
+		  ccw_device_unregister, (void *) &cdev->dev);
+	queue_work(ccw_device_work, &cdev->private->kick_work);
 	wake_up(&cdev->private->wait_q);
-	device_unregister(&cdev->dev);
 }
 
 /*
diff -urN linux-2.6.0-test1/drivers/s390/cio/qdio.c linux-2.6.0-s390/drivers/s390/cio/qdio.c
--- linux-2.6.0-test1/drivers/s390/cio/qdio.c	Mon Jul 14 05:35:14 2003
+++ linux-2.6.0-s390/drivers/s390/cio/qdio.c	Thu Jul 17 17:27:33 2003
@@ -55,7 +55,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.51 $"
+#define VERSION_QDIO_C "$Revision: 1.55 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -1643,6 +1643,7 @@
 	default:
 		BUG();
 	}
+	ccw_device_set_timeout(cdev, 0);
 	wake_up(&cdev->private->wait_q);
 
 }
@@ -1891,26 +1892,25 @@
 		result=-EIO;
 		goto exit;
 	}
-	/* 4: request block
-	 * 2: general char
-	 * 512: chsc char */
-	if ((scsc_area->general_char[1] & 0x00800000) != 0x00800000) {
+	/* Check for bit 41. */
+	if ((scsc_area->general_char[1] & 0x00400000) != 0x00400000) {
 		QDIO_PRINT_WARN("Adapter interruption facility not " \
 				"installed.\n");
 		result=-ENOENT;
 		goto exit;
 	}
-	if ((scsc_area->chsc_char[2] & 0x00180000) != 0x00180000) {
+	/* Check for bits 107 and 108. */
+	if ((scsc_area->chsc_char[3] & 0x00180000) != 0x00180000) {
 		QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \
 				"not available.\n");
 		result=-ENOENT;
 		goto exit;
 	}
 
-	/* Check for hydra thin interrupts. */
+	/* Check for hydra thin interrupts (bit 67). */
 	hydra_thinints = ((scsc_area->general_char[2] & 0x10000000)
 		== 0x10000000);
-	sprintf(dbf_text,"hydra_ti%1x", hydra_thinints);
+	sprintf(dbf_text,"hydrati%1x", hydra_thinints);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 exit:
 	free_page ((unsigned long) scsc_area);
@@ -2413,8 +2413,10 @@
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 	QDIO_DBF_TEXT0(0,trace,dbf_text);
 
-	if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat))
+	if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) {
+		ccw_device_set_timeout(cdev, 0);
 		return;
+	}
 
 	irq_ptr = cdev->private->qdio_data;
 
@@ -2439,7 +2441,7 @@
 	qdio_initialize_set_siga_flags_output(irq_ptr);
 
 	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
-
+	ccw_device_set_timeout(cdev, 0);
 }
 
 int
@@ -2698,6 +2700,8 @@
                            "returned %i, next try returned %i\n",
                            irq_ptr->irq,result,result2);
 		result=result2;
+		if (result)
+			ccw_device_set_timeout(cdev, 0);
 	}
 
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags);
@@ -3000,7 +3004,6 @@
 			int buffer_length, int *eof, void *data)
 {
         int c=0;
-	int irq;
 
         /* we are always called with buffer_length=4k, so we all
            deliver on the first read */
@@ -3020,7 +3023,7 @@
 		 perf_stats.siga_ins);
 	_OUTP_IT("Number of SIGA out's issued                     : %u\n",
 		 perf_stats.siga_outs);
-	_OUTP_IT("Number of PCIs caught                          : %u\n",
+	_OUTP_IT("Number of PCIs caught                           : %u\n",
 		 perf_stats.pcis);
 	_OUTP_IT("Number of adapter interrupts caught             : %u\n",
 		 perf_stats.thinints);
@@ -3037,27 +3040,6 @@
 		 perf_stats.outbound_cnt);
 	_OUTP_IT("\n");
 
-	/* 
-	 * FIXME: Rather use driver_for_each_dev, if we had it. 
-	 * I know this loop destroys our layering, but at least gets the 
-	 * performance stats out...
-	 */
-	for (irq=0;irq <= highest_subchannel; irq++) {
-		struct qdio_irq *irq_ptr;
-		struct ccw_device *cdev;
-
-		if (!ioinfo[irq])
-			continue;
-		cdev = ioinfo[irq]->dev.driver_data;
-		if (!cdev)
-			continue;
-		irq_ptr = cdev->private->qdio_data;
-		if (!irq_ptr)
-			continue;
-		_OUTP_IT("Polling time on irq %4x                        " \
-			 ": %u\n",
-			 irq_ptr->irq,irq_ptr->input_qs[0]->timing.threshold);
-	}
         return c;
 }
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-07-17 16:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-17 16:38 [PATCH] s390 (4/6): common i/o layer Martin Schwidefsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®