hwc_rw.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:48k
- /*
- * drivers/s390/char/hwc_rw.c
- * driver: reading from and writing to system console on S/390 via HWC
- *
- * S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *
- *
- *
- *
- *
- *
- */
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/ctype.h>
- #include <linux/mm.h>
- #include <linux/timer.h>
- #include <linux/bootmem.h>
- #include <linux/module.h>
- #include <asm/ebcdic.h>
- #include <asm/uaccess.h>
- #include <asm/types.h>
- #include <asm/bitops.h>
- #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
- extern void ctrl_alt_del (void);
- #define HWC_RW_PRINT_HEADER "hwc low level driver: "
- #define USE_VM_DETECTION
- #define DEFAULT_CASE_DELIMITER '%'
- #undef DUMP_HWC_INIT_ERROR
- #undef DUMP_HWC_WRITE_ERROR
- #undef DUMP_HWC_WRITE_LIST_ERROR
- #undef DUMP_HWC_READ_ERROR
- #undef DUMP_HWCB_INPUT
- #undef BUFFER_STRESS_TEST
- typedef struct {
- unsigned char *next;
- unsigned short int mto_char_sum;
- unsigned char mto_number;
- unsigned char times_lost;
- unsigned short int mto_number_lost;
- unsigned long int mto_char_sum_lost;
- } __attribute__ ((packed))
- hwcb_list_t;
- #define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))
- #define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))
- #define BUF_HWCB hwc_data.hwcb_list_tail
- #define OUT_HWCB hwc_data.hwcb_list_head
- #define ALL_HWCB_MTO hwc_data.mto_number
- #define ALL_HWCB_CHAR hwc_data.mto_char_sum
- #define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))
- #define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)
- #define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)
- #define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)
- #define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)
- #define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)
- #define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)
- #define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)
- #define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)
- #define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)
- #define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)
- #define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)
- #define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)
- #define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)
- #define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)
- #define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)
- #define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)
- #define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)
- #include "hwc.h"
- #define __HWC_RW_C__
- #include "hwc_rw.h"
- #undef __HWC_RW_C__
- static unsigned char _obuf[MAX_HWCB_ROOM];
- static unsigned char
- _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
- typedef unsigned long kmem_pages_t;
- #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
- #define HWC_WTIMER_RUNS 1
- #define HWC_FLUSH 2
- #define HWC_INIT 4
- #define HWC_BROKEN 8
- #define HWC_INTERRUPT 16
- #define HWC_PTIMER_RUNS 32
- static struct {
- hwc_ioctls_t ioctls;
- hwc_ioctls_t init_ioctls;
- unsigned char *hwcb_list_head;
- unsigned char *hwcb_list_tail;
- unsigned short int mto_number;
- unsigned int mto_char_sum;
- unsigned char hwcb_count;
- unsigned long kmem_start;
- unsigned long kmem_end;
- kmem_pages_t kmem_pages;
- unsigned char *obuf;
- unsigned short int obuf_cursor;
- unsigned short int obuf_count;
- unsigned short int obuf_start;
- unsigned char *page;
- u32 current_servc;
- unsigned char *current_hwcb;
- unsigned char write_nonprio:1;
- unsigned char write_prio:1;
- unsigned char read_nonprio:1;
- unsigned char read_prio:1;
- unsigned char read_statechange:1;
- unsigned char sig_quiesce:1;
- unsigned char flags;
- hwc_high_level_calls_t *calls;
- hwc_request_t *request;
- spinlock_t lock;
- struct timer_list write_timer;
- struct timer_list poll_timer;
- } hwc_data =
- {
- {
- },
- {
- 8,
- 0,
- 80,
- 1,
- MAX_KMEM_PAGES,
- MAX_KMEM_PAGES,
- 0,
- 0x6c
- },
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- _obuf,
- 0,
- 0,
- 0,
- _page,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL
- };
- static unsigned long cr0 __attribute__ ((aligned (8)));
- static unsigned long cr0_save __attribute__ ((aligned (8)));
- static unsigned char psw_mask __attribute__ ((aligned (8)));
- static ext_int_info_t ext_int_info_hwc;
- #define DELAYED_WRITE 0
- #define IMMEDIATE_WRITE 1
- static signed int do_hwc_write (int from_user, unsigned char *,
- unsigned int,
- unsigned char);
- unsigned char hwc_ip_buf[512];
- static asmlinkage int
- internal_print (char write_time, char *fmt,...)
- {
- va_list args;
- int i;
- va_start (args, fmt);
- i = vsprintf (hwc_ip_buf, fmt, args);
- va_end (args);
- return do_hwc_write (0, hwc_ip_buf, i, write_time);
- }
- int
- hwc_printk (const char *fmt,...)
- {
- va_list args;
- int i;
- unsigned long flags;
- int retval;
- spin_lock_irqsave (&hwc_data.lock, flags);
- i = vsprintf (hwc_ip_buf, fmt, args);
- va_end (args);
- retval = do_hwc_write (0, hwc_ip_buf, i, IMMEDIATE_WRITE);
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- return retval;
- }
- #ifdef DUMP_HWCB_INPUT
- static void
- dump_storage_area (unsigned char *area, unsigned short int count)
- {
- unsigned short int index;
- ioctl_nl_t old_final_nl;
- if (!area || !count)
- return;
- old_final_nl = hwc_data.ioctls.final_nl;
- hwc_data.ioctls.final_nl = 1;
- internal_print (DELAYED_WRITE, "n%8x ", area);
- for (index = 0; index < count; index++) {
- if (area[index] <= 0xF)
- internal_print (DELAYED_WRITE, "0%x", area[index]);
- else
- internal_print (DELAYED_WRITE, "%x", area[index]);
- if ((index & 0xF) == 0xF)
- internal_print (DELAYED_WRITE, "n%8x ",
- &area[index + 1]);
- else if ((index & 3) == 3)
- internal_print (DELAYED_WRITE, " ");
- }
- internal_print (IMMEDIATE_WRITE, "n");
- hwc_data.ioctls.final_nl = old_final_nl;
- }
- #endif
- static inline u32
- service_call (
- u32 hwc_command_word,
- unsigned char hwcb[])
- {
- unsigned int condition_code = 1;
- __asm__ __volatile__ ("L 1, 0(%0) nt"
- "LRA 2, 0(%1) nt"
- ".long 0xB2200012 nt"
- :
- :"a" (&hwc_command_word), "a" (hwcb)
- :"1", "2", "memory");
- __asm__ __volatile__ ("IPM %0 nt"
- "SRL %0, 28 nt"
- :"=r" (condition_code));
- return condition_code;
- }
- static inline unsigned long
- hwc_ext_int_param (void)
- {
- u32 param;
- __asm__ __volatile__ ("L %0,128nt"
- :"=r" (param));
- return (unsigned long) param;
- }
- static int
- prepare_write_hwcb (void)
- {
- write_hwcb_t *hwcb;
- if (!BUF_HWCB)
- return -ENOMEM;
- BUF_HWCB_MTO = 0;
- BUF_HWCB_CHAR = 0;
- hwcb = (write_hwcb_t *) BUF_HWCB;
- memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
- return 0;
- }
- static int
- sane_write_hwcb (void)
- {
- unsigned short int lost_msg;
- unsigned int lost_char;
- unsigned char lost_hwcb;
- unsigned char *bad_addr;
- unsigned long page;
- int page_nr;
- if (!OUT_HWCB)
- return -ENOMEM;
- if ((unsigned long) OUT_HWCB & 0xFFF) {
- bad_addr = OUT_HWCB;
- #ifdef DUMP_HWC_WRITE_LIST_ERROR
- __asm__ ("LHI 1,0xe30nt"
- "LRA 2,0(%0) nt"
- "J .+0 nt"
- :
- : "a" (bad_addr)
- : "1", "2");
- #endif
- hwc_data.kmem_pages = 0;
- if ((unsigned long) BUF_HWCB & 0xFFF) {
- lost_hwcb = hwc_data.hwcb_count;
- lost_msg = ALL_HWCB_MTO;
- lost_char = ALL_HWCB_CHAR;
- OUT_HWCB = NULL;
- BUF_HWCB = NULL;
- ALL_HWCB_MTO = 0;
- ALL_HWCB_CHAR = 0;
- hwc_data.hwcb_count = 0;
- } else {
- lost_hwcb = hwc_data.hwcb_count - 1;
- lost_msg = ALL_HWCB_MTO - BUF_HWCB_MTO;
- lost_char = ALL_HWCB_CHAR - BUF_HWCB_CHAR;
- OUT_HWCB = BUF_HWCB;
- ALL_HWCB_MTO = BUF_HWCB_MTO;
- ALL_HWCB_CHAR = BUF_HWCB_CHAR;
- hwc_data.hwcb_count = 1;
- page = (unsigned long) BUF_HWCB;
- if (page >= hwc_data.kmem_start &&
- page <= hwc_data.kmem_end) {
- page_nr = (int)
- ((page - hwc_data.kmem_start) >> 12);
- set_bit (page_nr, &hwc_data.kmem_pages);
- }
- }
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "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 long) bad_addr,
- lost_hwcb, lost_char, lost_msg,
- hwc_data.hwcb_count,
- ALL_HWCB_CHAR, ALL_HWCB_MTO);
- }
- return 0;
- }
- static int
- reuse_write_hwcb (void)
- {
- int retval;
- if (hwc_data.hwcb_count < 2)
- #ifdef DUMP_HWC_WRITE_LIST_ERROR
- __asm__ ("LHI 1,0xe31nt"
- "LRA 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "J .+0 nt"
- :
- : "a" (BUF_HWCB), "a" (OUT_HWCB)
- : "1", "2", "3");
- #else
- return -EPERM;
- #endif
- if (hwc_data.current_hwcb == OUT_HWCB) {
- if (hwc_data.hwcb_count > 2) {
- BUF_HWCB_NEXT = OUT_HWCB_NEXT;
- BUF_HWCB = OUT_HWCB_NEXT;
- OUT_HWCB_NEXT = BUF_HWCB_NEXT;
- BUF_HWCB_NEXT = NULL;
- }
- } else {
- BUF_HWCB_NEXT = OUT_HWCB;
- BUF_HWCB = OUT_HWCB;
- OUT_HWCB = OUT_HWCB_NEXT;
- BUF_HWCB_NEXT = NULL;
- }
- BUF_HWCB_TIMES_LOST += 1;
- BUF_HWCB_CHAR_LOST += BUF_HWCB_CHAR;
- BUF_HWCB_MTO_LOST += BUF_HWCB_MTO;
- ALL_HWCB_MTO -= BUF_HWCB_MTO;
- ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
- retval = prepare_write_hwcb ();
- if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "reached my own limit of "
- "allowed buffer space for output (%i HWCBs = %li "
- "bytes), skipped content of oldest HWCB %i time(s) "
- "(%i lines = %i characters)n",
- hwc_data.ioctls.max_hwcb,
- hwc_data.ioctls.max_hwcb * PAGE_SIZE,
- BUF_HWCB_TIMES_LOST,
- BUF_HWCB_MTO_LOST,
- BUF_HWCB_CHAR_LOST);
- else
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "page allocation failed, "
- "could not expand buffer for output (currently in "
- "use: %i HWCBs = %li bytes), skipped content of "
- "oldest HWCB %i time(s) (%i lines = %i characters)n",
- hwc_data.hwcb_count,
- hwc_data.hwcb_count * PAGE_SIZE,
- BUF_HWCB_TIMES_LOST,
- BUF_HWCB_MTO_LOST,
- BUF_HWCB_CHAR_LOST);
- return retval;
- }
- static int
- allocate_write_hwcb (void)
- {
- unsigned char *page;
- int page_nr;
- if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
- return -ENOMEM;
- page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);
- if (page_nr < hwc_data.ioctls.kmem_hwcb) {
- page = (unsigned char *)
- (hwc_data.kmem_start + (page_nr << 12));
- set_bit (page_nr, &hwc_data.kmem_pages);
- } else
- page = (unsigned char *) __get_free_page (GFP_ATOMIC | GFP_DMA);
- if (!page)
- return -ENOMEM;
- if (!OUT_HWCB)
- OUT_HWCB = page;
- else
- BUF_HWCB_NEXT = page;
- BUF_HWCB = page;
- BUF_HWCB_NEXT = NULL;
- hwc_data.hwcb_count++;
- prepare_write_hwcb ();
- BUF_HWCB_TIMES_LOST = 0;
- BUF_HWCB_MTO_LOST = 0;
- BUF_HWCB_CHAR_LOST = 0;
- #ifdef BUFFER_STRESS_TEST
- internal_print (
- DELAYED_WRITE,
- "*** " HWC_RW_PRINT_HEADER
- "page #%i at 0x%x for buffering allocated. ***n",
- hwc_data.hwcb_count, page);
- #endif
- return 0;
- }
- static int
- release_write_hwcb (void)
- {
- unsigned long page;
- int page_nr;
- if (!hwc_data.hwcb_count)
- return -ENODATA;
- if (hwc_data.hwcb_count == 1) {
- prepare_write_hwcb ();
- ALL_HWCB_CHAR = 0;
- ALL_HWCB_MTO = 0;
- BUF_HWCB_TIMES_LOST = 0;
- BUF_HWCB_MTO_LOST = 0;
- BUF_HWCB_CHAR_LOST = 0;
- } else {
- page = (unsigned long) OUT_HWCB;
- ALL_HWCB_MTO -= OUT_HWCB_MTO;
- ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
- hwc_data.hwcb_count--;
- OUT_HWCB = OUT_HWCB_NEXT;
- if (page >= hwc_data.kmem_start &&
- page <= hwc_data.kmem_end) {
- /*memset((void *) page, 0, PAGE_SIZE); */
- page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
- clear_bit (page_nr, &hwc_data.kmem_pages);
- } else
- free_page (page);
- #ifdef BUFFER_STRESS_TEST
- internal_print (
- DELAYED_WRITE,
- "*** " HWC_RW_PRINT_HEADER
- "page at 0x%x released, %i pages still in use ***n",
- page, hwc_data.hwcb_count);
- #endif
- }
- return 0;
- }
- static int
- add_mto (
- unsigned char *message,
- unsigned short int count)
- {
- unsigned short int mto_size;
- write_hwcb_t *hwcb;
- mto_t *mto;
- void *dest;
- if (!BUF_HWCB)
- return -ENOMEM;
- if (BUF_HWCB == hwc_data.current_hwcb)
- return -ENOMEM;
- mto_size = sizeof (mto_t) + count;
- hwcb = (write_hwcb_t *) BUF_HWCB;
- if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
- return -ENOMEM;
- mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
- memcpy (mto, &mto_template, sizeof (mto_t));
- dest = (void *) (((unsigned long) mto) + sizeof (mto_t));
- memcpy (dest, message, count);
- mto->length += count;
- hwcb->length += mto_size;
- hwcb->msgbuf.length += mto_size;
- hwcb->msgbuf.mdb.length += mto_size;
- BUF_HWCB_MTO++;
- ALL_HWCB_MTO++;
- BUF_HWCB_CHAR += count;
- ALL_HWCB_CHAR += count;
- return count;
- }
- static int write_event_data_1 (void);
- static void
- do_poll_hwc (unsigned long data)
- {
- unsigned long flags;
- spin_lock_irqsave (&hwc_data.lock, flags);
- write_event_data_1 ();
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- }
- void
- start_poll_hwc (void)
- {
- init_timer (&hwc_data.poll_timer);
- hwc_data.poll_timer.function = do_poll_hwc;
- hwc_data.poll_timer.data = (unsigned long) NULL;
- hwc_data.poll_timer.expires = jiffies + 2 * HZ;
- add_timer (&hwc_data.poll_timer);
- hwc_data.flags |= HWC_PTIMER_RUNS;
- }
- static int
- write_event_data_1 (void)
- {
- unsigned short int condition_code;
- int retval;
- write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
- if ((!hwc_data.write_prio) &&
- (!hwc_data.write_nonprio) &&
- hwc_data.read_statechange)
- return -EOPNOTSUPP;
- if (hwc_data.current_servc)
- return -EBUSY;
- retval = sane_write_hwcb ();
- if (retval < 0)
- return -EIO;
- if (!OUT_HWCB_MTO)
- return -ENODATA;
- if (!hwc_data.write_nonprio && hwc_data.write_prio)
- hwcb->msgbuf.type = ET_PMsgCmd;
- else
- hwcb->msgbuf.type = ET_Msg;
- condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
- #ifdef DUMP_HWC_WRITE_ERROR
- if (condition_code != HWC_COMMAND_INITIATED)
- __asm__ ("LHI 1,0xe20nt"
- "L 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "J .+0 nt"
- :
- : "a" (&condition_code), "a" (OUT_HWCB)
- : "1", "2", "3");
- #endif
- switch (condition_code) {
- case HWC_COMMAND_INITIATED:
- hwc_data.current_servc = HWC_CMDW_WRITEDATA;
- hwc_data.current_hwcb = OUT_HWCB;
- retval = condition_code;
- break;
- case HWC_BUSY:
- retval = -EBUSY;
- break;
- case HWC_NOT_OPERATIONAL:
- start_poll_hwc ();
- default:
- retval = -EIO;
- }
- return retval;
- }
- static void
- flush_hwcbs (void)
- {
- while (hwc_data.hwcb_count > 1)
- release_write_hwcb ();
- release_write_hwcb ();
- hwc_data.flags &= ~HWC_FLUSH;
- }
- static int
- write_event_data_2 (u32 ext_int_param)
- {
- write_hwcb_t *hwcb;
- int retval = 0;
- #ifdef DUMP_HWC_WRITE_ERROR
- 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_data_2 : "
- "HWCB address does not fit "
- "(expected: 0x%lx, got: 0x%lx).n",
- (unsigned long) hwc_data.current_hwcb,
- ext_int_param);
- return -EINVAL;
- }
- #endif
- hwcb = (write_hwcb_t *) OUT_HWCB;
- #ifdef DUMP_HWC_WRITE_LIST_ERROR
- if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
- __asm__ ("LHI 1,0xe22nt"
- "LRA 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "LRA 4,0(%2)nt"
- "LRA 5,0(%3)nt"
- "J .+0 nt"
- :
- : "a" (OUT_HWCB),
- "a" (hwc_data.current_hwcb),
- "a" (BUF_HWCB),
- "a" (hwcb)
- : "1", "2", "3", "4", "5");
- }
- #endif
- #ifdef DUMP_HWC_WRITE_ERROR
- if (hwcb->response_code != 0x0020) {
- __asm__ ("LHI 1,0xe21nt"
- "LRA 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "LRA 4,0(%2)nt"
- "LH 5,0(%3)nt"
- "SRL 5,8nt"
- "J .+0 nt"
- :
- : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
- "a" (BUF_HWCB),
- "a" (&(hwc_data.hwcb_count))
- : "1", "2", "3", "4", "5");
- }
- #endif
- switch (hwcb->response_code) {
- case 0x0020:
- retval = OUT_HWCB_CHAR;
- release_write_hwcb ();
- break;
- case 0x0040:
- case 0x0340:
- case 0x40F0:
- if (!hwc_data.read_statechange) {
- hwcb->response_code = 0;
- start_poll_hwc ();
- }
- retval = -EIO;
- break;
- default:
- 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;
- }
- if (retval == -EIO) {
- hwcb->control_mask[0] = 0;
- hwcb->control_mask[1] = 0;
- hwcb->control_mask[2] = 0;
- hwcb->response_code = 0;
- }
- hwc_data.current_servc = 0;
- hwc_data.current_hwcb = NULL;
- if (hwc_data.flags & HWC_FLUSH)
- flush_hwcbs ();
- return retval;
- }
- static void
- do_put_line (
- unsigned char *message,
- unsigned short count)
- {
- if (add_mto (message, count) != count) {
- if (allocate_write_hwcb () < 0)
- reuse_write_hwcb ();
- #ifdef DUMP_HWC_WRITE_LIST_ERROR
- if (add_mto (message, count) != count)
- __asm__ ("LHI 1,0xe32nt"
- "LRA 2,0(%0)nt"
- "L 3,0(%1)nt"
- "LRA 4,0(%2)nt"
- "LRA 5,0(%3)nt"
- "J .+0 nt"
- :
- : "a" (message), "a" (&hwc_data.kmem_pages),
- "a" (BUF_HWCB), "a" (OUT_HWCB)
- : "1", "2", "3", "4", "5");
- #else
- add_mto (message, count);
- #endif
- }
- }
- static void
- put_line (
- unsigned char *message,
- unsigned short count)
- {
- if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
- del_timer (&hwc_data.write_timer);
- hwc_data.flags &= ~HWC_WTIMER_RUNS;
- }
- hwc_data.obuf_start += count;
- do_put_line (message, count);
- hwc_data.obuf_start -= count;
- }
- static void
- set_alarm (void)
- {
- write_hwcb_t *hwcb;
- if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
- allocate_write_hwcb ();
- hwcb = (write_hwcb_t *) BUF_HWCB;
- hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
- }
- static void
- hwc_write_timeout (unsigned long data)
- {
- unsigned long flags;
- spin_lock_irqsave (&hwc_data.lock, flags);
- hwc_data.obuf_start = hwc_data.obuf_count;
- if (hwc_data.obuf_count)
- put_line (hwc_data.obuf, hwc_data.obuf_count);
- hwc_data.obuf_start = 0;
- hwc_data.obuf_cursor = 0;
- hwc_data.obuf_count = 0;
- write_event_data_1 ();
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- }
- static int
- do_hwc_write (
- int from_user,
- unsigned char *msg,
- unsigned int count,
- unsigned char write_time)
- {
- unsigned int i_msg = 0;
- unsigned short int spaces = 0;
- unsigned int processed_characters = 0;
- unsigned char ch;
- unsigned short int obuf_count;
- unsigned short int obuf_cursor;
- unsigned short int obuf_columns;
- if (hwc_data.obuf_start) {
- obuf_cursor = 0;
- obuf_count = 0;
- obuf_columns = MIN (hwc_data.ioctls.columns,
- MAX_MESSAGE_SIZE - hwc_data.obuf_start);
- } else {
- obuf_cursor = hwc_data.obuf_cursor;
- obuf_count = hwc_data.obuf_count;
- obuf_columns = hwc_data.ioctls.columns;
- }
- for (i_msg = 0; i_msg < count; i_msg++) {
- if (from_user)
- get_user (ch, msg + i_msg);
- else
- ch = msg[i_msg];
- processed_characters++;
- if ((obuf_cursor == obuf_columns) &&
- (ch != 'n') &&
- (ch != 't')) {
- put_line (&hwc_data.obuf[hwc_data.obuf_start],
- obuf_columns);
- obuf_cursor = 0;
- obuf_count = 0;
- }
- switch (ch) {
- case 'n':
- put_line (&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
- obuf_cursor = 0;
- obuf_count = 0;
- break;
- case 'a':
- hwc_data.obuf_start += obuf_count;
- set_alarm ();
- hwc_data.obuf_start -= obuf_count;
- break;
- case 't':
- do {
- if (obuf_cursor < obuf_columns) {
- hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor]
- = HWC_ASCEBC (' ');
- obuf_cursor++;
- } else
- break;
- } while (obuf_cursor % hwc_data.ioctls.width_htab);
- break;
- case 'f':
- case 'v':
- spaces = obuf_cursor;
- put_line (&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
- obuf_count = obuf_cursor;
- while (spaces) {
- hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor - spaces]
- = HWC_ASCEBC (' ');
- spaces--;
- }
- break;
- case 'b':
- if (obuf_cursor)
- obuf_cursor--;
- break;
- case 'r':
- obuf_cursor = 0;
- break;
- case 0x00:
- put_line (&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
- obuf_cursor = 0;
- obuf_count = 0;
- goto out;
- default:
- if (isprint (ch))
- hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor++]
- = HWC_ASCEBC (ch);
- }
- if (obuf_cursor > obuf_count)
- obuf_count = obuf_cursor;
- }
- if (obuf_cursor) {
- if (hwc_data.obuf_start ||
- (hwc_data.ioctls.final_nl == 0)) {
- put_line (&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
- obuf_cursor = 0;
- obuf_count = 0;
- } else {
- if (hwc_data.ioctls.final_nl > 0) {
- if (hwc_data.flags & HWC_WTIMER_RUNS) {
- mod_timer (&hwc_data.write_timer,
- jiffies + hwc_data.ioctls.final_nl * HZ / 10);
- } else {
- init_timer (&hwc_data.write_timer);
- hwc_data.write_timer.function =
- hwc_write_timeout;
- hwc_data.write_timer.data =
- (unsigned long) NULL;
- hwc_data.write_timer.expires =
- jiffies +
- hwc_data.ioctls.final_nl * HZ / 10;
- add_timer (&hwc_data.write_timer);
- hwc_data.flags |= HWC_WTIMER_RUNS;
- }
- } else;
- }
- } else;
- out:
- if (!hwc_data.obuf_start) {
- hwc_data.obuf_cursor = obuf_cursor;
- hwc_data.obuf_count = obuf_count;
- }
- if (write_time == IMMEDIATE_WRITE)
- write_event_data_1 ();
- return processed_characters;
- }
- signed int
- hwc_write (int from_user, const unsigned char *msg, unsigned int count)
- {
- unsigned long flags;
- int retval;
- spin_lock_irqsave (&hwc_data.lock, flags);
- retval = do_hwc_write (from_user, (unsigned char *) msg,
- count, IMMEDIATE_WRITE);
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- return retval;
- }
- unsigned int
- hwc_chars_in_buffer (unsigned char flag)
- {
- unsigned short int number = 0;
- unsigned long flags;
- spin_lock_irqsave (&hwc_data.lock, flags);
- if (flag & IN_HWCB)
- number += ALL_HWCB_CHAR;
- if (flag & IN_WRITE_BUF)
- number += hwc_data.obuf_cursor;
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- return number;
- }
- static inline int
- nr_setbits (kmem_pages_t arg)
- {
- int i;
- int nr = 0;
- for (i = 0; i < (sizeof (arg) << 3); i++) {
- if (arg & 1)
- nr++;
- arg >>= 1;
- }
- return nr;
- }
- unsigned int
- hwc_write_room (unsigned char flag)
- {
- unsigned int number = 0;
- unsigned long flags;
- write_hwcb_t *hwcb;
- spin_lock_irqsave (&hwc_data.lock, flags);
- if (flag & IN_HWCB) {
- if (BUF_HWCB) {
- hwcb = (write_hwcb_t *) BUF_HWCB;
- number += MAX_HWCB_ROOM - hwcb->length;
- }
- number += (hwc_data.ioctls.kmem_hwcb -
- nr_setbits (hwc_data.kmem_pages)) *
- (MAX_HWCB_ROOM -
- (sizeof (write_hwcb_t) + sizeof (mto_t)));
- }
- if (flag & IN_WRITE_BUF)
- number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- return number;
- }
- void
- hwc_flush_buffer (unsigned char flag)
- {
- unsigned long flags;
- spin_lock_irqsave (&hwc_data.lock, flags);
- if (flag & IN_HWCB) {
- if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
- flush_hwcbs ();
- else
- hwc_data.flags |= HWC_FLUSH;
- }
- if (flag & IN_WRITE_BUF) {
- hwc_data.obuf_cursor = 0;
- hwc_data.obuf_count = 0;
- }
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- }
- unsigned short int
- seperate_cases (unsigned char *buf, unsigned short int count)
- {
- unsigned short int i_in;
- unsigned short int i_out = 0;
- unsigned char _case = 0;
- for (i_in = 0; i_in < count; i_in++) {
- if (buf[i_in] == hwc_data.ioctls.delim) {
- if ((i_in + 1 < count) &&
- (buf[i_in + 1] == hwc_data.ioctls.delim)) {
- buf[i_out] = hwc_data.ioctls.delim;
- i_out++;
- i_in++;
- } else
- _case = ~_case;
- } else {
- if (_case) {
- if (hwc_data.ioctls.tolower)
- buf[i_out] = _ebc_toupper[buf[i_in]];
- else
- buf[i_out] = _ebc_tolower[buf[i_in]];
- } else
- buf[i_out] = buf[i_in];
- i_out++;
- }
- }
- return i_out;
- }
- #ifdef DUMP_HWCB_INPUT
- static int
- gds_vector_name (u16 id, unsigned char name[])
- {
- int retval = 0;
- switch (id) {
- case GDS_ID_MDSMU:
- name = "Multiple Domain Support Message Unit";
- break;
- case GDS_ID_MDSRouteInfo:
- name = "MDS Routing Information";
- break;
- case GDS_ID_AgUnWrkCorr:
- name = "Agent Unit of Work Correlator";
- break;
- case GDS_ID_SNACondReport:
- name = "SNA Condition Report";
- break;
- case GDS_ID_CPMSU:
- name = "CP Management Services Unit";
- break;
- case GDS_ID_RoutTargInstr:
- name = "Routing and Targeting Instructions";
- break;
- case GDS_ID_OpReq:
- name = "Operate Request";
- break;
- case GDS_ID_TextCmd:
- name = "Text Command";
- break;
- default:
- name = "unknown GDS variable";
- retval = -EINVAL;
- }
- return retval;
- }
- #endif
- inline static gds_vector_t *
- find_gds_vector (
- gds_vector_t * start, void *end, u16 id)
- {
- gds_vector_t *vec;
- gds_vector_t *retval = NULL;
- vec = start;
- while (((void *) vec) < end) {
- if (vec->gds_id == id) {
- #ifdef DUMP_HWCB_INPUT
- int retval_name;
- unsigned char name[64];
- retval_name = gds_vector_name (id, name);
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "%s at 0x%x up to 0x%x, length: %d",
- name,
- (unsigned long) vec,
- ((unsigned long) vec) + vec->length - 1,
- vec->length);
- if (retval_name < 0)
- internal_print (
- IMMEDIATE_WRITE,
- ", id: 0x%xn",
- vec->gds_id);
- else
- internal_print (
- IMMEDIATE_WRITE,
- "n");
- #endif
- retval = vec;
- break;
- }
- vec = (gds_vector_t *) (((unsigned long) vec) + vec->length);
- }
- return retval;
- }
- inline static gds_subvector_t *
- find_gds_subvector (
- gds_subvector_t * start, void *end, u8 key)
- {
- gds_subvector_t *subvec;
- gds_subvector_t *retval = NULL;
- subvec = start;
- while (((void *) subvec) < end) {
- if (subvec->key == key) {
- retval = subvec;
- break;
- }
- subvec = (gds_subvector_t *)
- (((unsigned long) subvec) + subvec->length);
- }
- return retval;
- }
- inline static int
- get_input (void *start, void *end)
- {
- int count;
- count = ((unsigned long) end) - ((unsigned long) start);
- if (hwc_data.ioctls.tolower)
- EBC_TOLOWER (start, count);
- if (hwc_data.ioctls.delim)
- count = seperate_cases (start, count);
- HWC_EBCASC_STR (start, count);
- if (hwc_data.ioctls.echo)
- do_hwc_write (0, start, count, IMMEDIATE_WRITE);
- if (hwc_data.calls != NULL)
- if (hwc_data.calls->move_input != NULL)
- (hwc_data.calls->move_input) (start, count);
- return count;
- }
- inline static int
- eval_selfdeftextmsg (gds_subvector_t * start, void *end)
- {
- gds_subvector_t *subvec;
- void *subvec_data;
- void *subvec_end;
- int retval = 0;
- subvec = start;
- while (((void *) subvec) < end) {
- subvec = find_gds_subvector (subvec, end, 0x30);
- if (!subvec)
- break;
- subvec_data = (void *)
- (((unsigned long) subvec) +
- sizeof (gds_subvector_t));
- subvec_end = (void *)
- (((unsigned long) subvec) + subvec->length);
- retval += get_input (subvec_data, subvec_end);
- subvec = (gds_subvector_t *) subvec_end;
- }
- return retval;
- }
- inline static int
- eval_textcmd (gds_subvector_t * start, void *end)
- {
- gds_subvector_t *subvec;
- gds_subvector_t *subvec_data;
- void *subvec_end;
- int retval = 0;
- subvec = start;
- while (((void *) subvec) < end) {
- subvec = find_gds_subvector (
- subvec, end, GDS_KEY_SelfDefTextMsg);
- if (!subvec)
- break;
- subvec_data = (gds_subvector_t *)
- (((unsigned long) subvec) +
- sizeof (gds_subvector_t));
- subvec_end = (void *)
- (((unsigned long) subvec) + subvec->length);
- retval += eval_selfdeftextmsg (subvec_data, subvec_end);
- subvec = (gds_subvector_t *) subvec_end;
- }
- return retval;
- }
- inline static int
- eval_cpmsu (gds_vector_t * start, void *end)
- {
- gds_vector_t *vec;
- gds_subvector_t *vec_data;
- void *vec_end;
- int retval = 0;
- vec = start;
- while (((void *) vec) < end) {
- vec = find_gds_vector (vec, end, GDS_ID_TextCmd);
- if (!vec)
- break;
- vec_data = (gds_subvector_t *)
- (((unsigned long) vec) + sizeof (gds_vector_t));
- vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval += eval_textcmd (vec_data, vec_end);
- vec = (gds_vector_t *) vec_end;
- }
- return retval;
- }
- inline static int
- eval_mdsmu (gds_vector_t * start, void *end)
- {
- gds_vector_t *vec;
- gds_vector_t *vec_data;
- void *vec_end;
- int retval = 0;
- vec = find_gds_vector (start, end, GDS_ID_CPMSU);
- if (vec) {
- vec_data = (gds_vector_t *)
- (((unsigned long) vec) + sizeof (gds_vector_t));
- vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval = eval_cpmsu (vec_data, vec_end);
- }
- return retval;
- }
- static int
- eval_evbuf (gds_vector_t * start, void *end)
- {
- gds_vector_t *vec;
- gds_vector_t *vec_data;
- void *vec_end;
- int retval = 0;
- vec = find_gds_vector (start, end, GDS_ID_MDSMU);
- if (vec) {
- vec_data = (gds_vector_t *)
- (((unsigned long) vec) + sizeof (gds_vector_t));
- vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval = eval_mdsmu (vec_data, vec_end);
- }
- return retval;
- }
- static inline int
- eval_hwc_receive_mask (_hwcb_mask_t mask)
- {
- hwc_data.write_nonprio
- = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
- hwc_data.write_prio
- = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
- if (hwc_data.write_prio || hwc_data.write_nonprio) {
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can write messagesn");
- return 0;
- } else {
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can not write messagesn");
- return -1;
- }
- }
- static inline int
- eval_hwc_send_mask (_hwcb_mask_t mask)
- {
- hwc_data.read_statechange
- = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
- if (hwc_data.read_statechange)
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can read state change notificationsn");
- else
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can not read state change notificationsn");
- hwc_data.sig_quiesce
- = ((mask & ET_SigQuiesce_Mask) == ET_SigQuiesce_Mask);
- if (hwc_data.sig_quiesce)
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can receive signal quiescen");
- else
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can not receive signal quiescen");
- hwc_data.read_nonprio
- = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
- if (hwc_data.read_nonprio)
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can read commandsn");
- hwc_data.read_prio
- = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
- if (hwc_data.read_prio)
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can read priority commandsn");
- if (hwc_data.read_prio || hwc_data.read_nonprio) {
- return 0;
- } else {
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "can not read commands from operatorn");
- return -1;
- }
- }
- static int
- eval_statechangebuf (statechangebuf_t * scbuf)
- {
- int retval = 0;
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "HWC state change detectedn");
- if (scbuf->validity_hwc_active_facility_mask) {
- }
- if (scbuf->validity_hwc_receive_mask) {
- if (scbuf->mask_length != 4) {
- #ifdef DUMP_HWC_INIT_ERROR
- __asm__ ("LHI 1,0xe50nt"
- "LRA 2,0(%0)nt"
- "J .+0 nt"
- :
- : "a" (scbuf)
- : "1", "2");
- #endif
- } else {
- retval += eval_hwc_receive_mask
- (scbuf->hwc_receive_mask);
- }
- }
- if (scbuf->validity_hwc_send_mask) {
- if (scbuf->mask_length != 4) {
- #ifdef DUMP_HWC_INIT_ERROR
- __asm__ ("LHI 1,0xe51nt"
- "LRA 2,0(%0)nt"
- "J .+0 nt"
- :
- : "a" (scbuf)
- : "1", "2");
- #endif
- } else {
- retval += eval_hwc_send_mask
- (scbuf->hwc_send_mask);
- }
- }
- if (scbuf->validity_read_data_function_mask) {
- }
- return retval;
- }
- #ifdef CONFIG_SMP
- extern unsigned long cpu_online_map;
- static volatile unsigned long cpu_quiesce_map;
- static void
- do_load_quiesce_psw (void)
- {
- psw_t quiesce_psw;
- clear_bit (smp_processor_id (), &cpu_quiesce_map);
- if (smp_processor_id () == 0) {
- while (cpu_quiesce_map != 0) ;
- quiesce_psw.mask = _DW_PSW_MASK;
- quiesce_psw.addr = 0xfff;
- __load_psw (quiesce_psw);
- }
- signal_processor (smp_processor_id (), sigp_stop);
- }
- static void
- do_machine_quiesce (void)
- {
- cpu_quiesce_map = cpu_online_map;
- smp_call_function (do_load_quiesce_psw, NULL, 0, 0);
- do_load_quiesce_psw ();
- }
- #else
- static void
- do_machine_quiesce (void)
- {
- psw_t quiesce_psw;
- quiesce_psw.mask = _DW_PSW_MASK;
- queisce_psw.addr = 0xfff;
- __load_psw (quiesce_psw);
- }
- #endif
- static int
- process_evbufs (void *start, void *end)
- {
- int retval = 0;
- evbuf_t *evbuf;
- void *evbuf_end;
- gds_vector_t *evbuf_data;
- evbuf = (evbuf_t *) start;
- while (((void *) evbuf) < end) {
- evbuf_data = (gds_vector_t *)
- (((unsigned long) evbuf) + sizeof (evbuf_t));
- evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
- switch (evbuf->type) {
- case ET_OpCmd:
- case ET_CntlProgOpCmd:
- case ET_PMsgCmd:
- #ifdef DUMP_HWCB_INPUT
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "event buffer "
- "at 0x%x up to 0x%x, length: %dn",
- (unsigned long) evbuf,
- (unsigned long) (evbuf_end - 1),
- evbuf->length);
- dump_storage_area ((void *) evbuf, evbuf->length);
- #endif
- retval += eval_evbuf (evbuf_data, evbuf_end);
- break;
- case ET_StateChange:
- retval += eval_statechangebuf
- ((statechangebuf_t *) evbuf);
- break;
- case ET_SigQuiesce:
- _machine_restart = do_machine_quiesce;
- _machine_halt = do_machine_quiesce;
- _machine_power_off = do_machine_quiesce;
- ctrl_alt_del ();
- break;
- default:
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "unknown event buffer found, "
- "type 0x%x",
- evbuf->type);
- retval = -ENOSYS;
- }
- evbuf = (evbuf_t *) evbuf_end;
- }
- return retval;
- }
- static int
- unconditional_read_1 (void)
- {
- unsigned short int condition_code;
- read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
- int retval;
- #if 0
- if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
- return -EOPNOTSUPP;
- if (hwc_data.current_servc)
- return -EBUSY;
- #endif
- memset (hwcb, 0x00, PAGE_SIZE);
- memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
- condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page);
- #ifdef DUMP_HWC_READ_ERROR
- if (condition_code == HWC_NOT_OPERATIONAL)
- __asm__ ("LHI 1,0xe40nt"
- "L 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "J .+0 nt"
- :
- : "a" (&condition_code), "a" (hwc_data.page)
- : "1", "2", "3");
- #endif
- switch (condition_code) {
- case HWC_COMMAND_INITIATED:
- hwc_data.current_servc = HWC_CMDW_READDATA;
- hwc_data.current_hwcb = hwc_data.page;
- retval = condition_code;
- break;
- case HWC_BUSY:
- retval = -EBUSY;
- break;
- default:
- retval = -EIO;
- }
- return retval;
- }
- static int
- unconditional_read_2 (u32 ext_int_param)
- {
- read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
- #ifdef DUMP_HWC_READ_ERROR
- if ((hwcb->response_code != 0x0020) &&
- (hwcb->response_code != 0x0220) &&
- (hwcb->response_code != 0x60F0) &&
- (hwcb->response_code != 0x62F0))
- __asm__ ("LHI 1,0xe41nt"
- "LRA 2,0(%0)nt"
- "L 3,0(%1)nt"
- "J .+0nt"
- :
- : "a" (hwc_data.page), "a" (&(hwcb->response_code))
- : "1", "2", "3");
- #endif
- hwc_data.current_servc = 0;
- hwc_data.current_hwcb = NULL;
- switch (hwcb->response_code) {
- case 0x0020:
- case 0x0220:
- return process_evbufs (
- (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)),
- (void *) (((unsigned long) hwcb) + hwcb->length));
- 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:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: HWCB boundary violation - this "
- "must not occur in a correct driver, please contact "
- "authorn");
- return -EIO;
- case 0x0300:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "insufficient HWCB length - this must not occur in a "
- "correct driver, please contact authorn");
- return -EIO;
- case 0x01F0:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "invalid command - this must not occur in a correct "
- "driver, please contact authorn");
- return -EIO;
- case 0x40F0:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: invalid function coden");
- return -EIO;
- case 0x70F0:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: invalid selection maskn");
- return -EIO;
- case 0x0040:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: HWC equipment checkn");
- return -EIO;
- default:
- internal_print (
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: invalid response code %x - this "
- "must not occur in a correct driver, please contact "
- "authorn",
- hwcb->response_code);
- return -EIO;
- }
- }
- static int
- write_event_mask_1 (void)
- {
- unsigned int condition_code;
- int retval;
- condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);
- #ifdef DUMP_HWC_INIT_ERROR
- if (condition_code == HWC_NOT_OPERATIONAL)
- __asm__ ("LHI 1,0xe10nt"
- "L 2,0(%0)nt"
- "LRA 3,0(%1)nt"
- "J .+0nt"
- :
- : "a" (&condition_code), "a" (hwc_data.page)
- : "1", "2", "3");
- #endif
- switch (condition_code) {
- case HWC_COMMAND_INITIATED:
- hwc_data.current_servc = HWC_CMDW_WRITEMASK;
- hwc_data.current_hwcb = hwc_data.page;
- retval = condition_code;
- break;
- case HWC_BUSY:
- retval = -EBUSY;
- break;
- default:
- retval = -EIO;
- }
- return retval;
- }
- static int
- write_event_mask_2 (u32 ext_int_param)
- {
- init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
- int retval = 0;
- if (hwcb->response_code != 0x0020) {
- #ifdef DUMP_HWC_INIT_ERROR
- __asm__ ("LHI 1,0xe11nt"
- "LRA 2,0(%0)nt"
- "L 3,0(%1)nt"
- "J .+0nt"
- :
- : "a" (hwcb), "a" (&(hwcb->response_code))
- : "1", "2", "3");
- #else
- retval = -1;
- #endif
- } else {
- if (hwcb->mask_length != 4) {
- #ifdef DUMP_HWC_INIT_ERROR
- __asm__ ("LHI 1,0xe52nt"
- "LRA 2,0(%0)nt"
- "J .+0 nt"
- :
- : "a" (hwcb)
- : "1", "2");
- #endif
- } else {
- retval += eval_hwc_receive_mask
- (hwcb->hwc_receive_mask);
- retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
- }
- }
- hwc_data.current_servc = 0;
- hwc_data.current_hwcb = NULL;
- return retval;
- }
- static int
- set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
- {
- int retval = 0;
- hwc_ioctls_t tmp;
- if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
- if (correct)
- tmp.width_htab = MAX_MESSAGE_SIZE;
- else
- retval = -EINVAL;
- } else
- tmp.width_htab = ioctls->width_htab;
- tmp.echo = ioctls->echo;
- if (ioctls->columns > MAX_MESSAGE_SIZE) {
- if (correct)
- tmp.columns = MAX_MESSAGE_SIZE;
- else
- retval = -EINVAL;
- } else
- tmp.columns = ioctls->columns;
- tmp.final_nl = ioctls->final_nl;
- if (ioctls->max_hwcb < 2) {
- if (correct)
- tmp.max_hwcb = 2;
- else
- retval = -EINVAL;
- } else
- tmp.max_hwcb = ioctls->max_hwcb;
- tmp.tolower = ioctls->tolower;
- if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
- if (correct)
- tmp.kmem_hwcb = ioctls->max_hwcb;
- else
- retval = -EINVAL;
- } else
- tmp.kmem_hwcb = ioctls->kmem_hwcb;
- if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
- if (correct)
- ioctls->kmem_hwcb = MAX_KMEM_PAGES;
- else
- retval = -EINVAL;
- }
- if (ioctls->kmem_hwcb < 2) {
- if (correct)
- ioctls->kmem_hwcb = 2;
- else
- retval = -EINVAL;
- }
- tmp.delim = ioctls->delim;
- if (!(retval < 0))
- hwc_data.ioctls = tmp;
- return retval;
- }
- 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;
- __ctl_store (cr0, 0, 0);
- cr0_save = cr0;
- cr0 |= 0x00000200;
- cr0 &= 0xFFFFF3AC;
- __ctl_load (cr0, 0, 0);
- 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");
- __ctl_load (cr0_save, 0, 0);
- hwc_data.flags &= ~HWC_INIT;
- }
- } while (retval == -EBUSY);
- if (retval == -EIO) {
- hwc_data.flags |= HWC_BROKEN;
- printk (HWC_RW_PRINT_HEADER "HWC not operationaln");
- }
- return retval;
- }
- void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
- int
- hwc_init (void)
- {
- int retval;
- #ifdef BUFFER_STRESS_TEST
- init_hwcb_t *hwcb;
- int i;
- #endif
- if (register_early_external_interrupt (0x2401, hwc_interrupt_handler,
- &ext_int_info_hwc) != 0)
- panic ("Couldn't request external interrupts 0x2401");
- spin_lock_init (&hwc_data.lock);
- #ifdef USE_VM_DETECTION
- if (MACHINE_IS_VM) {
- if (hwc_data.init_ioctls.columns > 76)
- hwc_data.init_ioctls.columns = 76;
- hwc_data.init_ioctls.tolower = 1;
- if (!hwc_data.init_ioctls.delim)
- hwc_data.init_ioctls.delim = DEFAULT_CASE_DELIMITER;
- } else {
- hwc_data.init_ioctls.tolower = 0;
- hwc_data.init_ioctls.delim = 0;
- }
- #endif
- retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
- hwc_data.kmem_start = (unsigned long)
- alloc_bootmem_low_pages (hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
- hwc_data.kmem_end = hwc_data.kmem_start +
- hwc_data.ioctls.kmem_hwcb * PAGE_SIZE - 1;
- retval = do_hwc_init ();
- ctl_set_bit (0, 9);
- #ifdef BUFFER_STRESS_TEST
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "use %i bytes for buffering.n",
- hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
- for (i = 0; i < 500; i++) {
- hwcb = (init_hwcb_t *) BUF_HWCB;
- internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "This is stress test message #%i, free: %i bytesn",
- i,
- MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t)));
- }
- #endif
- 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;
- }
- 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;
- }
- cc = service_call (req->word, req->block);
- switch (cc) {
- case 0:
- hwc_data.request = req;
- 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_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;
- }
- 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;
- if (hwc_data.flags & HWC_PTIMER_RUNS) {
- del_timer (&hwc_data.poll_timer);
- hwc_data.flags &= ~HWC_PTIMER_RUNS;
- }
- if (finished_hwcb) {
- 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 {
- 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 (evbuf_pending) {
- unconditional_read_1 ();
- } else {
- write_event_data_1 ();
- }
- if (!hwc_data.calls || !hwc_data.calls->wake_up)
- return;
- (hwc_data.calls->wake_up) ();
- }
- void
- hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
- {
- int cpu = smp_processor_id ();
- u32 ext_int_param = hwc_ext_int_param ();
- irq_enter (cpu, 0x2401);
- 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"
- " (ext. int. parameter=0x%x)n",
- ext_int_param);
- }
- } else {
- spin_lock (&hwc_data.lock);
- hwc_do_interrupt (ext_int_param);
- spin_unlock (&hwc_data.lock);
- }
- irq_exit (cpu, 0x2401);
- }
- void
- hwc_unblank (void)
- {
- spin_lock (&hwc_data.lock);
- spin_unlock (&hwc_data.lock);
- __ctl_store (cr0, 0, 0);
- cr0_save = cr0;
- cr0 |= 0x00000200;
- cr0 &= 0xFFFFF3AC;
- __ctl_load (cr0, 0, 0);
- asm volatile ("STOSM %0,0x01":"=m" (psw_mask)::"memory");
- while (ALL_HWCB_CHAR)
- barrier ();
- asm volatile ("STNSM %0,0xFE":"=m" (psw_mask)::"memory");
- __ctl_load (cr0_save, 0, 0);
- }
- int
- hwc_ioctl (unsigned int cmd, unsigned long arg)
- {
- hwc_ioctls_t tmp = hwc_data.ioctls;
- int retval = 0;
- unsigned long flags;
- unsigned int obuf;
- spin_lock_irqsave (&hwc_data.lock, flags);
- switch (cmd) {
- case TIOCHWCSHTAB:
- if (get_user (tmp.width_htab, (ioctl_htab_t *) arg))
- goto fault;
- break;
- case TIOCHWCSECHO:
- if (get_user (tmp.echo, (ioctl_echo_t *) arg))
- goto fault;
- break;
- case TIOCHWCSCOLS:
- if (get_user (tmp.columns, (ioctl_cols_t *) arg))
- goto fault;
- break;
- case TIOCHWCSNL:
- if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
- goto fault;
- break;
- case TIOCHWCSOBUF:
- if (get_user (obuf, (unsigned int *) arg))
- goto fault;
- if (obuf & 0xFFF)
- tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
- else
- tmp.max_hwcb = (obuf >> 12);
- break;
- case TIOCHWCSCASE:
- if (get_user (tmp.tolower, (ioctl_case_t *) arg))
- goto fault;
- break;
- case TIOCHWCSDELIM:
- if (get_user (tmp.delim, (ioctl_delim_t *) arg))
- goto fault;
- break;
- case TIOCHWCSINIT:
- retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
- break;
- case TIOCHWCGHTAB:
- if (put_user (tmp.width_htab, (ioctl_htab_t *) arg))
- goto fault;
- break;
- case TIOCHWCGECHO:
- if (put_user (tmp.echo, (ioctl_echo_t *) arg))
- goto fault;
- break;
- case TIOCHWCGCOLS:
- if (put_user (tmp.columns, (ioctl_cols_t *) arg))
- goto fault;
- break;
- case TIOCHWCGNL:
- if (put_user (tmp.final_nl, (ioctl_nl_t *) arg))
- goto fault;
- break;
- case TIOCHWCGOBUF:
- if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg))
- goto fault;
- break;
- case TIOCHWCGKBUF:
- if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
- goto fault;
- break;
- case TIOCHWCGCASE:
- if (put_user (tmp.tolower, (ioctl_case_t *) arg))
- goto fault;
- break;
- case TIOCHWCGDELIM:
- if (put_user (tmp.delim, (ioctl_delim_t *) arg))
- goto fault;
- break;
- #if 0
- case TIOCHWCGINIT:
- if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
- goto fault;
- break;
- case TIOCHWCGCURR:
- if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
- goto fault;
- break;
- #endif
- default:
- goto noioctlcmd;
- }
- if (_IOC_DIR (cmd) == _IOC_WRITE)
- retval = set_hwc_ioctls (&tmp, 0);
- goto out;
- fault:
- retval = -EFAULT;
- goto out;
- noioctlcmd:
- retval = -ENOIOCTLCMD;
- out:
- spin_unlock_irqrestore (&hwc_data.lock, flags);
- return retval;
- }