patch-2.2.16 linux/drivers/s390/char/hwc_rw.c
Next file: linux/drivers/s390/char/hwc_rw.h
Previous file: linux/drivers/s390/char/hwc_con.c
Back to the patch index
Back to the overall index
- Lines: 487
- Date:
Wed Jun 7 14:26:43 2000
- Orig file:
v2.2.15/linux/drivers/s390/char/hwc_rw.c
- Orig date:
Wed May 3 17:16:43 2000
diff -urN v2.2.15/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
@@ -26,6 +26,7 @@
#include <asm/bitops.h>
#include <asm/setup.h>
#include <asm/page.h>
+#include <asm/s390_ext.h>
#ifndef MIN
#define MIN(a,b) ((a<b) ? a : b)
@@ -121,7 +122,10 @@
#define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
#define HWC_TIMER_RUNS 1
-#define FLUSH_HWCBS 2
+#define HWC_FLUSH 2
+#define HWC_INIT 4
+#define HWC_BROKEN 8
+#define HWC_INTERRUPT 16
static struct {
@@ -166,6 +170,8 @@
unsigned char flags;
+ hwc_high_level_calls_t *calls;
+
spinlock_t lock;
struct timer_list write_timer;
@@ -206,20 +212,25 @@
0,
0,
0,
- 0
+ 0,
+ NULL
};
+static unsigned long cr0 __attribute__ ((aligned (8)));
+static unsigned long cr0_save __attribute__ ((aligned (8)));
+static unsigned char psw_mask __attribute__ ((aligned (8)));
+
#define DELAYED_WRITE 0
#define IMMEDIATE_WRITE 1
-static signed int do_hwc_write(int from_user, const unsigned char *,
+static signed int do_hwc_write (int from_user, unsigned char *,
unsigned int,
unsigned char,
unsigned char);
static asmlinkage int
-internal_print (char write_time, const char *fmt,...)
+internal_print (char write_time, char *fmt,...)
{
va_list args;
int i;
@@ -573,7 +584,7 @@
if (page >= hwc_data.kmem_start &&
page < hwc_data.kmem_end) {
- memset((void *) page, 0, PAGE_SIZE);
+/* memset((void *) page, 0, PAGE_SIZE); */
page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
clear_bit(page_nr, &hwc_data.kmem_pages);
@@ -693,7 +704,7 @@
release_write_hwcb();
- hwc_data.flags &= ~FLUSH_HWCBS;
+ hwc_data.flags &= ~HWC_FLUSH;
}
static int
@@ -701,17 +712,28 @@
{
write_hwcb_t *hwcb;
int retval;
+
+#ifdef DUMP_HWC_WRITE_ERROR
unsigned char *param;
param = ext_int_param();
- if (param != hwc_data.current_hwcb)
+ if (param != hwc_data.current_hwcb) {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "write_event_mask_2 : "
+ "HWCB address does not fit "
+ "(expected: 0x%x, got: 0x%x).\n",
+ hwc_data.current_hwcb,
+ param);
return -EINVAL;
+ }
+#endif
hwcb = (write_hwcb_t *) OUT_HWCB;
-#ifdef DUMP_HWC_WRITE_ERROR
-#if 0
- if (((unsigned char *) hwcb) != param)
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+ if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
__asm__("LHI 1,0xe22\n\t"
"LRA 2,0(0,%0)\n\t"
"LRA 3,0(0,%1)\n\t"
@@ -722,33 +744,13 @@
:"a"(OUT_HWCB),
"a"(hwc_data.current_hwcb),
"a"(BUF_HWCB),
- "a"(param)
+ "a" (hwcb)
:"1", "2", "3", "4", "5");
+ }
#endif
- if (hwcb->response_code != 0x0020)
-#if 0
- internal_print(DELAYED_WRITE, HWC_RW_PRINT_HEADER
- "\n************************ error in write_event_data_2()\n"
- "OUT_HWCB: 0x%x\n"
- "BUF_HWCB: 0x%x\n"
- "response_code: 0x%x\n"
- "hwc_data.hwcb_count: %d\n"
- "hwc_data.kmem_pages: 0x%x\n"
- "hwc_data.ioctls.kmem_hwcb: %d\n"
- "hwc_data.ioctls.max_hwcb: %d\n"
- "hwc_data.kmem_start: 0x%x\n"
- "hwc_data.kmem_end: 0x%x\n"
- "*****************************************************\n",
- OUT_HWCB,
- BUF_HWCB,
- hwcb->response_code,
- hwc_data.hwcb_count,
- hwc_data.kmem_pages,
- hwc_data.ioctls.kmem_hwcb,
- hwc_data.ioctls.max_hwcb,
- hwc_data.kmem_start,
- hwc_data.kmem_end);
-#endif
+
+#ifdef DUMP_HWC_WRITE_ERROR
+ if (hwcb->response_code != 0x0020) {
__asm__("LHI 1,0xe21\n\t"
"LRA 2,0(0,%0)\n\t"
"LRA 3,0(0,%1)\n\t"
@@ -761,19 +763,30 @@
"a"(BUF_HWCB),
"a"(&(hwc_data.hwcb_count))
:"1", "2", "3", "4", "5");
+ }
#endif
if (hwcb->response_code == 0x0020) {
retval = OUT_HWCB_CHAR;
release_write_hwcb();
- } else
+ } else {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "write_event_data_2 : "
+ "failed operation "
+ "(response code: 0x%x "
+ "HWCB address: 0x%x).\n",
+ hwcb->response_code,
+ hwcb);
retval = -EIO;
+ }
hwc_data.current_servc = 0;
hwc_data.current_hwcb = NULL;
- if (hwc_data.flags & FLUSH_HWCBS)
+ if (hwc_data.flags & HWC_FLUSH)
flush_hwcbs();
return retval;
@@ -860,7 +873,7 @@
static int
do_hwc_write (
int from_user,
- const unsigned char *msg,
+ unsigned char *msg,
unsigned int count,
unsigned char code,
unsigned char write_time)
@@ -891,7 +904,7 @@
else
orig_ch = msg[i_msg];
if (code == CODE_EBCDIC)
- ch = _ebcasc[orig_ch];
+ ch = (MACHINE_IS_VM ? _ebcasc[orig_ch] : _ebcasc_500[orig_ch]);
else
ch = orig_ch;
@@ -980,7 +993,10 @@
hwc_data.obuf[hwc_data.obuf_start +
obuf_cursor++]
= (code == CODE_ASCII) ?
- _ascebc[orig_ch]:orig_ch;
+ (MACHINE_IS_VM ?
+ _ascebc[orig_ch] :
+ _ascebc_500[orig_ch]) :
+ orig_ch;
}
if (obuf_cursor > obuf_count)
obuf_count = obuf_cursor;
@@ -1042,7 +1058,8 @@
spin_lock_irqsave(&hwc_data.lock, flags);
- retval = do_hwc_write(from_user, msg, count, hwc_data.ioctls.code,
+ retval = do_hwc_write (from_user, (unsigned char *) msg,
+ count, hwc_data.ioctls.code,
IMMEDIATE_WRITE);
spin_unlock_irqrestore(&hwc_data.lock, flags);
@@ -1123,7 +1140,7 @@
if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
flush_hwcbs();
else
- hwc_data.flags |= FLUSH_HWCBS;
+ hwc_data.flags |= HWC_FLUSH;
}
if (flag & IN_WRITE_BUF) {
hwc_data.obuf_cursor = 0;
@@ -1302,10 +1319,15 @@
if (hwc_data.ioctls.echo)
do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
- if (hwc_data.ioctls.code == CODE_ASCII)
+ if (hwc_data.ioctls.code == CODE_ASCII) {
+ if (MACHINE_IS_VM)
EBCASC(start, count);
-
- store_hwc_input(start, count);
+ else
+ EBCASC_500 (start, count);
+ }
+ if (hwc_data.calls != NULL)
+ if (hwc_data.calls->move_input != NULL)
+ (hwc_data.calls->move_input) (start, count);
return count;
}
@@ -1550,6 +1572,13 @@
case 0x60F0 :
case 0x62F0 :
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: "
+ "got interrupt and tried to read input, "
+ "but nothing found (response code=0x%x).\n",
+ hwcb->response_code);
return 0;
case 0x0100 :
@@ -1623,13 +1652,11 @@
unsigned int condition_code;
int retval;
- memcpy(hwc_data.page, &init_hwcb_template, sizeof(init_hwcb_t));
-
condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page);
#ifdef DUMP_HWC_INIT_ERROR
- if (condition_code != HWC_COMMAND_INITIATED)
+ if (condition_code == HWC_NOT_OPERATIONAL)
__asm__("LHI 1,0xe10\n\t"
"L 2,0(0,%0)\n\t"
"LRA 3,0(0,%1)\n\t"
@@ -1667,12 +1694,18 @@
if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
hwc_data.write_prio = 1;
- if (hwcb->hwc_send_mask & ET_OpCmd_Mask)
+ if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
+ internal_print (DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "capable of receipt of commands\n");
hwc_data.read_nonprio = 1;
-
- if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask)
+ }
+ if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) {
+ internal_print (DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "capable of receipt of priority commands\n");
hwc_data.read_nonprio = 1;
-
+ }
if ((hwcb->response_code != 0x0020) ||
(!hwc_data.write_nonprio) ||
((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
@@ -1685,7 +1718,7 @@
:"a"(hwcb), "a"(&(hwcb->response_code))
:"1", "2", "3");
#else
- retval = -EIO
+ retval = -EIO;
#endif
hwc_data.current_servc = 0;
@@ -1771,9 +1804,56 @@
}
int
+do_hwc_init (void)
+{
+ int retval;
+
+ memcpy (hwc_data.page, &init_hwcb_template, sizeof (init_hwcb_t));
+
+ do {
+
+ retval = write_event_mask_1 ();
+
+ if (retval == -EBUSY) {
+
+ hwc_data.flags |= HWC_INIT;
+
+ asm volatile ("STCTL 0,0,%0":"=m" (cr0));
+ cr0_save = cr0;
+ cr0 |= 0x00000200;
+ cr0 &= 0xFFFFF3AC;
+ asm volatile ("LCTL 0,0,%0"::"m" (cr0):"memory");
+
+ asm volatile ("STOSM %0,0x01"
+ :"=m" (psw_mask)::"memory");
+
+ while (!(hwc_data.flags & HWC_INTERRUPT))
+ barrier ();
+
+ asm volatile ("STNSM %0,0xFE"
+ :"=m" (psw_mask)::"memory");
+
+ asm volatile ("LCTL 0,0,%0"
+ ::"m" (cr0_save):"memory");
+
+ hwc_data.flags &= ~HWC_INIT;
+ }
+ } while (retval == -EBUSY);
+
+ if (retval == -EIO) {
+ hwc_data.flags |= HWC_BROKEN;
+ printk (HWC_RW_PRINT_HEADER "HWC not operational\n");
+ }
+ return retval;
+}
+
+void do_hwc_interrupt (struct pt_regs *regs, __u16 code);
+
+int
hwc_init (unsigned long *kmem_start)
{
int retval;
+
#ifdef BUFFER_STRESS_TEST
init_hwcb_t *hwcb;
@@ -1781,17 +1861,11 @@
#endif
-#ifdef CONFIG_3215
- if (MACHINE_IS_VM)
- return kmem_start;
-#endif
+ if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
+ panic ("Couldn't request external interrupts 0x2401");
spin_lock_init(&hwc_data.lock);
- retval = write_event_mask_1();
- if (retval < 0)
- return retval;
-
#ifdef USE_VM_DETECTION
if (MACHINE_IS_VM) {
@@ -1813,6 +1887,8 @@
*kmem_start += hwc_data.ioctls.kmem_hwcb * PAGE_SIZE;
hwc_data.kmem_end = *kmem_start - 1;
+ retval = do_hwc_init ();
+
ctl_set_bit(0, 9);
#ifdef BUFFER_STRESS_TEST
@@ -1834,13 +1910,52 @@
#endif
- return retval;
+ return /*retval */ 0;
+}
+
+signed int
+hwc_register_calls (hwc_high_level_calls_t * calls)
+{
+ if (calls == NULL)
+ return -EINVAL;
+
+ if (hwc_data.calls != NULL)
+ return -EBUSY;
+
+ hwc_data.calls = calls;
+ return 0;
+}
+
+signed int
+hwc_unregister_calls (hwc_high_level_calls_t * calls)
+{
+ if (hwc_data.calls == NULL)
+ return -EINVAL;
+
+ if (calls != hwc_data.calls)
+ return -EINVAL;
+
+ hwc_data.calls = NULL;
+ return 0;
}
void
-do_hwc_interrupt (void)
+do_hwc_interrupt (struct pt_regs *regs, __u16 code)
{
+ if (hwc_data.flags & HWC_INIT) {
+
+ hwc_data.flags |= HWC_INTERRUPT;
+ } else if (hwc_data.flags & HWC_BROKEN) {
+
+ if (!do_hwc_init ()) {
+ hwc_data.flags &= ~HWC_BROKEN;
+ internal_print (DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "delayed HWC setup after"
+ " temporary breakdown\n");
+ }
+ } else {
spin_lock(&hwc_data.lock);
if (!hwc_data.current_servc) {
@@ -1869,10 +1984,34 @@
write_event_data_1();
}
+ if (hwc_data.calls != NULL)
+ if (hwc_data.calls->wake_up != NULL)
+ (hwc_data.calls->wake_up) ();
+ spin_unlock (&hwc_data.lock);
+ }
+}
- wake_up_hwc_tty();
+void
+hwc_unblank (void)
+{
+ spin_lock (&hwc_data.lock);
spin_unlock(&hwc_data.lock);
+
+ asm volatile ("STCTL 0,0,%0":"=m" (cr0));
+ cr0_save = cr0;
+ cr0 |= 0x00000200;
+ cr0 &= 0xFFFFF3AC;
+ asm volatile ("LCTL 0,0,%0"::"m" (cr0):"memory");
+
+ asm volatile ("STOSM %0,0x01":"=m" (psw_mask)::"memory");
+
+ while (ALL_HWCB_CHAR)
+ barrier ();
+
+ asm volatile ("STNSM %0,0xFE":"=m" (psw_mask)::"memory");
+
+ asm volatile ("LCTL 0,0,%0"::"m" (cr0_save):"memory");
}
int
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)