1 /*
2 * drivers/s390/char/hwc_rw.c
3 * driver: reading from and writing to system console on S/390 via HWC
4 *
5 * S390 version
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 *
9 *
10 *
11 *
12 *
13 *
14 */
15
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/ctype.h>
20 #include <linux/mm.h>
21 #include <linux/timer.h>
22 #include <linux/bootmem.h>
23 #include <linux/module.h>
24
25 #include <asm/ebcdic.h>
26 #include <asm/uaccess.h>
27 #include <asm/types.h>
28 #include <asm/bitops.h>
29 #include <asm/setup.h>
30 #include <asm/page.h>
31 #include <asm/s390_ext.h>
32 #include <asm/irq.h>
33
34 #ifndef MIN
35 #define MIN(a,b) (((a<b) ? a : b))
36 #endif
37
38 extern void ctrl_alt_del (void);
39
40 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
41
42 #define USE_VM_DETECTION
43
44 #define DEFAULT_CASE_DELIMITER '%'
45
46 #undef DUMP_HWC_INIT_ERROR
47
48 #undef DUMP_HWC_WRITE_ERROR
49
50 #undef DUMP_HWC_WRITE_LIST_ERROR
51
52 #undef DUMP_HWC_READ_ERROR
53
54 #undef DUMP_HWCB_INPUT
55
56 #undef BUFFER_STRESS_TEST
57
58 typedef struct {
59 unsigned char *next;
60 unsigned short int mto_char_sum;
61 unsigned char mto_number;
62 unsigned char times_lost;
63 unsigned short int mto_number_lost;
64 unsigned long int mto_char_sum_lost;
65 } __attribute__ ((packed))
66
67 hwcb_list_t;
68
69 #define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))
70
71 #define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))
72
73 #define BUF_HWCB hwc_data.hwcb_list_tail
74 #define OUT_HWCB hwc_data.hwcb_list_head
75 #define ALL_HWCB_MTO hwc_data.mto_number
76 #define ALL_HWCB_CHAR hwc_data.mto_char_sum
77
78 #define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))
79
80 #define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)
81
82 #define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)
83
84 #define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)
85
86 #define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)
87
88 #define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)
89
90 #define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)
91
92 #define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)
93
94 #define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)
95
96 #define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)
97
98 #define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)
99
100 #define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)
101
102 #define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)
103
104 #define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)
105
106 #define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)
107
108 #define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)
109
110 #define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)
111
112 #define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)
113
114 #include "hwc.h"
115
116 #define __HWC_RW_C__
117 #include "hwc_rw.h"
118 #undef __HWC_RW_C__
119
120 static unsigned char _obuf[MAX_HWCB_ROOM];
121
122 static unsigned char
123 _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
124
125 typedef unsigned long kmem_pages_t;
126
127 #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
128
129 #define HWC_WTIMER_RUNS 1
130 #define HWC_FLUSH 2
131 #define HWC_INIT 4
132 #define HWC_BROKEN 8
133 #define HWC_INTERRUPT 16
134 #define HWC_PTIMER_RUNS 32
135
136 static struct {
137
138 hwc_ioctls_t ioctls;
139
140 hwc_ioctls_t init_ioctls;
141
142 unsigned char *hwcb_list_head;
143
144 unsigned char *hwcb_list_tail;
145
146 unsigned short int mto_number;
147
148 unsigned int mto_char_sum;
149
150 unsigned char hwcb_count;
151
152 unsigned long kmem_start;
153
154 unsigned long kmem_end;
155
156 kmem_pages_t kmem_pages;
157
158 unsigned char *obuf;
159
160 unsigned short int obuf_cursor;
161
162 unsigned short int obuf_count;
163
164 unsigned short int obuf_start;
165
166 unsigned char *page;
167
168 u32 current_servc;
169
170 unsigned char *current_hwcb;
171
172 unsigned char write_nonprio:1;
173 unsigned char write_prio:1;
174 unsigned char read_nonprio:1;
175 unsigned char read_prio:1;
176 unsigned char read_statechange:1;
177 unsigned char sig_quiesce:1;
178
179 unsigned char flags;
180
181 hwc_high_level_calls_t *calls;
182
183 hwc_request_t *request;
184
185 spinlock_t lock;
186
187 struct timer_list write_timer;
188
189 struct timer_list poll_timer;
190 } hwc_data =
191 {
192 {
193 },
194 {
195 8,
196 0,
197 80,
198 1,
199 MAX_KMEM_PAGES,
200 MAX_KMEM_PAGES,
201
202 0,
203
204 0x6c
205
206 },
207 NULL,
208 NULL,
209 0,
210 0,
211 0,
212 0,
213 0,
214 0,
215 _obuf,
216 0,
217 0,
218 0,
219 _page,
220 0,
221 NULL,
222 0,
223 0,
224 0,
225 0,
226 0,
227 0,
228 0,
229 NULL,
230 NULL
231
232 };
233
234 static unsigned long cr0 __attribute__ ((aligned (8)));
235 static unsigned long cr0_save __attribute__ ((aligned (8)));
236 static unsigned char psw_mask __attribute__ ((aligned (8)));
237
238 static ext_int_info_t ext_int_info_hwc;
239
240 #define DELAYED_WRITE 0
241 #define IMMEDIATE_WRITE 1
242
243 static signed int do_hwc_write (int from_user, unsigned char *,
244 unsigned int,
245 unsigned char);
246
247 unsigned char hwc_ip_buf[512];
248
249 static asmlinkage int
internal_print(char write_time,char * fmt,...)250 internal_print (char write_time, char *fmt,...)
251 {
252 va_list args;
253 int i;
254
255 va_start (args, fmt);
256 i = vsprintf (hwc_ip_buf, fmt, args);
257 va_end (args);
258 return do_hwc_write (0, hwc_ip_buf, i, write_time);
259 }
260
261 int
hwc_printk(const char * fmt,...)262 hwc_printk (const char *fmt,...)
263 {
264 va_list args;
265 int i;
266 unsigned long flags;
267 int retval;
268
269 spin_lock_irqsave (&hwc_data.lock, flags);
270
271 i = vsprintf (hwc_ip_buf, fmt, args);
272 va_end (args);
273 retval = do_hwc_write (0, hwc_ip_buf, i, IMMEDIATE_WRITE);
274
275 spin_unlock_irqrestore (&hwc_data.lock, flags);
276
277 return retval;
278 }
279
280 #ifdef DUMP_HWCB_INPUT
281
282 static void
dump_storage_area(unsigned char * area,unsigned short int count)283 dump_storage_area (unsigned char *area, unsigned short int count)
284 {
285 unsigned short int index;
286 ioctl_nl_t old_final_nl;
287
288 if (!area || !count)
289 return;
290
291 old_final_nl = hwc_data.ioctls.final_nl;
292 hwc_data.ioctls.final_nl = 1;
293
294 internal_print (DELAYED_WRITE, "\n%8x ", area);
295
296 for (index = 0; index < count; index++) {
297
298 if (area[index] <= 0xF)
299 internal_print (DELAYED_WRITE, "0%x", area[index]);
300 else
301 internal_print (DELAYED_WRITE, "%x", area[index]);
302
303 if ((index & 0xF) == 0xF)
304 internal_print (DELAYED_WRITE, "\n%8x ",
305 &area[index + 1]);
306 else if ((index & 3) == 3)
307 internal_print (DELAYED_WRITE, " ");
308 }
309
310 internal_print (IMMEDIATE_WRITE, "\n");
311
312 hwc_data.ioctls.final_nl = old_final_nl;
313 }
314 #endif
315
316 static inline u32
service_call(u32 hwc_command_word,unsigned char hwcb[])317 service_call (
318 u32 hwc_command_word,
319 unsigned char hwcb[])
320 {
321 unsigned int condition_code = 1;
322
323 __asm__ __volatile__ ("L 1, 0(%0) \n\t"
324 "LRA 2, 0(%1) \n\t"
325 ".long 0xB2200012 \n\t"
326 :
327 :"a" (&hwc_command_word), "a" (hwcb)
328 :"1", "2", "memory");
329
330 __asm__ __volatile__ ("IPM %0 \n\t"
331 "SRL %0, 28 \n\t"
332 :"=r" (condition_code));
333
334 return condition_code;
335 }
336
337 static inline unsigned long
hwc_ext_int_param(void)338 hwc_ext_int_param (void)
339 {
340 u32 param;
341
342 __asm__ __volatile__ ("L %0,128\n\t"
343 :"=r" (param));
344
345 return (unsigned long) param;
346 }
347
348 static int
prepare_write_hwcb(void)349 prepare_write_hwcb (void)
350 {
351 write_hwcb_t *hwcb;
352
353 if (!BUF_HWCB)
354 return -ENOMEM;
355
356 BUF_HWCB_MTO = 0;
357 BUF_HWCB_CHAR = 0;
358
359 hwcb = (write_hwcb_t *) BUF_HWCB;
360
361 memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
362
363 return 0;
364 }
365
366 static int
sane_write_hwcb(void)367 sane_write_hwcb (void)
368 {
369 unsigned short int lost_msg;
370 unsigned int lost_char;
371 unsigned char lost_hwcb;
372 unsigned char *bad_addr;
373 unsigned long page;
374 int page_nr;
375
376 if (!OUT_HWCB)
377 return -ENOMEM;
378
379 if ((unsigned long) OUT_HWCB & 0xFFF) {
380
381 bad_addr = OUT_HWCB;
382
383 #ifdef DUMP_HWC_WRITE_LIST_ERROR
384 __asm__ ("LHI 1,0xe30\n\t"
385 "LRA 2,0(%0) \n\t"
386 "J .+0 \n\t"
387 :
388 : "a" (bad_addr)
389 : "1", "2");
390 #endif
391
392 hwc_data.kmem_pages = 0;
393 if ((unsigned long) BUF_HWCB & 0xFFF) {
394
395 lost_hwcb = hwc_data.hwcb_count;
396 lost_msg = ALL_HWCB_MTO;
397 lost_char = ALL_HWCB_CHAR;
398
399 OUT_HWCB = NULL;
400 BUF_HWCB = NULL;
401 ALL_HWCB_MTO = 0;
402 ALL_HWCB_CHAR = 0;
403 hwc_data.hwcb_count = 0;
404 } else {
405
406 lost_hwcb = hwc_data.hwcb_count - 1;
407 lost_msg = ALL_HWCB_MTO - BUF_HWCB_MTO;
408 lost_char = ALL_HWCB_CHAR - BUF_HWCB_CHAR;
409 OUT_HWCB = BUF_HWCB;
410 ALL_HWCB_MTO = BUF_HWCB_MTO;
411 ALL_HWCB_CHAR = BUF_HWCB_CHAR;
412 hwc_data.hwcb_count = 1;
413 page = (unsigned long) BUF_HWCB;
414
415 if (page >= hwc_data.kmem_start &&
416 page <= hwc_data.kmem_end) {
417
418 page_nr = (int)
419 ((page - hwc_data.kmem_start) >> 12);
420 set_bit (page_nr, &hwc_data.kmem_pages);
421 }
422 }
423
424 internal_print (
425 DELAYED_WRITE,
426 HWC_RW_PRINT_HEADER
427 "found invalid HWCB at address 0x%lx. List corrupted. "
428 "Lost %i HWCBs with %i characters within up to %i "
429 "messages. Saved %i HWCB with last %i characters i"
430 "within up to %i messages.\n",
431 (unsigned long) bad_addr,
432 lost_hwcb, lost_char, lost_msg,
433 hwc_data.hwcb_count,
434 ALL_HWCB_CHAR, ALL_HWCB_MTO);
435 }
436 return 0;
437 }
438
439 static int
reuse_write_hwcb(void)440 reuse_write_hwcb (void)
441 {
442 int retval;
443
444 if (hwc_data.hwcb_count < 2)
445 #ifdef DUMP_HWC_WRITE_LIST_ERROR
446 __asm__ ("LHI 1,0xe31\n\t"
447 "LRA 2,0(%0)\n\t"
448 "LRA 3,0(%1)\n\t"
449 "J .+0 \n\t"
450 :
451 : "a" (BUF_HWCB), "a" (OUT_HWCB)
452 : "1", "2", "3");
453 #else
454 return -EPERM;
455 #endif
456
457 if (hwc_data.current_hwcb == OUT_HWCB) {
458
459 if (hwc_data.hwcb_count > 2) {
460
461 BUF_HWCB_NEXT = OUT_HWCB_NEXT;
462
463 BUF_HWCB = OUT_HWCB_NEXT;
464
465 OUT_HWCB_NEXT = BUF_HWCB_NEXT;
466
467 BUF_HWCB_NEXT = NULL;
468 }
469 } else {
470
471 BUF_HWCB_NEXT = OUT_HWCB;
472
473 BUF_HWCB = OUT_HWCB;
474
475 OUT_HWCB = OUT_HWCB_NEXT;
476
477 BUF_HWCB_NEXT = NULL;
478 }
479
480 BUF_HWCB_TIMES_LOST += 1;
481 BUF_HWCB_CHAR_LOST += BUF_HWCB_CHAR;
482 BUF_HWCB_MTO_LOST += BUF_HWCB_MTO;
483 ALL_HWCB_MTO -= BUF_HWCB_MTO;
484 ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
485
486 retval = prepare_write_hwcb ();
487
488 if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
489 internal_print (
490 DELAYED_WRITE,
491 HWC_RW_PRINT_HEADER
492 "reached my own limit of "
493 "allowed buffer space for output (%i HWCBs = %li "
494 "bytes), skipped content of oldest HWCB %i time(s) "
495 "(%i lines = %i characters)\n",
496 hwc_data.ioctls.max_hwcb,
497 hwc_data.ioctls.max_hwcb * PAGE_SIZE,
498 BUF_HWCB_TIMES_LOST,
499 BUF_HWCB_MTO_LOST,
500 BUF_HWCB_CHAR_LOST);
501 else
502 internal_print (
503 DELAYED_WRITE,
504 HWC_RW_PRINT_HEADER
505 "page allocation failed, "
506 "could not expand buffer for output (currently in "
507 "use: %i HWCBs = %li bytes), skipped content of "
508 "oldest HWCB %i time(s) (%i lines = %i characters)\n",
509 hwc_data.hwcb_count,
510 hwc_data.hwcb_count * PAGE_SIZE,
511 BUF_HWCB_TIMES_LOST,
512 BUF_HWCB_MTO_LOST,
513 BUF_HWCB_CHAR_LOST);
514
515 return retval;
516 }
517
518 static int
allocate_write_hwcb(void)519 allocate_write_hwcb (void)
520 {
521 unsigned char *page;
522 int page_nr;
523
524 if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
525 return -ENOMEM;
526
527 page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);
528 if (page_nr < hwc_data.ioctls.kmem_hwcb) {
529
530 page = (unsigned char *)
531 (hwc_data.kmem_start + (page_nr << 12));
532 set_bit (page_nr, &hwc_data.kmem_pages);
533 } else
534 page = (unsigned char *) __get_free_page (GFP_ATOMIC | GFP_DMA);
535
536 if (!page)
537 return -ENOMEM;
538
539 if (!OUT_HWCB)
540 OUT_HWCB = page;
541 else
542 BUF_HWCB_NEXT = page;
543
544 BUF_HWCB = page;
545
546 BUF_HWCB_NEXT = NULL;
547
548 hwc_data.hwcb_count++;
549
550 prepare_write_hwcb ();
551
552 BUF_HWCB_TIMES_LOST = 0;
553 BUF_HWCB_MTO_LOST = 0;
554 BUF_HWCB_CHAR_LOST = 0;
555
556 #ifdef BUFFER_STRESS_TEST
557
558 internal_print (
559 DELAYED_WRITE,
560 "*** " HWC_RW_PRINT_HEADER
561 "page #%i at 0x%x for buffering allocated. ***\n",
562 hwc_data.hwcb_count, page);
563
564 #endif
565
566 return 0;
567 }
568
569 static int
release_write_hwcb(void)570 release_write_hwcb (void)
571 {
572 unsigned long page;
573 int page_nr;
574
575 if (!hwc_data.hwcb_count)
576 return -ENODATA;
577
578 if (hwc_data.hwcb_count == 1) {
579
580 prepare_write_hwcb ();
581
582 ALL_HWCB_CHAR = 0;
583 ALL_HWCB_MTO = 0;
584 BUF_HWCB_TIMES_LOST = 0;
585 BUF_HWCB_MTO_LOST = 0;
586 BUF_HWCB_CHAR_LOST = 0;
587 } else {
588 page = (unsigned long) OUT_HWCB;
589
590 ALL_HWCB_MTO -= OUT_HWCB_MTO;
591 ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
592 hwc_data.hwcb_count--;
593
594 OUT_HWCB = OUT_HWCB_NEXT;
595
596 if (page >= hwc_data.kmem_start &&
597 page <= hwc_data.kmem_end) {
598 /*memset((void *) page, 0, PAGE_SIZE); */
599
600 page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
601 clear_bit (page_nr, &hwc_data.kmem_pages);
602 } else
603 free_page (page);
604 #ifdef BUFFER_STRESS_TEST
605
606 internal_print (
607 DELAYED_WRITE,
608 "*** " HWC_RW_PRINT_HEADER
609 "page at 0x%x released, %i pages still in use ***\n",
610 page, hwc_data.hwcb_count);
611
612 #endif
613 }
614 return 0;
615 }
616
617 static int
add_mto(unsigned char * message,unsigned short int count)618 add_mto (
619 unsigned char *message,
620 unsigned short int count)
621 {
622 unsigned short int mto_size;
623 write_hwcb_t *hwcb;
624 mto_t *mto;
625 void *dest;
626
627 if (!BUF_HWCB)
628 return -ENOMEM;
629
630 if (BUF_HWCB == hwc_data.current_hwcb)
631 return -ENOMEM;
632
633 mto_size = sizeof (mto_t) + count;
634
635 hwcb = (write_hwcb_t *) BUF_HWCB;
636
637 if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
638 return -ENOMEM;
639
640 mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
641
642 memcpy (mto, &mto_template, sizeof (mto_t));
643
644 dest = (void *) (((unsigned long) mto) + sizeof (mto_t));
645
646 memcpy (dest, message, count);
647
648 mto->length += count;
649
650 hwcb->length += mto_size;
651 hwcb->msgbuf.length += mto_size;
652 hwcb->msgbuf.mdb.length += mto_size;
653
654 BUF_HWCB_MTO++;
655 ALL_HWCB_MTO++;
656 BUF_HWCB_CHAR += count;
657 ALL_HWCB_CHAR += count;
658
659 return count;
660 }
661
662 static int write_event_data_1 (void);
663
664 static void
do_poll_hwc(unsigned long data)665 do_poll_hwc (unsigned long data)
666 {
667 unsigned long flags;
668
669 spin_lock_irqsave (&hwc_data.lock, flags);
670
671 write_event_data_1 ();
672
673 spin_unlock_irqrestore (&hwc_data.lock, flags);
674 }
675
676 void
start_poll_hwc(void)677 start_poll_hwc (void)
678 {
679 init_timer (&hwc_data.poll_timer);
680 hwc_data.poll_timer.function = do_poll_hwc;
681 hwc_data.poll_timer.data = (unsigned long) NULL;
682 hwc_data.poll_timer.expires = jiffies + 2 * HZ;
683 add_timer (&hwc_data.poll_timer);
684 hwc_data.flags |= HWC_PTIMER_RUNS;
685 }
686
687 static int
write_event_data_1(void)688 write_event_data_1 (void)
689 {
690 unsigned short int condition_code;
691 int retval;
692 write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
693
694 if ((!hwc_data.write_prio) &&
695 (!hwc_data.write_nonprio) &&
696 hwc_data.read_statechange)
697 return -EOPNOTSUPP;
698
699 if (hwc_data.current_servc)
700 return -EBUSY;
701
702 retval = sane_write_hwcb ();
703 if (retval < 0)
704 return -EIO;
705
706 if (!OUT_HWCB_MTO)
707 return -ENODATA;
708
709 if (!hwc_data.write_nonprio && hwc_data.write_prio)
710 hwcb->msgbuf.type = ET_PMsgCmd;
711 else
712 hwcb->msgbuf.type = ET_Msg;
713
714 condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
715
716 #ifdef DUMP_HWC_WRITE_ERROR
717 if (condition_code != HWC_COMMAND_INITIATED)
718 __asm__ ("LHI 1,0xe20\n\t"
719 "L 2,0(%0)\n\t"
720 "LRA 3,0(%1)\n\t"
721 "J .+0 \n\t"
722 :
723 : "a" (&condition_code), "a" (OUT_HWCB)
724 : "1", "2", "3");
725 #endif
726
727 switch (condition_code) {
728 case HWC_COMMAND_INITIATED:
729 hwc_data.current_servc = HWC_CMDW_WRITEDATA;
730 hwc_data.current_hwcb = OUT_HWCB;
731 retval = condition_code;
732 break;
733 case HWC_BUSY:
734 retval = -EBUSY;
735 break;
736 case HWC_NOT_OPERATIONAL:
737 start_poll_hwc ();
738 default:
739 retval = -EIO;
740 }
741
742 return retval;
743 }
744
745 static void
flush_hwcbs(void)746 flush_hwcbs (void)
747 {
748 while (hwc_data.hwcb_count > 1)
749 release_write_hwcb ();
750
751 release_write_hwcb ();
752
753 hwc_data.flags &= ~HWC_FLUSH;
754 }
755
756 static int
write_event_data_2(u32 ext_int_param)757 write_event_data_2 (u32 ext_int_param)
758 {
759 write_hwcb_t *hwcb;
760 int retval = 0;
761
762 #ifdef DUMP_HWC_WRITE_ERROR
763 if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
764 != (unsigned long) hwc_data.current_hwcb) {
765 internal_print (
766 DELAYED_WRITE,
767 HWC_RW_PRINT_HEADER
768 "write_event_data_2 : "
769 "HWCB address does not fit "
770 "(expected: 0x%lx, got: 0x%lx).\n",
771 (unsigned long) hwc_data.current_hwcb,
772 ext_int_param);
773 return -EINVAL;
774 }
775 #endif
776
777 hwcb = (write_hwcb_t *) OUT_HWCB;
778
779 #ifdef DUMP_HWC_WRITE_LIST_ERROR
780 if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
781 __asm__ ("LHI 1,0xe22\n\t"
782 "LRA 2,0(%0)\n\t"
783 "LRA 3,0(%1)\n\t"
784 "LRA 4,0(%2)\n\t"
785 "LRA 5,0(%3)\n\t"
786 "J .+0 \n\t"
787 :
788 : "a" (OUT_HWCB),
789 "a" (hwc_data.current_hwcb),
790 "a" (BUF_HWCB),
791 "a" (hwcb)
792 : "1", "2", "3", "4", "5");
793 }
794 #endif
795
796 #ifdef DUMP_HWC_WRITE_ERROR
797 if (hwcb->response_code != 0x0020) {
798 __asm__ ("LHI 1,0xe21\n\t"
799 "LRA 2,0(%0)\n\t"
800 "LRA 3,0(%1)\n\t"
801 "LRA 4,0(%2)\n\t"
802 "LH 5,0(%3)\n\t"
803 "SRL 5,8\n\t"
804 "J .+0 \n\t"
805 :
806 : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
807 "a" (BUF_HWCB),
808 "a" (&(hwc_data.hwcb_count))
809 : "1", "2", "3", "4", "5");
810 }
811 #endif
812
813 switch (hwcb->response_code) {
814 case 0x0020:
815
816 retval = OUT_HWCB_CHAR;
817 release_write_hwcb ();
818 break;
819 case 0x0040:
820 case 0x0340:
821 case 0x40F0:
822 if (!hwc_data.read_statechange) {
823 hwcb->response_code = 0;
824 start_poll_hwc ();
825 }
826 retval = -EIO;
827 break;
828 default:
829 internal_print (
830 DELAYED_WRITE,
831 HWC_RW_PRINT_HEADER
832 "write_event_data_2 : "
833 "failed operation "
834 "(response code: 0x%x "
835 "HWCB address: 0x%x).\n",
836 hwcb->response_code,
837 hwcb);
838 retval = -EIO;
839 }
840
841 if (retval == -EIO) {
842
843 hwcb->control_mask[0] = 0;
844 hwcb->control_mask[1] = 0;
845 hwcb->control_mask[2] = 0;
846 hwcb->response_code = 0;
847 }
848 hwc_data.current_servc = 0;
849 hwc_data.current_hwcb = NULL;
850
851 if (hwc_data.flags & HWC_FLUSH)
852 flush_hwcbs ();
853
854 return retval;
855 }
856
857 static void
do_put_line(unsigned char * message,unsigned short count)858 do_put_line (
859 unsigned char *message,
860 unsigned short count)
861 {
862
863 if (add_mto (message, count) != count) {
864
865 if (allocate_write_hwcb () < 0)
866 reuse_write_hwcb ();
867
868 #ifdef DUMP_HWC_WRITE_LIST_ERROR
869 if (add_mto (message, count) != count)
870 __asm__ ("LHI 1,0xe32\n\t"
871 "LRA 2,0(%0)\n\t"
872 "L 3,0(%1)\n\t"
873 "LRA 4,0(%2)\n\t"
874 "LRA 5,0(%3)\n\t"
875 "J .+0 \n\t"
876 :
877 : "a" (message), "a" (&hwc_data.kmem_pages),
878 "a" (BUF_HWCB), "a" (OUT_HWCB)
879 : "1", "2", "3", "4", "5");
880 #else
881 add_mto (message, count);
882 #endif
883 }
884 }
885
886 static void
put_line(unsigned char * message,unsigned short count)887 put_line (
888 unsigned char *message,
889 unsigned short count)
890 {
891
892 if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
893 del_timer (&hwc_data.write_timer);
894 hwc_data.flags &= ~HWC_WTIMER_RUNS;
895 }
896 hwc_data.obuf_start += count;
897
898 do_put_line (message, count);
899
900 hwc_data.obuf_start -= count;
901 }
902
903 static void
set_alarm(void)904 set_alarm (void)
905 {
906 write_hwcb_t *hwcb;
907
908 if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
909 allocate_write_hwcb ();
910
911 hwcb = (write_hwcb_t *) BUF_HWCB;
912 hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
913 }
914
915 static void
hwc_write_timeout(unsigned long data)916 hwc_write_timeout (unsigned long data)
917 {
918 unsigned long flags;
919
920 spin_lock_irqsave (&hwc_data.lock, flags);
921
922 hwc_data.obuf_start = hwc_data.obuf_count;
923 if (hwc_data.obuf_count)
924 put_line (hwc_data.obuf, hwc_data.obuf_count);
925 hwc_data.obuf_start = 0;
926
927 hwc_data.obuf_cursor = 0;
928 hwc_data.obuf_count = 0;
929
930 write_event_data_1 ();
931
932 spin_unlock_irqrestore (&hwc_data.lock, flags);
933 }
934
935 static int
do_hwc_write(int from_user,unsigned char * msg,unsigned int count,unsigned char write_time)936 do_hwc_write (
937 int from_user,
938 unsigned char *msg,
939 unsigned int count,
940 unsigned char write_time)
941 {
942 unsigned int i_msg = 0;
943 unsigned short int spaces = 0;
944 unsigned int processed_characters = 0;
945 unsigned char ch;
946 unsigned short int obuf_count;
947 unsigned short int obuf_cursor;
948 unsigned short int obuf_columns;
949
950 if (hwc_data.obuf_start) {
951 obuf_cursor = 0;
952 obuf_count = 0;
953 obuf_columns = MIN (hwc_data.ioctls.columns,
954 MAX_MESSAGE_SIZE - hwc_data.obuf_start);
955 } else {
956 obuf_cursor = hwc_data.obuf_cursor;
957 obuf_count = hwc_data.obuf_count;
958 obuf_columns = hwc_data.ioctls.columns;
959 }
960
961 for (i_msg = 0; i_msg < count; i_msg++) {
962 if (from_user)
963 get_user (ch, msg + i_msg);
964 else
965 ch = msg[i_msg];
966
967 processed_characters++;
968
969 if ((obuf_cursor == obuf_columns) &&
970
971 (ch != '\n') &&
972
973 (ch != '\t')) {
974 put_line (&hwc_data.obuf[hwc_data.obuf_start],
975 obuf_columns);
976 obuf_cursor = 0;
977 obuf_count = 0;
978 }
979 switch (ch) {
980
981 case '\n':
982
983 put_line (&hwc_data.obuf[hwc_data.obuf_start],
984 obuf_count);
985 obuf_cursor = 0;
986 obuf_count = 0;
987 break;
988
989 case '\a':
990
991 hwc_data.obuf_start += obuf_count;
992 set_alarm ();
993 hwc_data.obuf_start -= obuf_count;
994
995 break;
996
997 case '\t':
998
999 do {
1000 if (obuf_cursor < obuf_columns) {
1001 hwc_data.obuf[hwc_data.obuf_start +
1002 obuf_cursor]
1003 = HWC_ASCEBC (' ');
1004 obuf_cursor++;
1005 } else
1006 break;
1007 } while (obuf_cursor % hwc_data.ioctls.width_htab);
1008
1009 break;
1010
1011 case '\f':
1012 case '\v':
1013
1014 spaces = obuf_cursor;
1015 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1016 obuf_count);
1017 obuf_count = obuf_cursor;
1018 while (spaces) {
1019 hwc_data.obuf[hwc_data.obuf_start +
1020 obuf_cursor - spaces]
1021 = HWC_ASCEBC (' ');
1022 spaces--;
1023 }
1024
1025 break;
1026
1027 case '\b':
1028
1029 if (obuf_cursor)
1030 obuf_cursor--;
1031 break;
1032
1033 case '\r':
1034
1035 obuf_cursor = 0;
1036 break;
1037
1038 case 0x00:
1039
1040 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1041 obuf_count);
1042 obuf_cursor = 0;
1043 obuf_count = 0;
1044 goto out;
1045
1046 default:
1047
1048 if (isprint (ch))
1049 hwc_data.obuf[hwc_data.obuf_start +
1050 obuf_cursor++]
1051 = HWC_ASCEBC (ch);
1052 }
1053 if (obuf_cursor > obuf_count)
1054 obuf_count = obuf_cursor;
1055 }
1056
1057 if (obuf_cursor) {
1058
1059 if (hwc_data.obuf_start ||
1060 (hwc_data.ioctls.final_nl == 0)) {
1061
1062 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1063 obuf_count);
1064 obuf_cursor = 0;
1065 obuf_count = 0;
1066 } else {
1067
1068 if (hwc_data.ioctls.final_nl > 0) {
1069
1070 if (hwc_data.flags & HWC_WTIMER_RUNS) {
1071
1072 mod_timer (&hwc_data.write_timer,
1073 jiffies + hwc_data.ioctls.final_nl * HZ / 10);
1074 } else {
1075
1076 init_timer (&hwc_data.write_timer);
1077 hwc_data.write_timer.function =
1078 hwc_write_timeout;
1079 hwc_data.write_timer.data =
1080 (unsigned long) NULL;
1081 hwc_data.write_timer.expires =
1082 jiffies +
1083 hwc_data.ioctls.final_nl * HZ / 10;
1084 add_timer (&hwc_data.write_timer);
1085 hwc_data.flags |= HWC_WTIMER_RUNS;
1086 }
1087 } else;
1088
1089 }
1090 } else;
1091
1092 out:
1093
1094 if (!hwc_data.obuf_start) {
1095 hwc_data.obuf_cursor = obuf_cursor;
1096 hwc_data.obuf_count = obuf_count;
1097 }
1098 if (write_time == IMMEDIATE_WRITE)
1099 write_event_data_1 ();
1100
1101 return processed_characters;
1102 }
1103
1104 signed int
hwc_write(int from_user,const unsigned char * msg,unsigned int count)1105 hwc_write (int from_user, const unsigned char *msg, unsigned int count)
1106 {
1107 unsigned long flags;
1108 int retval;
1109
1110 spin_lock_irqsave (&hwc_data.lock, flags);
1111
1112 retval = do_hwc_write (from_user, (unsigned char *) msg,
1113 count, IMMEDIATE_WRITE);
1114
1115 spin_unlock_irqrestore (&hwc_data.lock, flags);
1116
1117 return retval;
1118 }
1119
1120 unsigned int
hwc_chars_in_buffer(unsigned char flag)1121 hwc_chars_in_buffer (unsigned char flag)
1122 {
1123 unsigned short int number = 0;
1124 unsigned long flags;
1125
1126 spin_lock_irqsave (&hwc_data.lock, flags);
1127
1128 if (flag & IN_HWCB)
1129 number += ALL_HWCB_CHAR;
1130
1131 if (flag & IN_WRITE_BUF)
1132 number += hwc_data.obuf_cursor;
1133
1134 spin_unlock_irqrestore (&hwc_data.lock, flags);
1135
1136 return number;
1137 }
1138
1139 static inline int
nr_setbits(kmem_pages_t arg)1140 nr_setbits (kmem_pages_t arg)
1141 {
1142 int i;
1143 int nr = 0;
1144
1145 for (i = 0; i < (sizeof (arg) << 3); i++) {
1146 if (arg & 1)
1147 nr++;
1148 arg >>= 1;
1149 }
1150
1151 return nr;
1152 }
1153
1154 unsigned int
hwc_write_room(unsigned char flag)1155 hwc_write_room (unsigned char flag)
1156 {
1157 unsigned int number = 0;
1158 unsigned long flags;
1159 write_hwcb_t *hwcb;
1160
1161 spin_lock_irqsave (&hwc_data.lock, flags);
1162
1163 if (flag & IN_HWCB) {
1164
1165 if (BUF_HWCB) {
1166 hwcb = (write_hwcb_t *) BUF_HWCB;
1167 number += MAX_HWCB_ROOM - hwcb->length;
1168 }
1169 number += (hwc_data.ioctls.kmem_hwcb -
1170 nr_setbits (hwc_data.kmem_pages)) *
1171 (MAX_HWCB_ROOM -
1172 (sizeof (write_hwcb_t) + sizeof (mto_t)));
1173 }
1174 if (flag & IN_WRITE_BUF)
1175 number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
1176
1177 spin_unlock_irqrestore (&hwc_data.lock, flags);
1178
1179 return number;
1180 }
1181
1182 void
hwc_flush_buffer(unsigned char flag)1183 hwc_flush_buffer (unsigned char flag)
1184 {
1185 unsigned long flags;
1186
1187 spin_lock_irqsave (&hwc_data.lock, flags);
1188
1189 if (flag & IN_HWCB) {
1190 if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
1191 flush_hwcbs ();
1192 else
1193 hwc_data.flags |= HWC_FLUSH;
1194 }
1195 if (flag & IN_WRITE_BUF) {
1196 hwc_data.obuf_cursor = 0;
1197 hwc_data.obuf_count = 0;
1198 }
1199 spin_unlock_irqrestore (&hwc_data.lock, flags);
1200 }
1201
1202 unsigned short int
seperate_cases(unsigned char * buf,unsigned short int count)1203 seperate_cases (unsigned char *buf, unsigned short int count)
1204 {
1205
1206 unsigned short int i_in;
1207
1208 unsigned short int i_out = 0;
1209
1210 unsigned char _case = 0;
1211
1212 for (i_in = 0; i_in < count; i_in++) {
1213
1214 if (buf[i_in] == hwc_data.ioctls.delim) {
1215
1216 if ((i_in + 1 < count) &&
1217 (buf[i_in + 1] == hwc_data.ioctls.delim)) {
1218
1219 buf[i_out] = hwc_data.ioctls.delim;
1220
1221 i_out++;
1222
1223 i_in++;
1224
1225 } else
1226 _case = ~_case;
1227
1228 } else {
1229
1230 if (_case) {
1231
1232 if (hwc_data.ioctls.tolower)
1233 buf[i_out] = _ebc_toupper[buf[i_in]];
1234
1235 else
1236 buf[i_out] = _ebc_tolower[buf[i_in]];
1237
1238 } else
1239 buf[i_out] = buf[i_in];
1240
1241 i_out++;
1242 }
1243 }
1244
1245 return i_out;
1246 }
1247
1248 #ifdef DUMP_HWCB_INPUT
1249
1250 static int
gds_vector_name(u16 id,unsigned char name[])1251 gds_vector_name (u16 id, unsigned char name[])
1252 {
1253 int retval = 0;
1254
1255 switch (id) {
1256 case GDS_ID_MDSMU:
1257 name = "Multiple Domain Support Message Unit";
1258 break;
1259 case GDS_ID_MDSRouteInfo:
1260 name = "MDS Routing Information";
1261 break;
1262 case GDS_ID_AgUnWrkCorr:
1263 name = "Agent Unit of Work Correlator";
1264 break;
1265 case GDS_ID_SNACondReport:
1266 name = "SNA Condition Report";
1267 break;
1268 case GDS_ID_CPMSU:
1269 name = "CP Management Services Unit";
1270 break;
1271 case GDS_ID_RoutTargInstr:
1272 name = "Routing and Targeting Instructions";
1273 break;
1274 case GDS_ID_OpReq:
1275 name = "Operate Request";
1276 break;
1277 case GDS_ID_TextCmd:
1278 name = "Text Command";
1279 break;
1280
1281 default:
1282 name = "unknown GDS variable";
1283 retval = -EINVAL;
1284 }
1285
1286 return retval;
1287 }
1288 #endif
1289
1290 inline static gds_vector_t *
find_gds_vector(gds_vector_t * start,void * end,u16 id)1291 find_gds_vector (
1292 gds_vector_t * start, void *end, u16 id)
1293 {
1294 gds_vector_t *vec;
1295 gds_vector_t *retval = NULL;
1296
1297 vec = start;
1298
1299 while (((void *) vec) < end) {
1300 if (vec->gds_id == id) {
1301
1302 #ifdef DUMP_HWCB_INPUT
1303 int retval_name;
1304 unsigned char name[64];
1305
1306 retval_name = gds_vector_name (id, name);
1307 internal_print (
1308 DELAYED_WRITE,
1309 HWC_RW_PRINT_HEADER
1310 "%s at 0x%x up to 0x%x, length: %d",
1311 name,
1312 (unsigned long) vec,
1313 ((unsigned long) vec) + vec->length - 1,
1314 vec->length);
1315 if (retval_name < 0)
1316 internal_print (
1317 IMMEDIATE_WRITE,
1318 ", id: 0x%x\n",
1319 vec->gds_id);
1320 else
1321 internal_print (
1322 IMMEDIATE_WRITE,
1323 "\n");
1324 #endif
1325
1326 retval = vec;
1327 break;
1328 }
1329 vec = (gds_vector_t *) (((unsigned long) vec) + vec->length);
1330 }
1331
1332 return retval;
1333 }
1334
1335 inline static gds_subvector_t *
find_gds_subvector(gds_subvector_t * start,void * end,u8 key)1336 find_gds_subvector (
1337 gds_subvector_t * start, void *end, u8 key)
1338 {
1339 gds_subvector_t *subvec;
1340 gds_subvector_t *retval = NULL;
1341
1342 subvec = start;
1343
1344 while (((void *) subvec) < end) {
1345 if (subvec->key == key) {
1346 retval = subvec;
1347 break;
1348 }
1349 subvec = (gds_subvector_t *)
1350 (((unsigned long) subvec) + subvec->length);
1351 }
1352
1353 return retval;
1354 }
1355
1356 inline static int
get_input(void * start,void * end)1357 get_input (void *start, void *end)
1358 {
1359 int count;
1360
1361 count = ((unsigned long) end) - ((unsigned long) start);
1362
1363 if (hwc_data.ioctls.tolower)
1364 EBC_TOLOWER (start, count);
1365
1366 if (hwc_data.ioctls.delim)
1367 count = seperate_cases (start, count);
1368
1369 HWC_EBCASC_STR (start, count);
1370
1371 if (hwc_data.ioctls.echo)
1372 do_hwc_write (0, start, count, IMMEDIATE_WRITE);
1373
1374 if (hwc_data.calls != NULL)
1375 if (hwc_data.calls->move_input != NULL)
1376 (hwc_data.calls->move_input) (start, count);
1377
1378 return count;
1379 }
1380
1381 inline static int
eval_selfdeftextmsg(gds_subvector_t * start,void * end)1382 eval_selfdeftextmsg (gds_subvector_t * start, void *end)
1383 {
1384 gds_subvector_t *subvec;
1385 void *subvec_data;
1386 void *subvec_end;
1387 int retval = 0;
1388
1389 subvec = start;
1390
1391 while (((void *) subvec) < end) {
1392 subvec = find_gds_subvector (subvec, end, 0x30);
1393 if (!subvec)
1394 break;
1395 subvec_data = (void *)
1396 (((unsigned long) subvec) +
1397 sizeof (gds_subvector_t));
1398 subvec_end = (void *)
1399 (((unsigned long) subvec) + subvec->length);
1400 retval += get_input (subvec_data, subvec_end);
1401 subvec = (gds_subvector_t *) subvec_end;
1402 }
1403
1404 return retval;
1405 }
1406
1407 inline static int
eval_textcmd(gds_subvector_t * start,void * end)1408 eval_textcmd (gds_subvector_t * start, void *end)
1409 {
1410 gds_subvector_t *subvec;
1411 gds_subvector_t *subvec_data;
1412 void *subvec_end;
1413 int retval = 0;
1414
1415 subvec = start;
1416
1417 while (((void *) subvec) < end) {
1418 subvec = find_gds_subvector (
1419 subvec, end, GDS_KEY_SelfDefTextMsg);
1420 if (!subvec)
1421 break;
1422 subvec_data = (gds_subvector_t *)
1423 (((unsigned long) subvec) +
1424 sizeof (gds_subvector_t));
1425 subvec_end = (void *)
1426 (((unsigned long) subvec) + subvec->length);
1427 retval += eval_selfdeftextmsg (subvec_data, subvec_end);
1428 subvec = (gds_subvector_t *) subvec_end;
1429 }
1430
1431 return retval;
1432 }
1433
1434 inline static int
eval_cpmsu(gds_vector_t * start,void * end)1435 eval_cpmsu (gds_vector_t * start, void *end)
1436 {
1437 gds_vector_t *vec;
1438 gds_subvector_t *vec_data;
1439 void *vec_end;
1440 int retval = 0;
1441
1442 vec = start;
1443
1444 while (((void *) vec) < end) {
1445 vec = find_gds_vector (vec, end, GDS_ID_TextCmd);
1446 if (!vec)
1447 break;
1448 vec_data = (gds_subvector_t *)
1449 (((unsigned long) vec) + sizeof (gds_vector_t));
1450 vec_end = (void *) (((unsigned long) vec) + vec->length);
1451 retval += eval_textcmd (vec_data, vec_end);
1452 vec = (gds_vector_t *) vec_end;
1453 }
1454
1455 return retval;
1456 }
1457
1458 inline static int
eval_mdsmu(gds_vector_t * start,void * end)1459 eval_mdsmu (gds_vector_t * start, void *end)
1460 {
1461 gds_vector_t *vec;
1462 gds_vector_t *vec_data;
1463 void *vec_end;
1464 int retval = 0;
1465
1466 vec = find_gds_vector (start, end, GDS_ID_CPMSU);
1467 if (vec) {
1468 vec_data = (gds_vector_t *)
1469 (((unsigned long) vec) + sizeof (gds_vector_t));
1470 vec_end = (void *) (((unsigned long) vec) + vec->length);
1471 retval = eval_cpmsu (vec_data, vec_end);
1472 }
1473 return retval;
1474 }
1475
1476 static int
eval_evbuf(gds_vector_t * start,void * end)1477 eval_evbuf (gds_vector_t * start, void *end)
1478 {
1479 gds_vector_t *vec;
1480 gds_vector_t *vec_data;
1481 void *vec_end;
1482 int retval = 0;
1483
1484 vec = find_gds_vector (start, end, GDS_ID_MDSMU);
1485 if (vec) {
1486 vec_data = (gds_vector_t *)
1487 (((unsigned long) vec) + sizeof (gds_vector_t));
1488 vec_end = (void *) (((unsigned long) vec) + vec->length);
1489 retval = eval_mdsmu (vec_data, vec_end);
1490 }
1491 return retval;
1492 }
1493
1494 static inline int
eval_hwc_receive_mask(_hwcb_mask_t mask)1495 eval_hwc_receive_mask (_hwcb_mask_t mask)
1496 {
1497
1498 hwc_data.write_nonprio
1499 = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
1500
1501 hwc_data.write_prio
1502 = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
1503
1504 if (hwc_data.write_prio || hwc_data.write_nonprio) {
1505 internal_print (
1506 DELAYED_WRITE,
1507 HWC_RW_PRINT_HEADER
1508 "can write messages\n");
1509 return 0;
1510 } else {
1511 internal_print (
1512 DELAYED_WRITE,
1513 HWC_RW_PRINT_HEADER
1514 "can not write messages\n");
1515 return -1;
1516 }
1517 }
1518
1519 static inline int
eval_hwc_send_mask(_hwcb_mask_t mask)1520 eval_hwc_send_mask (_hwcb_mask_t mask)
1521 {
1522
1523 hwc_data.read_statechange
1524 = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
1525 if (hwc_data.read_statechange)
1526 internal_print (
1527 DELAYED_WRITE,
1528 HWC_RW_PRINT_HEADER
1529 "can read state change notifications\n");
1530 else
1531 internal_print (
1532 DELAYED_WRITE,
1533 HWC_RW_PRINT_HEADER
1534 "can not read state change notifications\n");
1535
1536 hwc_data.sig_quiesce
1537 = ((mask & ET_SigQuiesce_Mask) == ET_SigQuiesce_Mask);
1538 if (hwc_data.sig_quiesce)
1539 internal_print (
1540 DELAYED_WRITE,
1541 HWC_RW_PRINT_HEADER
1542 "can receive signal quiesce\n");
1543 else
1544 internal_print (
1545 DELAYED_WRITE,
1546 HWC_RW_PRINT_HEADER
1547 "can not receive signal quiesce\n");
1548
1549 hwc_data.read_nonprio
1550 = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
1551 if (hwc_data.read_nonprio)
1552 internal_print (
1553 DELAYED_WRITE,
1554 HWC_RW_PRINT_HEADER
1555 "can read commands\n");
1556
1557 hwc_data.read_prio
1558 = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
1559 if (hwc_data.read_prio)
1560 internal_print (
1561 DELAYED_WRITE,
1562 HWC_RW_PRINT_HEADER
1563 "can read priority commands\n");
1564
1565 if (hwc_data.read_prio || hwc_data.read_nonprio) {
1566 return 0;
1567 } else {
1568 internal_print (
1569 DELAYED_WRITE,
1570 HWC_RW_PRINT_HEADER
1571 "can not read commands from operator\n");
1572 return -1;
1573 }
1574 }
1575
1576 static int
eval_statechangebuf(statechangebuf_t * scbuf)1577 eval_statechangebuf (statechangebuf_t * scbuf)
1578 {
1579 int retval = 0;
1580
1581 internal_print (
1582 DELAYED_WRITE,
1583 HWC_RW_PRINT_HEADER
1584 "HWC state change detected\n");
1585
1586 if (scbuf->validity_hwc_active_facility_mask) {
1587
1588 }
1589 if (scbuf->validity_hwc_receive_mask) {
1590
1591 if (scbuf->mask_length != 4) {
1592 #ifdef DUMP_HWC_INIT_ERROR
1593 __asm__ ("LHI 1,0xe50\n\t"
1594 "LRA 2,0(%0)\n\t"
1595 "J .+0 \n\t"
1596 :
1597 : "a" (scbuf)
1598 : "1", "2");
1599 #endif
1600 } else {
1601
1602 retval += eval_hwc_receive_mask
1603 (scbuf->hwc_receive_mask);
1604 }
1605 }
1606 if (scbuf->validity_hwc_send_mask) {
1607
1608 if (scbuf->mask_length != 4) {
1609 #ifdef DUMP_HWC_INIT_ERROR
1610 __asm__ ("LHI 1,0xe51\n\t"
1611 "LRA 2,0(%0)\n\t"
1612 "J .+0 \n\t"
1613 :
1614 : "a" (scbuf)
1615 : "1", "2");
1616 #endif
1617 } else {
1618
1619 retval += eval_hwc_send_mask
1620 (scbuf->hwc_send_mask);
1621 }
1622 }
1623 if (scbuf->validity_read_data_function_mask) {
1624
1625 }
1626 return retval;
1627 }
1628
1629 #ifdef CONFIG_SMP
1630 extern unsigned long cpu_online_map;
1631 static volatile unsigned long cpu_quiesce_map;
1632
1633 static void
do_load_quiesce_psw(void)1634 do_load_quiesce_psw (void)
1635 {
1636 psw_t quiesce_psw;
1637
1638 clear_bit (smp_processor_id (), &cpu_quiesce_map);
1639 if (smp_processor_id () == 0) {
1640
1641 while (cpu_quiesce_map != 0) ;
1642
1643 quiesce_psw.mask = _DW_PSW_MASK;
1644 quiesce_psw.addr = 0xfff;
1645 __load_psw (quiesce_psw);
1646 }
1647 signal_processor (smp_processor_id (), sigp_stop);
1648 }
1649
1650 static void
do_machine_quiesce(void)1651 do_machine_quiesce (void)
1652 {
1653 cpu_quiesce_map = cpu_online_map;
1654 smp_call_function (do_load_quiesce_psw, NULL, 0, 0);
1655 do_load_quiesce_psw ();
1656 }
1657
1658 #else
1659 static void
do_machine_quiesce(void)1660 do_machine_quiesce (void)
1661 {
1662 psw_t quiesce_psw;
1663
1664 quiesce_psw.mask = _DW_PSW_MASK;
1665 queisce_psw.addr = 0xfff;
1666 __load_psw (quiesce_psw);
1667 }
1668
1669 #endif
1670
1671 static int
process_evbufs(void * start,void * end)1672 process_evbufs (void *start, void *end)
1673 {
1674 int retval = 0;
1675 evbuf_t *evbuf;
1676 void *evbuf_end;
1677 gds_vector_t *evbuf_data;
1678
1679 evbuf = (evbuf_t *) start;
1680 while (((void *) evbuf) < end) {
1681 evbuf_data = (gds_vector_t *)
1682 (((unsigned long) evbuf) + sizeof (evbuf_t));
1683 evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
1684 switch (evbuf->type) {
1685 case ET_OpCmd:
1686 case ET_CntlProgOpCmd:
1687 case ET_PMsgCmd:
1688 #ifdef DUMP_HWCB_INPUT
1689
1690 internal_print (
1691 DELAYED_WRITE,
1692 HWC_RW_PRINT_HEADER
1693 "event buffer "
1694 "at 0x%x up to 0x%x, length: %d\n",
1695 (unsigned long) evbuf,
1696 (unsigned long) (evbuf_end - 1),
1697 evbuf->length);
1698 dump_storage_area ((void *) evbuf, evbuf->length);
1699 #endif
1700 retval += eval_evbuf (evbuf_data, evbuf_end);
1701 break;
1702 case ET_StateChange:
1703 retval += eval_statechangebuf
1704 ((statechangebuf_t *) evbuf);
1705 break;
1706 case ET_SigQuiesce:
1707
1708 _machine_restart = do_machine_quiesce;
1709 _machine_halt = do_machine_quiesce;
1710 _machine_power_off = do_machine_quiesce;
1711 ctrl_alt_del ();
1712 break;
1713 default:
1714 internal_print (
1715 DELAYED_WRITE,
1716 HWC_RW_PRINT_HEADER
1717 "unconditional read: "
1718 "unknown event buffer found, "
1719 "type 0x%x",
1720 evbuf->type);
1721 retval = -ENOSYS;
1722 }
1723 evbuf = (evbuf_t *) evbuf_end;
1724 }
1725 return retval;
1726 }
1727
1728 static int
unconditional_read_1(void)1729 unconditional_read_1 (void)
1730 {
1731 unsigned short int condition_code;
1732 read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
1733 int retval;
1734
1735 #if 0
1736
1737 if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
1738 return -EOPNOTSUPP;
1739
1740 if (hwc_data.current_servc)
1741 return -EBUSY;
1742 #endif
1743
1744 memset (hwcb, 0x00, PAGE_SIZE);
1745 memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
1746
1747 condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page);
1748
1749 #ifdef DUMP_HWC_READ_ERROR
1750 if (condition_code == HWC_NOT_OPERATIONAL)
1751 __asm__ ("LHI 1,0xe40\n\t"
1752 "L 2,0(%0)\n\t"
1753 "LRA 3,0(%1)\n\t"
1754 "J .+0 \n\t"
1755 :
1756 : "a" (&condition_code), "a" (hwc_data.page)
1757 : "1", "2", "3");
1758 #endif
1759
1760 switch (condition_code) {
1761 case HWC_COMMAND_INITIATED:
1762 hwc_data.current_servc = HWC_CMDW_READDATA;
1763 hwc_data.current_hwcb = hwc_data.page;
1764 retval = condition_code;
1765 break;
1766 case HWC_BUSY:
1767 retval = -EBUSY;
1768 break;
1769 default:
1770 retval = -EIO;
1771 }
1772
1773 return retval;
1774 }
1775
1776 static int
unconditional_read_2(u32 ext_int_param)1777 unconditional_read_2 (u32 ext_int_param)
1778 {
1779 read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
1780
1781 #ifdef DUMP_HWC_READ_ERROR
1782 if ((hwcb->response_code != 0x0020) &&
1783 (hwcb->response_code != 0x0220) &&
1784 (hwcb->response_code != 0x60F0) &&
1785 (hwcb->response_code != 0x62F0))
1786 __asm__ ("LHI 1,0xe41\n\t"
1787 "LRA 2,0(%0)\n\t"
1788 "L 3,0(%1)\n\t"
1789 "J .+0\n\t"
1790 :
1791 : "a" (hwc_data.page), "a" (&(hwcb->response_code))
1792 : "1", "2", "3");
1793 #endif
1794
1795 hwc_data.current_servc = 0;
1796 hwc_data.current_hwcb = NULL;
1797
1798 switch (hwcb->response_code) {
1799
1800 case 0x0020:
1801 case 0x0220:
1802 return process_evbufs (
1803 (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)),
1804 (void *) (((unsigned long) hwcb) + hwcb->length));
1805
1806 case 0x60F0:
1807 case 0x62F0:
1808 internal_print (
1809 IMMEDIATE_WRITE,
1810 HWC_RW_PRINT_HEADER
1811 "unconditional read: "
1812 "got interrupt and tried to read input, "
1813 "but nothing found (response code=0x%x).\n",
1814 hwcb->response_code);
1815 return 0;
1816
1817 case 0x0100:
1818 internal_print (
1819 IMMEDIATE_WRITE,
1820 HWC_RW_PRINT_HEADER
1821 "unconditional read: HWCB boundary violation - this "
1822 "must not occur in a correct driver, please contact "
1823 "author\n");
1824 return -EIO;
1825
1826 case 0x0300:
1827 internal_print (
1828 IMMEDIATE_WRITE,
1829 HWC_RW_PRINT_HEADER
1830 "unconditional read: "
1831 "insufficient HWCB length - this must not occur in a "
1832 "correct driver, please contact author\n");
1833 return -EIO;
1834
1835 case 0x01F0:
1836 internal_print (
1837 IMMEDIATE_WRITE,
1838 HWC_RW_PRINT_HEADER
1839 "unconditional read: "
1840 "invalid command - this must not occur in a correct "
1841 "driver, please contact author\n");
1842 return -EIO;
1843
1844 case 0x40F0:
1845 internal_print (
1846 IMMEDIATE_WRITE,
1847 HWC_RW_PRINT_HEADER
1848 "unconditional read: invalid function code\n");
1849 return -EIO;
1850
1851 case 0x70F0:
1852 internal_print (
1853 IMMEDIATE_WRITE,
1854 HWC_RW_PRINT_HEADER
1855 "unconditional read: invalid selection mask\n");
1856 return -EIO;
1857
1858 case 0x0040:
1859 internal_print (
1860 IMMEDIATE_WRITE,
1861 HWC_RW_PRINT_HEADER
1862 "unconditional read: HWC equipment check\n");
1863 return -EIO;
1864
1865 default:
1866 internal_print (
1867 IMMEDIATE_WRITE,
1868 HWC_RW_PRINT_HEADER
1869 "unconditional read: invalid response code %x - this "
1870 "must not occur in a correct driver, please contact "
1871 "author\n",
1872 hwcb->response_code);
1873 return -EIO;
1874 }
1875 }
1876
1877 static int
write_event_mask_1(void)1878 write_event_mask_1 (void)
1879 {
1880 unsigned int condition_code;
1881 int retval;
1882
1883 condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);
1884
1885 #ifdef DUMP_HWC_INIT_ERROR
1886
1887 if (condition_code == HWC_NOT_OPERATIONAL)
1888 __asm__ ("LHI 1,0xe10\n\t"
1889 "L 2,0(%0)\n\t"
1890 "LRA 3,0(%1)\n\t"
1891 "J .+0\n\t"
1892 :
1893 : "a" (&condition_code), "a" (hwc_data.page)
1894 : "1", "2", "3");
1895 #endif
1896
1897 switch (condition_code) {
1898 case HWC_COMMAND_INITIATED:
1899 hwc_data.current_servc = HWC_CMDW_WRITEMASK;
1900 hwc_data.current_hwcb = hwc_data.page;
1901 retval = condition_code;
1902 break;
1903 case HWC_BUSY:
1904 retval = -EBUSY;
1905 break;
1906 default:
1907 retval = -EIO;
1908 }
1909
1910 return retval;
1911 }
1912
1913 static int
write_event_mask_2(u32 ext_int_param)1914 write_event_mask_2 (u32 ext_int_param)
1915 {
1916 init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
1917 int retval = 0;
1918
1919 if (hwcb->response_code != 0x0020) {
1920 #ifdef DUMP_HWC_INIT_ERROR
1921 __asm__ ("LHI 1,0xe11\n\t"
1922 "LRA 2,0(%0)\n\t"
1923 "L 3,0(%1)\n\t"
1924 "J .+0\n\t"
1925 :
1926 : "a" (hwcb), "a" (&(hwcb->response_code))
1927 : "1", "2", "3");
1928 #else
1929 retval = -1;
1930 #endif
1931 } else {
1932 if (hwcb->mask_length != 4) {
1933 #ifdef DUMP_HWC_INIT_ERROR
1934 __asm__ ("LHI 1,0xe52\n\t"
1935 "LRA 2,0(%0)\n\t"
1936 "J .+0 \n\t"
1937 :
1938 : "a" (hwcb)
1939 : "1", "2");
1940 #endif
1941 } else {
1942 retval += eval_hwc_receive_mask
1943 (hwcb->hwc_receive_mask);
1944 retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
1945 }
1946 }
1947
1948 hwc_data.current_servc = 0;
1949 hwc_data.current_hwcb = NULL;
1950
1951 return retval;
1952 }
1953
1954 static int
set_hwc_ioctls(hwc_ioctls_t * ioctls,char correct)1955 set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
1956 {
1957 int retval = 0;
1958 hwc_ioctls_t tmp;
1959
1960 if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
1961 if (correct)
1962 tmp.width_htab = MAX_MESSAGE_SIZE;
1963 else
1964 retval = -EINVAL;
1965 } else
1966 tmp.width_htab = ioctls->width_htab;
1967
1968 tmp.echo = ioctls->echo;
1969
1970 if (ioctls->columns > MAX_MESSAGE_SIZE) {
1971 if (correct)
1972 tmp.columns = MAX_MESSAGE_SIZE;
1973 else
1974 retval = -EINVAL;
1975 } else
1976 tmp.columns = ioctls->columns;
1977
1978 tmp.final_nl = ioctls->final_nl;
1979
1980 if (ioctls->max_hwcb < 2) {
1981 if (correct)
1982 tmp.max_hwcb = 2;
1983 else
1984 retval = -EINVAL;
1985 } else
1986 tmp.max_hwcb = ioctls->max_hwcb;
1987
1988 tmp.tolower = ioctls->tolower;
1989
1990 if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
1991 if (correct)
1992 tmp.kmem_hwcb = ioctls->max_hwcb;
1993 else
1994 retval = -EINVAL;
1995 } else
1996 tmp.kmem_hwcb = ioctls->kmem_hwcb;
1997
1998 if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
1999 if (correct)
2000 ioctls->kmem_hwcb = MAX_KMEM_PAGES;
2001 else
2002 retval = -EINVAL;
2003 }
2004 if (ioctls->kmem_hwcb < 2) {
2005 if (correct)
2006 ioctls->kmem_hwcb = 2;
2007 else
2008 retval = -EINVAL;
2009 }
2010 tmp.delim = ioctls->delim;
2011
2012 if (!(retval < 0))
2013 hwc_data.ioctls = tmp;
2014
2015 return retval;
2016 }
2017
2018 int
do_hwc_init(void)2019 do_hwc_init (void)
2020 {
2021 int retval;
2022
2023 memcpy (hwc_data.page, &init_hwcb_template, sizeof (init_hwcb_t));
2024
2025 do {
2026
2027 retval = write_event_mask_1 ();
2028
2029 if (retval == -EBUSY) {
2030
2031 hwc_data.flags |= HWC_INIT;
2032
2033 __ctl_store (cr0, 0, 0);
2034 cr0_save = cr0;
2035 cr0 |= 0x00000200;
2036 cr0 &= 0xFFFFF3AC;
2037 __ctl_load (cr0, 0, 0);
2038
2039 asm volatile ("STOSM %0,0x01"
2040 :"=m" (psw_mask)::"memory");
2041
2042 while (!(hwc_data.flags & HWC_INTERRUPT))
2043 barrier ();
2044
2045 asm volatile ("STNSM %0,0xFE"
2046 :"=m" (psw_mask)::"memory");
2047
2048 __ctl_load (cr0_save, 0, 0);
2049
2050 hwc_data.flags &= ~HWC_INIT;
2051 }
2052 } while (retval == -EBUSY);
2053
2054 if (retval == -EIO) {
2055 hwc_data.flags |= HWC_BROKEN;
2056 printk (HWC_RW_PRINT_HEADER "HWC not operational\n");
2057 }
2058 return retval;
2059 }
2060
2061 void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
2062
2063 int
hwc_init(void)2064 hwc_init (void)
2065 {
2066 int retval;
2067
2068 #ifdef BUFFER_STRESS_TEST
2069
2070 init_hwcb_t *hwcb;
2071 int i;
2072
2073 #endif
2074
2075 if (register_early_external_interrupt (0x2401, hwc_interrupt_handler,
2076 &ext_int_info_hwc) != 0)
2077 panic ("Couldn't request external interrupts 0x2401");
2078
2079 spin_lock_init (&hwc_data.lock);
2080
2081 #ifdef USE_VM_DETECTION
2082
2083 if (MACHINE_IS_VM) {
2084
2085 if (hwc_data.init_ioctls.columns > 76)
2086 hwc_data.init_ioctls.columns = 76;
2087 hwc_data.init_ioctls.tolower = 1;
2088 if (!hwc_data.init_ioctls.delim)
2089 hwc_data.init_ioctls.delim = DEFAULT_CASE_DELIMITER;
2090 } else {
2091 hwc_data.init_ioctls.tolower = 0;
2092 hwc_data.init_ioctls.delim = 0;
2093 }
2094 #endif
2095 retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
2096
2097 hwc_data.kmem_start = (unsigned long)
2098 alloc_bootmem_low_pages (hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
2099 hwc_data.kmem_end = hwc_data.kmem_start +
2100 hwc_data.ioctls.kmem_hwcb * PAGE_SIZE - 1;
2101
2102 retval = do_hwc_init ();
2103
2104 ctl_set_bit (0, 9);
2105
2106 #ifdef BUFFER_STRESS_TEST
2107
2108 internal_print (
2109 DELAYED_WRITE,
2110 HWC_RW_PRINT_HEADER
2111 "use %i bytes for buffering.\n",
2112 hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
2113 for (i = 0; i < 500; i++) {
2114 hwcb = (init_hwcb_t *) BUF_HWCB;
2115 internal_print (
2116 DELAYED_WRITE,
2117 HWC_RW_PRINT_HEADER
2118 "This is stress test message #%i, free: %i bytes\n",
2119 i,
2120 MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t)));
2121 }
2122
2123 #endif
2124
2125 return /*retval */ 0;
2126 }
2127
2128 signed int
hwc_register_calls(hwc_high_level_calls_t * calls)2129 hwc_register_calls (hwc_high_level_calls_t * calls)
2130 {
2131 if (calls == NULL)
2132 return -EINVAL;
2133
2134 if (hwc_data.calls != NULL)
2135 return -EBUSY;
2136
2137 hwc_data.calls = calls;
2138 return 0;
2139 }
2140
2141 signed int
hwc_unregister_calls(hwc_high_level_calls_t * calls)2142 hwc_unregister_calls (hwc_high_level_calls_t * calls)
2143 {
2144 if (hwc_data.calls == NULL)
2145 return -EINVAL;
2146
2147 if (calls != hwc_data.calls)
2148 return -EINVAL;
2149
2150 hwc_data.calls = NULL;
2151 return 0;
2152 }
2153
2154 int
hwc_send(hwc_request_t * req)2155 hwc_send (hwc_request_t * req)
2156 {
2157 unsigned long flags;
2158 int retval;
2159 int cc;
2160
2161 spin_lock_irqsave (&hwc_data.lock, flags);
2162 if (!req || !req->callback || !req->block) {
2163 retval = -EINVAL;
2164 goto unlock;
2165 }
2166 if (hwc_data.request) {
2167 retval = -ENOTSUPP;
2168 goto unlock;
2169 }
2170 cc = service_call (req->word, req->block);
2171 switch (cc) {
2172 case 0:
2173 hwc_data.request = req;
2174 hwc_data.current_servc = req->word;
2175 hwc_data.current_hwcb = req->block;
2176 retval = 0;
2177 break;
2178 case 2:
2179 retval = -EBUSY;
2180 break;
2181 default:
2182 retval = -ENOSYS;
2183
2184 }
2185 unlock:
2186 spin_unlock_irqrestore (&hwc_data.lock, flags);
2187 return retval;
2188 }
2189
2190 EXPORT_SYMBOL (hwc_send);
2191
2192 void
do_hwc_callback(u32 ext_int_param)2193 do_hwc_callback (u32 ext_int_param)
2194 {
2195 if (!hwc_data.request || !hwc_data.request->callback)
2196 return;
2197 if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
2198 != (unsigned long) hwc_data.request->block)
2199 return;
2200 hwc_data.request->callback (hwc_data.request);
2201 hwc_data.request = NULL;
2202 hwc_data.current_hwcb = NULL;
2203 hwc_data.current_servc = 0;
2204 }
2205
2206 void
hwc_do_interrupt(u32 ext_int_param)2207 hwc_do_interrupt (u32 ext_int_param)
2208 {
2209 u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
2210 u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
2211
2212 if (hwc_data.flags & HWC_PTIMER_RUNS) {
2213 del_timer (&hwc_data.poll_timer);
2214 hwc_data.flags &= ~HWC_PTIMER_RUNS;
2215 }
2216 if (finished_hwcb) {
2217
2218 if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
2219 internal_print (
2220 DELAYED_WRITE,
2221 HWC_RW_PRINT_HEADER
2222 "interrupt: mismatch: "
2223 "ext. int param. (0x%x) vs. "
2224 "current HWCB (0x%x)\n",
2225 ext_int_param,
2226 hwc_data.current_hwcb);
2227 } else {
2228 if (hwc_data.request) {
2229
2230 do_hwc_callback (ext_int_param);
2231 } else {
2232
2233 switch (hwc_data.current_servc) {
2234
2235 case HWC_CMDW_WRITEMASK:
2236
2237 write_event_mask_2 (ext_int_param);
2238 break;
2239
2240 case HWC_CMDW_WRITEDATA:
2241
2242 write_event_data_2 (ext_int_param);
2243 break;
2244
2245 case HWC_CMDW_READDATA:
2246
2247 unconditional_read_2 (ext_int_param);
2248 break;
2249 default:
2250 }
2251 }
2252 }
2253 } else {
2254
2255 if (hwc_data.current_hwcb) {
2256 internal_print (
2257 DELAYED_WRITE,
2258 HWC_RW_PRINT_HEADER
2259 "interrupt: mismatch: "
2260 "ext. int. param. (0x%x) vs. "
2261 "current HWCB (0x%x)\n",
2262 ext_int_param,
2263 hwc_data.current_hwcb);
2264 }
2265 }
2266
2267 if (evbuf_pending) {
2268
2269 unconditional_read_1 ();
2270 } else {
2271
2272 write_event_data_1 ();
2273 }
2274
2275 if (!hwc_data.calls || !hwc_data.calls->wake_up)
2276 return;
2277 (hwc_data.calls->wake_up) ();
2278 }
2279
2280 void
hwc_interrupt_handler(struct pt_regs * regs,__u16 code)2281 hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
2282 {
2283 int cpu = smp_processor_id ();
2284
2285 u32 ext_int_param = hwc_ext_int_param ();
2286
2287 irq_enter (cpu, 0x2401);
2288
2289 if (hwc_data.flags & HWC_INIT) {
2290
2291 hwc_data.flags |= HWC_INTERRUPT;
2292 } else if (hwc_data.flags & HWC_BROKEN) {
2293
2294 if (!do_hwc_init ()) {
2295 hwc_data.flags &= ~HWC_BROKEN;
2296 internal_print (DELAYED_WRITE,
2297 HWC_RW_PRINT_HEADER
2298 "delayed HWC setup after"
2299 " temporary breakdown"
2300 " (ext. int. parameter=0x%x)\n",
2301 ext_int_param);
2302 }
2303 } else {
2304 spin_lock (&hwc_data.lock);
2305 hwc_do_interrupt (ext_int_param);
2306 spin_unlock (&hwc_data.lock);
2307 }
2308 irq_exit (cpu, 0x2401);
2309 }
2310
2311 void
hwc_unblank(void)2312 hwc_unblank (void)
2313 {
2314
2315 spin_lock (&hwc_data.lock);
2316 spin_unlock (&hwc_data.lock);
2317
2318 __ctl_store (cr0, 0, 0);
2319 cr0_save = cr0;
2320 cr0 |= 0x00000200;
2321 cr0 &= 0xFFFFF3AC;
2322 __ctl_load (cr0, 0, 0);
2323
2324 asm volatile ("STOSM %0,0x01":"=m" (psw_mask)::"memory");
2325
2326 while (ALL_HWCB_CHAR)
2327 barrier ();
2328
2329 asm volatile ("STNSM %0,0xFE":"=m" (psw_mask)::"memory");
2330
2331 __ctl_load (cr0_save, 0, 0);
2332 }
2333
2334 int
hwc_ioctl(unsigned int cmd,unsigned long arg)2335 hwc_ioctl (unsigned int cmd, unsigned long arg)
2336 {
2337 hwc_ioctls_t tmp = hwc_data.ioctls;
2338 int retval = 0;
2339 unsigned long flags;
2340 unsigned int obuf;
2341
2342 spin_lock_irqsave (&hwc_data.lock, flags);
2343
2344 switch (cmd) {
2345
2346 case TIOCHWCSHTAB:
2347 if (get_user (tmp.width_htab, (ioctl_htab_t *) arg))
2348 goto fault;
2349 break;
2350
2351 case TIOCHWCSECHO:
2352 if (get_user (tmp.echo, (ioctl_echo_t *) arg))
2353 goto fault;
2354 break;
2355
2356 case TIOCHWCSCOLS:
2357 if (get_user (tmp.columns, (ioctl_cols_t *) arg))
2358 goto fault;
2359 break;
2360
2361 case TIOCHWCSNL:
2362 if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
2363 goto fault;
2364 break;
2365
2366 case TIOCHWCSOBUF:
2367 if (get_user (obuf, (unsigned int *) arg))
2368 goto fault;
2369 if (obuf & 0xFFF)
2370 tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
2371 else
2372 tmp.max_hwcb = (obuf >> 12);
2373 break;
2374
2375 case TIOCHWCSCASE:
2376 if (get_user (tmp.tolower, (ioctl_case_t *) arg))
2377 goto fault;
2378 break;
2379
2380 case TIOCHWCSDELIM:
2381 if (get_user (tmp.delim, (ioctl_delim_t *) arg))
2382 goto fault;
2383 break;
2384
2385 case TIOCHWCSINIT:
2386 retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
2387 break;
2388
2389 case TIOCHWCGHTAB:
2390 if (put_user (tmp.width_htab, (ioctl_htab_t *) arg))
2391 goto fault;
2392 break;
2393
2394 case TIOCHWCGECHO:
2395 if (put_user (tmp.echo, (ioctl_echo_t *) arg))
2396 goto fault;
2397 break;
2398
2399 case TIOCHWCGCOLS:
2400 if (put_user (tmp.columns, (ioctl_cols_t *) arg))
2401 goto fault;
2402 break;
2403
2404 case TIOCHWCGNL:
2405 if (put_user (tmp.final_nl, (ioctl_nl_t *) arg))
2406 goto fault;
2407 break;
2408
2409 case TIOCHWCGOBUF:
2410 if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg))
2411 goto fault;
2412 break;
2413
2414 case TIOCHWCGKBUF:
2415 if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
2416 goto fault;
2417 break;
2418
2419 case TIOCHWCGCASE:
2420 if (put_user (tmp.tolower, (ioctl_case_t *) arg))
2421 goto fault;
2422 break;
2423
2424 case TIOCHWCGDELIM:
2425 if (put_user (tmp.delim, (ioctl_delim_t *) arg))
2426 goto fault;
2427 break;
2428 #if 0
2429
2430 case TIOCHWCGINIT:
2431 if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
2432 goto fault;
2433 break;
2434
2435 case TIOCHWCGCURR:
2436 if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
2437 goto fault;
2438 break;
2439 #endif
2440
2441 default:
2442 goto noioctlcmd;
2443 }
2444
2445 if (_IOC_DIR (cmd) == _IOC_WRITE)
2446 retval = set_hwc_ioctls (&tmp, 0);
2447
2448 goto out;
2449
2450 fault:
2451 retval = -EFAULT;
2452 goto out;
2453 noioctlcmd:
2454 retval = -ENOIOCTLCMD;
2455 out:
2456 spin_unlock_irqrestore (&hwc_data.lock, flags);
2457 return retval;
2458 }
2459