patch-2.4.8 linux/drivers/s390/char/hwc_rw.c

Next file: linux/drivers/s390/char/hwc_rw.h
Previous file: linux/drivers/s390/char/hwc_cpi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  * 
  *
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
@@ -28,28 +29,25 @@
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/s390_ext.h>
+#include <asm/irq.h>
 
 #ifndef MIN
 #define MIN(a,b) (((a<b) ? a : b))
 #endif
 
-#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
-
-#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
-
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
 
 #define  DEFAULT_CASE_DELIMITER '%'
 
-#define DUMP_HWC_INIT_ERROR
+#undef DUMP_HWC_INIT_ERROR
 
-#define DUMP_HWC_WRITE_ERROR
+#undef DUMP_HWC_WRITE_ERROR
 
-#define DUMP_HWC_WRITE_LIST_ERROR
+#undef DUMP_HWC_WRITE_LIST_ERROR
 
-#define DUMP_HWC_READ_ERROR
+#undef DUMP_HWC_READ_ERROR
 
 #undef DUMP_HWCB_INPUT
 
@@ -179,6 +177,8 @@
 
 	hwc_high_level_calls_t *calls;
 
+	hwc_request_t *request;
+
 	spinlock_t lock;
 
 	struct timer_list write_timer;
@@ -222,6 +222,7 @@
 	    0,
 	    0,
 	    0,
+	    NULL,
 	    NULL
 
 };
@@ -327,15 +328,15 @@
 	return condition_code;
 }
 
-static inline unsigned char *
-ext_int_param (void)
+static inline unsigned long 
+hwc_ext_int_param (void)
 {
 	u32 param;
 
 	__asm__ __volatile__ ("L %0,128\n\t"
 			      :"=r" (param));
 
-	return ((unsigned char *) param);
+	return (unsigned long) param;
 }
 
 static int 
@@ -417,11 +418,11 @@
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-			"found invalid HWCB at address 0x%x. List corrupted. "
+		       "found invalid HWCB at address 0x%lx. List corrupted. "
 			   "Lost %i HWCBs with %i characters within up to %i "
 			   "messages. Saved %i HWCB with last %i characters i"
 				       "within up to %i messages.\n",
-				       (unsigned int) bad_addr,
+				       (unsigned long) bad_addr,
 				       lost_hwcb, lost_char, lost_msg,
 				       hwc_data.hwcb_count,
 				       ALL_HWCB_CHAR, ALL_HWCB_MTO);
@@ -747,24 +748,22 @@
 }
 
 static int 
-write_event_data_2 (void)
+write_event_data_2 (u32 ext_int_param)
 {
 	write_hwcb_t *hwcb;
 	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
-	unsigned char *param;
-
-	param = ext_int_param ();
-	if (param != hwc_data.current_hwcb) {
+	if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+	    != (unsigned long) hwc_data.current_hwcb) {
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-				       "write_event_mask_2 : "
+				       "write_event_data_2 : "
 				       "HWCB address does not fit "
-				       "(expected: 0x%x, got: 0x%x).\n",
-				       hwc_data.current_hwcb,
-				       param);
+				       "(expected: 0x%lx, got: 0x%lx).\n",
+				       (unsigned long) hwc_data.current_hwcb,
+				       ext_int_param);
 		return -EINVAL;
 	}
 #endif
@@ -1707,7 +1706,7 @@
 }
 
 static int 
-unconditional_read_2 (void)
+unconditional_read_2 (u32 ext_int_param)
 {
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 
@@ -1844,7 +1843,7 @@
 }
 
 static int 
-write_event_mask_2 (void)
+write_event_mask_2 (u32 ext_int_param)
 {
 	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
 	int retval = 0;
@@ -1991,7 +1990,7 @@
 	return retval;
 }
 
-void do_hwc_interrupt (struct pt_regs *regs, __u16 code);
+void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
 
 int 
 hwc_init (void)
@@ -2005,7 +2004,7 @@
 
 #endif
 
-	if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
+	if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
 	spin_lock_init (&hwc_data.lock);
@@ -2083,60 +2082,161 @@
 	return 0;
 }
 
+int 
+hwc_send (hwc_request_t * req)
+{
+	unsigned long flags;
+	int retval;
+	int cc;
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+	if (!req || !req->callback || !req->block) {
+		retval = -EINVAL;
+		goto unlock;
+	}
+	if (hwc_data.request) {
+		retval = -ENOTSUPP;
+		goto unlock;
+	}
+	hwc_data.request = req;
+	cc = service_call (req->word, req->block);
+	switch (cc) {
+	case 0:
+		hwc_data.current_servc = req->word;
+		hwc_data.current_hwcb = req->block;
+		retval = 0;
+		break;
+	case 2:
+		retval = -EBUSY;
+		break;
+	default:
+		retval = -ENOSYS;
+
+	}
+      unlock:
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+	return retval;
+}
+
+EXPORT_SYMBOL (hwc_send);
+
 void 
-do_hwc_interrupt (struct pt_regs *regs, __u16 code)
+do_hwc_callback (u32 ext_int_param)
 {
+	if (!hwc_data.request || !hwc_data.request->callback)
+		return;
+	if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+	    != (unsigned long) hwc_data.request->block)
+		return;
+	hwc_data.request->callback (hwc_data.request);
+	hwc_data.request = NULL;
+	hwc_data.current_hwcb = NULL;
+	hwc_data.current_servc = 0;
+}
 
-	if (hwc_data.flags & HWC_INIT) {
+void 
+hwc_do_interrupt (u32 ext_int_param)
+{
+	u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
+	u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
 
-		hwc_data.flags |= HWC_INTERRUPT;
-	} else if (hwc_data.flags & HWC_BROKEN) {
+	if (hwc_data.flags & HWC_PTIMER_RUNS) {
+		del_timer (&hwc_data.poll_timer);
+		hwc_data.flags &= ~HWC_PTIMER_RUNS;
+	}
+	if (finished_hwcb) {
 
-		if (!do_hwc_init ()) {
-			hwc_data.flags &= ~HWC_BROKEN;
-			internal_print (DELAYED_WRITE,
-					HWC_RW_PRINT_HEADER
-					"delayed HWC setup after"
-					" temporary breakdown\n");
+		if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "interrupt: mismatch: "
+					       "ext. int param. (0x%x) vs. "
+					       "current HWCB (0x%x)\n",
+					       ext_int_param,
+					       hwc_data.current_hwcb);
+		} else {
+			if (hwc_data.request) {
+
+				do_hwc_callback (ext_int_param);
+			} else {
+
+				switch (hwc_data.current_servc) {
+
+				case HWC_CMDW_WRITEMASK:
+
+					write_event_mask_2 (ext_int_param);
+					break;
+
+				case HWC_CMDW_WRITEDATA:
+
+					write_event_data_2 (ext_int_param);
+					break;
+
+				case HWC_CMDW_READDATA:
+
+					unconditional_read_2 (ext_int_param);
+					break;
+				default:
+				}
+			}
 		}
 	} else {
-		spin_lock (&hwc_data.lock);
 
-		if (hwc_data.flags & HWC_PTIMER_RUNS) {
-			del_timer (&hwc_data.poll_timer);
-			hwc_data.flags &= ~HWC_PTIMER_RUNS;
+		if (hwc_data.current_hwcb) {
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "interrupt: mismatch: "
+					       "ext. int. param. (0x%x) vs. "
+					       "current HWCB (0x%x)\n",
+					       ext_int_param,
+					       hwc_data.current_hwcb);
 		}
-		if (!hwc_data.current_servc) {
+	}
 
-			unconditional_read_1 ();
+	if (evbuf_pending) {
 
-		} else {
+		unconditional_read_1 ();
+	} else {
 
-			switch (hwc_data.current_servc) {
+		write_event_data_1 ();
+	}
 
-			case HWC_CMDW_WRITEMASK:
+	if (!hwc_data.calls || !hwc_data.calls->wake_up)
+		return;
+	(hwc_data.calls->wake_up) ();
+}
 
-				write_event_mask_2 ();
-				break;
+void 
+hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
+{
+	int cpu = smp_processor_id ();
 
-			case HWC_CMDW_WRITEDATA:
+	u32 ext_int_param = hwc_ext_int_param ();
 
-				write_event_data_2 ();
-				break;
+	irq_enter (cpu, 0x2401);
 
-			case HWC_CMDW_READDATA:
+	if (hwc_data.flags & HWC_INIT) {
 
-				unconditional_read_2 ();
-				break;
-			}
+		hwc_data.flags |= HWC_INTERRUPT;
+	} else if (hwc_data.flags & HWC_BROKEN) {
 
-			write_event_data_1 ();
+		if (!do_hwc_init ()) {
+			hwc_data.flags &= ~HWC_BROKEN;
+			internal_print (DELAYED_WRITE,
+					HWC_RW_PRINT_HEADER
+					"delayed HWC setup after"
+					" temporary breakdown"
+					" (ext. int. parameter=0x%x)\n",
+					ext_int_param);
 		}
-		if (hwc_data.calls != NULL)
-			if (hwc_data.calls->wake_up != NULL)
-				(hwc_data.calls->wake_up) ();
+	} else {
+		spin_lock (&hwc_data.lock);
+		hwc_do_interrupt (ext_int_param);
 		spin_unlock (&hwc_data.lock);
 	}
+	irq_exit (cpu, 0x2401);
 }
 
 void 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)