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
- Lines: 363
- Date:
Wed Jul 25 14:12:02 2001
- Orig file:
v2.4.7/linux/drivers/s390/char/hwc_rw.c
- Orig date:
Wed Apr 11 19:02:29 2001
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)