[PATCH] s390 fixes (9/12).
Martin Schwidefsky (schwidefsky@de.ibm.com)
Mon, 3 Feb 2003 20:47:39 +0100
update qdio driver
diff -urN linux-2.5.59/drivers/s390/cio/qdio.c linux-2.5.59-s390/drivers/s390/cio/qdio.c
--- linux-2.5.59/drivers/s390/cio/qdio.c	Fri Jan 17 03:22:19 2003
+++ linux-2.5.59-s390/drivers/s390/cio/qdio.c	Mon Feb  3 20:50:01 2003
@@ -55,7 +55,7 @@
 #include "qdio.h"
 #include "ioasm.h"
 
-#define VERSION_QDIO_C "$Revision: 1.18 $"
+#define VERSION_QDIO_C "$Revision: 1.23 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -752,7 +752,7 @@
 #endif /* QDIO_DBF_LIKE_HELL */
 
 	if (q->state==QDIO_IRQ_STATE_ACTIVE)
-		q->handler(q->irq,
+		q->handler(q->cdev,
 			   QDIO_STATUS_INBOUND_INT|q->error_status_flags,
 			   q->qdio_error,q->siga_error,q->q_no,start,count,
 			   q->int_parm);
@@ -1039,7 +1039,7 @@
 #endif /* QDIO_DBF_LIKE_HELL */
 
 	if (q->state==QDIO_IRQ_STATE_ACTIVE)
-		q->handler(q->irq,QDIO_STATUS_OUTBOUND_INT|
+		q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT|
 			   q->error_status_flags,
 			   q->qdio_error,q->siga_error,q->q_no,start,count,
 			   q->int_parm);
@@ -1283,7 +1283,8 @@
 }
 
 static int
-qdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs,
+qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
+	      int no_input_qs, int no_output_qs,
 	      qdio_handler_t *input_handler,
 	      qdio_handler_t *output_handler,
 	      unsigned long int_parm,int q_format,
@@ -1327,6 +1328,7 @@
 		q->int_parm=int_parm;
 		irq_ptr->input_qs[i]=q;
 		q->irq=irq_ptr->irq;
+		q->cdev = cdev;
 		q->mask=1<<(31-i);
 		q->q_no=i;
 		q->is_input_q=1;
@@ -1403,6 +1405,7 @@
 		irq_ptr->output_qs[i]=q;
 		q->is_input_q=0;
 		q->irq=irq_ptr->irq;
+		q->cdev = cdev;
 		q->mask=1<<(31-i);
 		q->q_no=i;
 		q->first_to_check=0;
@@ -1626,7 +1629,7 @@
 				       "device %s!?\n", cdev->dev.bus_id);
 			goto omit_handler_call;
 		}
-		q->handler(q->irq,QDIO_STATUS_ACTIVATE_CHECK_CONDITION|
+		q->handler(q->cdev,QDIO_STATUS_ACTIVATE_CHECK_CONDITION|
 			   QDIO_STATUS_LOOK_FOR_ERROR,
 			   0,0,0,-1,-1,q->int_parm);
 	omit_handler_call:
@@ -1882,6 +1885,27 @@
 qdio_cleanup(struct ccw_device *cdev, int how)
 {
 	struct qdio_irq *irq_ptr;
+	char dbf_text[15];
+	int rc;
+
+	irq_ptr = cdev->private->qdio_data;
+	if (!irq_ptr)
+		return -ENODEV;
+
+	sprintf(dbf_text,"qcln%4x",irq_ptr->irq);
+	QDIO_DBF_TEXT1(0,trace,dbf_text);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+
+	rc = qdio_shutdown(cdev, how);
+	if (rc == 0)
+		rc = qdio_free(cdev);
+	return rc;
+}
+
+int
+qdio_shutdown(struct ccw_device *cdev, int how)
+{
+	struct qdio_irq *irq_ptr;
 	int i,result;
 	unsigned long flags;
 	int timeout;
@@ -1891,7 +1915,7 @@
 	if (!irq_ptr)
 		return -ENODEV;
 
-	sprintf(dbf_text,"qcln%4x",irq_ptr->irq);
+	sprintf(dbf_text,"qsqs%4x",irq_ptr->irq);
 	QDIO_DBF_TEXT1(0,trace,dbf_text);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 
@@ -1923,6 +1947,9 @@
 			result=-EINPROGRESS;
 	}
 
+	if (result)
+		return result;
+
 	/* cleanup subchannel */
 	spin_lock_irqsave(get_ccwdev_lock(cdev),flags);
 	if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) {
@@ -1955,6 +1982,29 @@
 	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
 }
 
+int
+qdio_free(struct ccw_device *cdev)
+{
+	struct qdio_irq *irq_ptr;
+	char dbf_text[15];
+
+	irq_ptr = cdev->private->qdio_data;
+	if (!irq_ptr)
+		return -ENODEV;
+
+	sprintf(dbf_text,"qfqs%4x",irq_ptr->irq);
+	QDIO_DBF_TEXT1(0,trace,dbf_text);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+
+	if (cdev->private->state != DEV_STATE_ONLINE)
+		return -EINVAL;
+
+	qdio_cleanup_finish(irq_ptr);
+	cdev->private->qdio_data = 0;
+	qdio_release_irq_memory(irq_ptr);
+	return 0;
+}
+
 static void
 qdio_cleanup_handle_timeout(struct ccw_device *cdev)
 {
@@ -1967,14 +2017,10 @@
 	QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n",
 			irq_ptr->irq);
 
-	qdio_cleanup_finish(irq_ptr);
-
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags);
 
 	spin_unlock(&irq_ptr->setting_up_lock);
 
-	cdev->private->qdio_data = 0;
-	qdio_release_irq_memory(irq_ptr);
 	cdev->private->state = DEV_STATE_ONLINE;
 	wake_up(&cdev->private->wait_q);
 }
@@ -1984,10 +2030,6 @@
 			struct irb *irb)
 {
 	struct qdio_irq *irq_ptr;
-	int cstat,dstat;
-
-	cstat = irb->scsw.cstat;
-        dstat = irb->scsw.dstat;
 
 	if (intparm == 0)
 		QDIO_PRINT_WARN("Got unsolicited interrupt on cleanup "
@@ -1997,22 +2039,18 @@
 
 	qdio_irq_check_sense(irq_ptr->irq, irb);
 
-	qdio_cleanup_finish(irq_ptr);
-
 	spin_unlock(&irq_ptr->setting_up_lock);
 
-	cdev->private->qdio_data = 0;
-	qdio_release_irq_memory(irq_ptr);
 	cdev->private->state = DEV_STATE_ONLINE;
 	wake_up(&cdev->private->wait_q);
 }
 
 static inline void
-qdio_initialize_do_dbf(struct qdio_initialize *init_data)
+qdio_allocate_do_dbf(struct qdio_initialize *init_data)
 {
 	char dbf_text[20]; /* if a printf would print out more than 8 chars */
 
-	sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq);
+	sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 	QDIO_DBF_TEXT0(0,trace,dbf_text);
 	sprintf(dbf_text,"qfmt:%x",init_data->q_format);
@@ -2045,7 +2083,7 @@
 }
 
 static inline void
-qdio_initialize_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
+qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
 {
 	irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
 
@@ -2063,8 +2101,8 @@
 }
 
 static inline void
-qdio_initialize_fill_output_desc(struct qdio_irq *irq_ptr, int i, 
-				 int j, int iqfmt)
+qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
+			       int j, int iqfmt)
 {
 	irq_ptr->output_qs[i]->is_iqdio_q = iqfmt;
 
@@ -2093,7 +2131,7 @@
 		       irq_ptr->irq);
 	QDIO_DBF_TEXT2(1,setup,"eq:timeo");
 	spin_unlock(&irq_ptr->setting_up_lock);
-	qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
+	qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
 
 	up(&init_sema);
 }
@@ -2164,7 +2202,7 @@
 			       "device end: dstat=%02x, cstat=%02x\n",
 			       irq_ptr->irq, dstat, cstat);
 		spin_unlock(&irq_ptr->setting_up_lock);
-		qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
+		qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
 		up(&init_sema);
 		return 1;
 	}
@@ -2243,13 +2281,32 @@
 int
 qdio_initialize(struct qdio_initialize *init_data)
 {
+	int rc;
+	char dbf_text[15];
+
+	sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_TEXT0(0,trace,dbf_text);
+
+	rc = qdio_allocate(init_data);
+	if (rc == 0) {
+		rc = qdio_establish(init_data->cdev);
+		if (rc != 0)
+			qdio_free(init_data->cdev);
+	}
+
+	return rc;
+}
+
+
+int
+qdio_allocate(struct qdio_initialize *init_data)
+{
 	int i;
-	unsigned long saveflags;
 	struct qdio_irq *irq_ptr;
 	struct ciw *ciw;
-	int result,result2;
+	int result;
 	int is_iqdio;
-	char dbf_text[20]; /* if a printf would print out more than 8 chars */
 
 	down_interruptible(&init_sema);
 
@@ -2270,7 +2327,7 @@
 		goto out;
 	}
 
-	qdio_initialize_do_dbf(init_data);
+	qdio_allocate_do_dbf(init_data);
 
 	/* create irq */
 	irq_ptr=kmalloc(sizeof(struct qdio_irq),GFP_DMA);
@@ -2325,7 +2382,8 @@
 	irq_ptr->aqueue.cmd=DEFAULT_ACTIVATE_QS_CMD;
 	irq_ptr->aqueue.count=DEFAULT_ACTIVATE_QS_COUNT;
 
-	if (!qdio_alloc_qs(irq_ptr,init_data->no_input_qs,
+	if (!qdio_alloc_qs(irq_ptr, init_data->cdev,
+			   init_data->no_input_qs,
 			   init_data->no_output_qs,
 			   init_data->input_handler,
 			   init_data->output_handler,init_data->int_parm,
@@ -2383,12 +2441,12 @@
 	/* first input descriptors, then output descriptors */
 	is_iqdio = (init_data->q_format == QDIO_IQDIO_QFMT) ? 1 : 0;
 	for (i=0;i<init_data->no_input_qs;i++)
-		qdio_initialize_fill_input_desc(irq_ptr, i, is_iqdio);
+		qdio_allocate_fill_input_desc(irq_ptr, i, is_iqdio);
 
 	for (i=0;i<init_data->no_output_qs;i++)
-		qdio_initialize_fill_output_desc(irq_ptr, i,
-						 init_data->no_input_qs,
-						 is_iqdio);
+		qdio_allocate_fill_output_desc(irq_ptr, i,
+					       init_data->no_input_qs,
+					       is_iqdio);
 
 	/* qdr, qib, sls, slsbs, slibs, sbales filled. */
 
@@ -2423,7 +2481,8 @@
 			goto out2;
 		}
 		iqdio_set_delay_target(irq_ptr,IQDIO_DELAY_TARGET);
-	}
+	} else
+		result = 0;
 
 	/* Set callback functions. */
 	irq_ptr->cleanup_irq = qdio_cleanup_handle_irq;
@@ -2431,6 +2490,36 @@
 	irq_ptr->establish_irq = qdio_establish_handle_irq;
 	irq_ptr->establish_timeout = qdio_establish_handle_timeout;
 	irq_ptr->handler = qdio_handler;
+	
+out:
+	if (irq_ptr)
+		spin_unlock(&irq_ptr->setting_up_lock);
+out2:
+	up(&init_sema);
+
+	return result;
+}
+
+int
+qdio_establish(struct ccw_device *cdev)
+{
+	struct qdio_irq *irq_ptr;
+	unsigned long saveflags;
+	int result, result2;
+	char dbf_text[20];
+
+	irq_ptr = cdev->private->qdio_data;
+	if (!irq_ptr)
+		return -EINVAL;
+
+	if (cdev->private->state != DEV_STATE_ONLINE)
+		return -EINVAL;
+	
+	spin_lock(&irq_ptr->setting_up_lock);
+
+	sprintf(dbf_text,"qest%4x",cdev->private->irq);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_TEXT0(0,trace,dbf_text);
 
 	/* establish q */
 	irq_ptr->ccw.cmd_code=irq_ptr->equeue.cmd;
@@ -2438,14 +2527,14 @@
 	irq_ptr->ccw.count=irq_ptr->equeue.count;
 	irq_ptr->ccw.cda=QDIO_GET_ADDR(irq_ptr->qdr);
 
-	spin_lock_irqsave(get_ccwdev_lock(init_data->cdev),saveflags);
+	spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags);
 
-	ccw_device_set_timeout(init_data->cdev, QDIO_ESTABLISH_TIMEOUT);
-	ccw_device_set_options(init_data->cdev, 0);
-	result=ccw_device_start(init_data->cdev,&irq_ptr->ccw,
+	ccw_device_set_timeout(cdev, QDIO_ESTABLISH_TIMEOUT);
+	ccw_device_set_options(cdev, 0);
+	result=ccw_device_start(cdev,&irq_ptr->ccw,
 				QDIO_DOING_ESTABLISH,0,0);
 	if (result) {
-		result2=ccw_device_start(init_data->cdev,&irq_ptr->ccw,
+		result2=ccw_device_start(cdev,&irq_ptr->ccw,
 					 QDIO_DOING_ESTABLISH,0,0);
 		sprintf(dbf_text,"eq:io%4x",result);
 		QDIO_DBF_TEXT2(1,setup,dbf_text);
@@ -2459,28 +2548,26 @@
 		result=result2;
 	}
 	if (result == 0)
-		init_data->cdev->private->state = DEV_STATE_QDIO_INIT;
-	spin_unlock_irqrestore(get_ccwdev_lock(init_data->cdev),saveflags);
+		cdev->private->state = DEV_STATE_QDIO_INIT;
+	spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags);
 
 	if (result) {
 		spin_unlock(&irq_ptr->setting_up_lock);
-		qdio_cleanup(init_data->cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
-		goto out2;
+		qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
+		goto out;
 	}
 	
-	wait_event(init_data->cdev->private->wait_q,
-		   dev_fsm_final_state(init_data->cdev) ||
+	wait_event(cdev->private->wait_q,
+		   dev_fsm_final_state(cdev) ||
 		   (irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED));
 
-	if (init_data->cdev->private->state == DEV_STATE_QDIO_INIT)
-		return 0;
+	if (cdev->private->state == DEV_STATE_QDIO_INIT)
+		result = 0;
+	else 
+		result = -EIO;
 
-	result = -EIO;
- out:
-	if (irq_ptr)
-		spin_unlock(&irq_ptr->setting_up_lock);
- out2:
-	up(&init_sema);
+out:
+	spin_unlock(&irq_ptr->setting_up_lock);
 
 	return result;
 	
@@ -2564,6 +2651,8 @@
 		}
 	}
 
+	qdio_wait_nonbusy(QDIO_ACTIVATE_DELAY);
+
 	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ACTIVE);
 
  out:
@@ -3051,8 +3140,12 @@
 module_init(init_QDIO);
 module_exit(cleanup_QDIO);
 
+EXPORT_SYMBOL(qdio_allocate);
+EXPORT_SYMBOL(qdio_establish);
 EXPORT_SYMBOL(qdio_initialize);
 EXPORT_SYMBOL(qdio_activate);
 EXPORT_SYMBOL(do_QDIO);
+EXPORT_SYMBOL(qdio_shutdown);
+EXPORT_SYMBOL(qdio_free);
 EXPORT_SYMBOL(qdio_cleanup);
 EXPORT_SYMBOL(qdio_synchronize);
diff -urN linux-2.5.59/drivers/s390/cio/qdio.h linux-2.5.59-s390/drivers/s390/cio/qdio.h
--- linux-2.5.59/drivers/s390/cio/qdio.h	Fri Jan 17 03:21:44 2003
+++ linux-2.5.59-s390/drivers/s390/cio/qdio.h	Mon Feb  3 20:50:01 2003
@@ -1,7 +1,7 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.8 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.10 $"
 
 //#define QDIO_DBF_LIKE_HELL
 
@@ -48,6 +48,10 @@
 #define QDIO_STATS_CLASSES 2
 #define QDIO_STATS_COUNT_NEEDED 2*/
 
+#define QDIO_ACTIVATE_DELAY 5 /* according to brenton belmar and paul
+				 gioquindo it can take up to 5ms before
+				 queues are really active */
+
 #define QDIO_NO_USE_COUNT_TIME 10
 #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
 					  exiting without having use_count
@@ -579,6 +583,7 @@
 
 	int is_input_q;
 	int irq;
+	struct ccw_device *cdev;
 
 	unsigned int is_iqdio_q;
 
diff -urN linux-2.5.59/include/asm-s390/qdio.h linux-2.5.59-s390/include/asm-s390/qdio.h
--- linux-2.5.59/include/asm-s390/qdio.h	Fri Jan 17 03:21:42 2003
+++ linux-2.5.59-s390/include/asm-s390/qdio.h	Mon Feb  3 20:50:01 2003
@@ -50,11 +50,11 @@
 } __attribute__ ((packed,aligned(256)));
 
 
-/* params are: irq, status, qdio_error, siga_error,
+/* params are: ccw_device, status, qdio_error, siga_error,
    queue_number, first element processed, number of elements processed,
    int_parm */
-typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
-			    unsigned int,int,int,unsigned long);
+typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
+			    unsigned int,unsigned int,int,int,unsigned long);
 
 
 #define QDIO_STATUS_INBOUND_INT 0x01
@@ -100,6 +100,8 @@
 	void **output_sbal_addr_array; /* addr of n*128 void ptrs */
 };
 extern int qdio_initialize(struct qdio_initialize *init_data);
+extern int qdio_allocate(struct qdio_initialize *init_data);
+extern int qdio_establish(struct ccw_device *);
 
 extern int qdio_activate(struct ccw_device *,int flags);
 
@@ -127,6 +129,8 @@
 			    unsigned int queue_number);
 
 extern int qdio_cleanup(struct ccw_device*, int how);
+extern int qdio_shutdown(struct ccw_device*, int how);
+extern int qdio_free(struct ccw_device*);
 
 unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag,
 				  unsigned int queue_number,
diff -urN linux-2.5.59/include/asm-s390x/qdio.h linux-2.5.59-s390/include/asm-s390x/qdio.h
--- linux-2.5.59/include/asm-s390x/qdio.h	Fri Jan 17 03:22:09 2003
+++ linux-2.5.59-s390/include/asm-s390x/qdio.h	Mon Feb  3 20:50:01 2003
@@ -50,11 +50,11 @@
 } __attribute__ ((packed,aligned(256)));
 
 
-/* params are: irq, status, qdio_error, siga_error,
+/* params are: ccw_device, status, qdio_error, siga_error,
    queue_number, first element processed, number of elements processed,
    int_parm */
-typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
-			    unsigned int,int,int,unsigned long);
+typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
+			    unsigned int,unsigned int,int,int,unsigned long);
 
 
 #define QDIO_STATUS_INBOUND_INT 0x01
@@ -100,6 +100,8 @@
 	void **output_sbal_addr_array; /* addr of n*128 void ptrs */
 };
 extern int qdio_initialize(struct qdio_initialize *init_data);
+extern int qdio_allocate(struct qdio_initialize *init_data);
+extern int qdio_establish(struct ccw_device *);
 
 extern int qdio_activate(struct ccw_device *,int flags);
 
@@ -127,6 +129,8 @@
 			    unsigned int queue_number);
 
 extern int qdio_cleanup(struct ccw_device*, int how);
+extern int qdio_shutdown(struct ccw_device*, int how);
+extern int qdio_free(struct ccw_device*);
 
 unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag,
 				  unsigned int queue_number,
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/