xref: /freebsd/sys/powerpc/powerpc/intr_machdep.c (revision e0c4386e)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1991 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * William Jolitz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*-
35  * Copyright (c) 2002 Benno Rice.
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  *	form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
59  */
60 
61 #include "opt_isa.h"
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/queue.h>
67 #include <sys/bus.h>
68 #include <sys/cpuset.h>
69 #include <sys/interrupt.h>
70 #include <sys/ktr.h>
71 #include <sys/lock.h>
72 #include <sys/malloc.h>
73 #include <sys/mutex.h>
74 #include <sys/pcpu.h>
75 #include <sys/smp.h>
76 #include <sys/syslog.h>
77 #include <sys/vmmeter.h>
78 #include <sys/proc.h>
79 
80 #include <machine/frame.h>
81 #include <machine/intr_machdep.h>
82 #include <machine/md_var.h>
83 #include <machine/smp.h>
84 #include <machine/trap.h>
85 
86 #include "pic_if.h"
87 
88 static MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
89 
90 struct powerpc_intr {
91 	struct intr_event *event;
92 	long	*cntp;
93 	void	*priv;		/* PIC-private data */
94 	device_t pic;
95 	u_int	irq;
96 	u_int	intline;
97 	u_int	vector;
98 	u_int	cntindex;
99 	int	fwcode;
100 	int	ipi;
101 	int	pi_domain;
102 	enum intr_trigger trig;
103 	enum intr_polarity pol;
104 	cpuset_t pi_cpuset;
105 };
106 
107 struct pic {
108 	device_t dev;
109 	uint32_t node;
110 	u_int	irqs;
111 	u_int	ipis;
112 	int	base;
113 };
114 
115 static u_int intrcnt_index = 0;
116 static struct mtx intr_table_lock;
117 static struct powerpc_intr **powerpc_intrs;
118 static struct pic piclist[MAX_PICS];
119 static u_int nvectors;		/* Allocated vectors */
120 static u_int npics;		/* PICs registered */
121 #ifdef DEV_ISA
122 static u_int nirqs = 16;	/* Allocated IRQS (ISA pre-allocated). */
123 #else
124 static u_int nirqs = 0;		/* Allocated IRQs. */
125 #endif
126 static u_int stray_count;
127 
128 #define	INTRNAME_LEN	(MAXCOMLEN + 1)
129 u_long *intrcnt;
130 char *intrnames;
131 size_t sintrcnt = sizeof(intrcnt);
132 size_t sintrnames = sizeof(intrnames);
133 int nintrcnt;
134 
135 /*
136  * Just to start
137  */
138 #ifdef __powerpc64__
139 u_int num_io_irqs = 768;
140 #else
141 u_int num_io_irqs = 256;
142 #endif
143 
144 device_t root_pic;
145 
146 #ifdef SMP
147 static void *ipi_cookie;
148 #endif
149 
150 static void
151 intrcnt_setname(const char *name, int index)
152 {
153 
154 	snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s",
155 	    INTRNAME_LEN - 1, name);
156 }
157 
158 static void
159 intr_init(void *dummy __unused)
160 {
161 
162 	mtx_init(&intr_table_lock, "intr sources lock", NULL, MTX_DEF);
163 }
164 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
165 
166 static void
167 intr_init_sources(void *arg __unused)
168 {
169 
170 	powerpc_intrs = mallocarray(num_io_irqs, sizeof(*powerpc_intrs),
171 	    M_INTR, M_WAITOK | M_ZERO);
172 	nintrcnt = 1 + num_io_irqs * 2 + mp_ncpus * 2;
173 #ifdef COUNT_IPIS
174 	if (mp_ncpus > 1)
175 		nintrcnt += 8 * mp_ncpus;
176 #endif
177 	intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTR, M_WAITOK |
178 	    M_ZERO);
179 	intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTR, M_WAITOK |
180 	    M_ZERO);
181 	sintrcnt = nintrcnt * sizeof(u_long);
182 	sintrnames = nintrcnt * INTRNAME_LEN;
183 
184 	intrcnt_setname("???", 0);
185 	intrcnt_index = 1;
186 }
187 /*
188  * This needs to happen before SI_SUB_CPU
189  */
190 SYSINIT(intr_init_sources, SI_SUB_KLD, SI_ORDER_ANY, intr_init_sources, NULL);
191 
192 #ifdef SMP
193 static void
194 smp_intr_init(void *dummy __unused)
195 {
196 	struct powerpc_intr *i;
197 	int vector;
198 
199 	for (vector = 0; vector < nvectors; vector++) {
200 		i = powerpc_intrs[vector];
201 		if (i != NULL && i->event != NULL && i->pic == root_pic)
202 			PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
203 	}
204 }
205 SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL);
206 #endif
207 
208 void
209 intrcnt_add(const char *name, u_long **countp)
210 {
211 	int idx;
212 
213 	idx = atomic_fetchadd_int(&intrcnt_index, 1);
214 	KASSERT(idx < nintrcnt, ("intrcnt_add: Interrupt counter index %d/%d"
215 		"reached nintrcnt : %d", intrcnt_index, idx, nintrcnt));
216 	*countp = &intrcnt[idx];
217 	intrcnt_setname(name, idx);
218 }
219 
220 extern void kdb_backtrace(void);
221 static struct powerpc_intr *
222 intr_lookup(u_int irq)
223 {
224 	char intrname[16];
225 	struct powerpc_intr *i, *iscan;
226 	int vector;
227 
228 	mtx_lock(&intr_table_lock);
229 	for (vector = 0; vector < nvectors; vector++) {
230 		i = powerpc_intrs[vector];
231 		if (i != NULL && i->irq == irq) {
232 			mtx_unlock(&intr_table_lock);
233 			return (i);
234 		}
235 	}
236 
237 	i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
238 	if (i == NULL) {
239 		mtx_unlock(&intr_table_lock);
240 		return (NULL);
241 	}
242 
243 	i->event = NULL;
244 	i->cntp = NULL;
245 	i->priv = NULL;
246 	i->trig = INTR_TRIGGER_CONFORM;
247 	i->pol = INTR_POLARITY_CONFORM;
248 	i->irq = irq;
249 	i->pic = NULL;
250 	i->vector = -1;
251 	i->fwcode = 0;
252 	i->ipi = 0;
253 
254 #ifdef SMP
255 	i->pi_cpuset = all_cpus;
256 #else
257 	CPU_SETOF(0, &i->pi_cpuset);
258 #endif
259 
260 	for (vector = 0; vector < num_io_irqs && vector <= nvectors;
261 	    vector++) {
262 		iscan = powerpc_intrs[vector];
263 		if (iscan != NULL && iscan->irq == irq)
264 			break;
265 		if (iscan == NULL && i->vector == -1)
266 			i->vector = vector;
267 		iscan = NULL;
268 	}
269 
270 	if (iscan == NULL && i->vector != -1) {
271 		powerpc_intrs[i->vector] = i;
272 		i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1);
273 		i->cntp = &intrcnt[i->cntindex];
274 		sprintf(intrname, "irq%u:", i->irq);
275 		intrcnt_setname(intrname, i->cntindex);
276 		nvectors++;
277 	}
278 	mtx_unlock(&intr_table_lock);
279 
280 	if (iscan != NULL || i->vector == -1) {
281 		free(i, M_INTR);
282 		i = iscan;
283 	}
284 
285 	return (i);
286 }
287 
288 static int
289 powerpc_map_irq(struct powerpc_intr *i)
290 {
291 	struct pic *p;
292 	u_int cnt;
293 	int idx;
294 
295 	for (idx = 0; idx < npics; idx++) {
296 		p = &piclist[idx];
297 		cnt = p->irqs + p->ipis;
298 		if (i->irq >= p->base && i->irq < p->base + cnt)
299 			break;
300 	}
301 	if (idx == npics)
302 		return (EINVAL);
303 
304 	i->intline = i->irq - p->base;
305 	i->pic = p->dev;
306 
307 	/* Try a best guess if that failed */
308 	if (i->pic == NULL)
309 		i->pic = root_pic;
310 
311 	return (0);
312 }
313 
314 static void
315 powerpc_intr_eoi(void *arg)
316 {
317 	struct powerpc_intr *i = arg;
318 
319 	PIC_EOI(i->pic, i->intline, i->priv);
320 }
321 
322 static void
323 powerpc_intr_pre_ithread(void *arg)
324 {
325 	struct powerpc_intr *i = arg;
326 
327 	PIC_MASK(i->pic, i->intline, i->priv);
328 	PIC_EOI(i->pic, i->intline, i->priv);
329 }
330 
331 static void
332 powerpc_intr_post_ithread(void *arg)
333 {
334 	struct powerpc_intr *i = arg;
335 
336 	PIC_UNMASK(i->pic, i->intline, i->priv);
337 }
338 
339 static int
340 powerpc_assign_intr_cpu(void *arg, int cpu)
341 {
342 #ifdef SMP
343 	struct powerpc_intr *i = arg;
344 
345 	if (cpu == NOCPU)
346 		i->pi_cpuset = all_cpus;
347 	else
348 		CPU_SETOF(cpu, &i->pi_cpuset);
349 
350 	if (!cold && i->pic != NULL && i->pic == root_pic)
351 		PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
352 
353 	return (0);
354 #else
355 	return (EOPNOTSUPP);
356 #endif
357 }
358 
359 u_int
360 powerpc_register_pic(device_t dev, uint32_t node, u_int irqs, u_int ipis,
361     u_int atpic)
362 {
363 	struct pic *p;
364 	u_int irq;
365 	int idx;
366 
367 	mtx_lock(&intr_table_lock);
368 
369 	/* XXX see powerpc_get_irq(). */
370 	for (idx = 0; idx < npics; idx++) {
371 		p = &piclist[idx];
372 		if (p->node != node)
373 			continue;
374 		if (node != 0 || p->dev == dev)
375 			break;
376 	}
377 	p = &piclist[idx];
378 
379 	p->dev = dev;
380 	p->node = node;
381 	p->irqs = irqs;
382 	p->ipis = ipis;
383 	if (idx == npics) {
384 #ifdef DEV_ISA
385 		p->base = (atpic) ? 0 : nirqs;
386 #else
387 		p->base = nirqs;
388 #endif
389 		irq = p->base + irqs + ipis;
390 		nirqs = MAX(nirqs, irq);
391 		npics++;
392 	}
393 
394 	KASSERT(npics < MAX_PICS,
395 	    ("Number of PICs exceeds maximum (%d)", MAX_PICS));
396 
397 	mtx_unlock(&intr_table_lock);
398 
399 	return (p->base);
400 }
401 
402 u_int
403 powerpc_get_irq(uint32_t node, u_int pin)
404 {
405 	int idx;
406 
407 	if (node == 0)
408 		return (pin);
409 
410 	mtx_lock(&intr_table_lock);
411 	for (idx = 0; idx < npics; idx++) {
412 		if (piclist[idx].node == node) {
413 			mtx_unlock(&intr_table_lock);
414 			return (piclist[idx].base + pin);
415 		}
416 	}
417 
418 	/*
419 	 * XXX we should never encounter an unregistered PIC, but that
420 	 * can only be done when we properly support bus enumeration
421 	 * using multiple passes. Until then, fake an entry and give it
422 	 * some adhoc maximum number of IRQs and IPIs.
423 	 */
424 	piclist[idx].dev = NULL;
425 	piclist[idx].node = node;
426 	piclist[idx].irqs = 124;
427 	piclist[idx].ipis = 4;
428 	piclist[idx].base = nirqs;
429 	nirqs += (1 << 25);
430 	npics++;
431 
432 	KASSERT(npics < MAX_PICS,
433 	    ("Number of PICs exceeds maximum (%d)", MAX_PICS));
434 
435 	mtx_unlock(&intr_table_lock);
436 
437 	return (piclist[idx].base + pin);
438 }
439 
440 int
441 powerpc_enable_intr(void)
442 {
443 	struct powerpc_intr *i;
444 	int error, vector;
445 #ifdef SMP
446 	int n;
447 #endif
448 
449 	if (npics == 0)
450 		panic("no PIC detected\n");
451 
452 	if (root_pic == NULL)
453 		root_pic = piclist[0].dev;
454 
455 	KASSERT(root_pic != NULL, ("no root PIC!"));
456 
457 #ifdef SMP
458 	/* Install an IPI handler. */
459 	if (mp_ncpus > 1) {
460 		for (n = 0; n < npics; n++) {
461 			if (piclist[n].dev != root_pic)
462 				continue;
463 
464 			KASSERT(piclist[n].ipis != 0,
465 			    ("%s: SMP root PIC does not supply any IPIs",
466 			    __func__));
467 			error = powerpc_setup_intr("IPI",
468 			    MAP_IRQ(piclist[n].node, piclist[n].irqs),
469 			    powerpc_ipi_handler, NULL, NULL,
470 			    INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie,
471 			    0 /* domain XXX */);
472 			if (error) {
473 				printf("unable to setup IPI handler\n");
474 				return (error);
475 			}
476 
477 			/*
478 			 * Some subterfuge: disable late EOI and mark this
479 			 * as an IPI to the dispatch layer.
480 			 */
481 			i = intr_lookup(MAP_IRQ(piclist[n].node,
482 			    piclist[n].irqs));
483 			i->event->ie_post_filter = NULL;
484 			i->ipi = 1;
485 		}
486 	}
487 #endif
488 
489 	for (vector = 0; vector < nvectors; vector++) {
490 		i = powerpc_intrs[vector];
491 		if (i == NULL)
492 			continue;
493 
494 		error = powerpc_map_irq(i);
495 		if (error)
496 			continue;
497 
498 		if (i->trig == INTR_TRIGGER_INVALID)
499 			PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode,
500 			    &i->trig, &i->pol);
501 		if (i->trig != INTR_TRIGGER_CONFORM ||
502 		    i->pol != INTR_POLARITY_CONFORM)
503 			PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
504 
505 		if (i->event != NULL)
506 			PIC_ENABLE(i->pic, i->intline, vector, &i->priv);
507 	}
508 
509 	return (0);
510 }
511 
512 int
513 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
514     driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep,
515     int domain)
516 {
517 	struct powerpc_intr *i;
518 	int error, enable = 0;
519 
520 	i = intr_lookup(irq);
521 	if (i == NULL)
522 		return (ENOMEM);
523 
524 	if (i->event == NULL) {
525 		error = intr_event_create(&i->event, (void *)i, 0, irq,
526 		    powerpc_intr_pre_ithread, powerpc_intr_post_ithread,
527 		    powerpc_intr_eoi, powerpc_assign_intr_cpu, "irq%u:", irq);
528 		if (error)
529 			return (error);
530 
531 		enable = 1;
532 	}
533 
534 	error = intr_event_add_handler(i->event, name, filter, handler, arg,
535 	    intr_priority(flags), flags, cookiep);
536 	if (error)
537 		return (error);
538 	i->pi_domain = domain;
539 	if (strcmp(name, "IPI") != 0)  {
540 		CPU_ZERO(&i->pi_cpuset);
541 		CPU_COPY(&cpuset_domain[domain], &i->pi_cpuset);
542 	}
543 	mtx_lock(&intr_table_lock);
544 	intrcnt_setname(i->event->ie_fullname, i->cntindex);
545 	mtx_unlock(&intr_table_lock);
546 
547 	if (!cold) {
548 		error = powerpc_map_irq(i);
549 
550 		if (!error) {
551 			if (i->trig == INTR_TRIGGER_INVALID)
552 				PIC_TRANSLATE_CODE(i->pic, i->intline,
553 				    i->fwcode, &i->trig, &i->pol);
554 
555 			if (i->trig != INTR_TRIGGER_CONFORM ||
556 			    i->pol != INTR_POLARITY_CONFORM)
557 				PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
558 
559 			if (i->pic == root_pic)
560 				PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
561 
562 			if (enable)
563 				PIC_ENABLE(i->pic, i->intline, i->vector,
564 				    &i->priv);
565 		}
566 	}
567 	return (error);
568 }
569 
570 int
571 powerpc_teardown_intr(void *cookie)
572 {
573 
574 	return (intr_event_remove_handler(cookie));
575 }
576 
577 #ifdef SMP
578 int
579 powerpc_bind_intr(u_int irq, u_char cpu)
580 {
581 	struct powerpc_intr *i;
582 
583 	i = intr_lookup(irq);
584 	if (i == NULL)
585 		return (ENOMEM);
586 
587 	return (intr_event_bind(i->event, cpu));
588 }
589 #endif
590 
591 int
592 powerpc_fw_config_intr(int irq, int sense_code)
593 {
594 	struct powerpc_intr *i;
595 
596 	i = intr_lookup(irq);
597 	if (i == NULL)
598 		return (ENOMEM);
599 
600 	i->trig = INTR_TRIGGER_INVALID;
601 	i->pol = INTR_POLARITY_CONFORM;
602 	i->fwcode = sense_code;
603 
604 	if (!cold && i->pic != NULL) {
605 		PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig,
606 		    &i->pol);
607 		PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
608 	}
609 
610 	return (0);
611 }
612 
613 int
614 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
615 {
616 	struct powerpc_intr *i;
617 
618 	i = intr_lookup(irq);
619 	if (i == NULL)
620 		return (ENOMEM);
621 
622 	i->trig = trig;
623 	i->pol = pol;
624 
625 	if (!cold && i->pic != NULL)
626 		PIC_CONFIG(i->pic, i->intline, trig, pol);
627 
628 	return (0);
629 }
630 
631 void
632 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
633 {
634 	struct powerpc_intr *i;
635 	struct intr_event *ie;
636 
637 	i = powerpc_intrs[vector];
638 	if (i == NULL)
639 		goto stray;
640 
641 	(*i->cntp)++;
642 
643 	ie = i->event;
644 	KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
645 
646 	/*
647 	 * IPIs are magical and need to be EOI'ed before filtering.
648 	 * This prevents races in IPI handling.
649 	 */
650 	if (i->ipi)
651 		PIC_EOI(i->pic, i->intline, i->priv);
652 
653 	if (intr_event_handle(ie, tf) != 0) {
654 		goto stray;
655 	}
656 	return;
657 
658 stray:
659 	stray_count++;
660 	if (stray_count <= INTR_STRAY_LOG_MAX) {
661 		printf("stray irq %d\n", i ? i->irq : -1);
662 		if (stray_count >= INTR_STRAY_LOG_MAX) {
663 			printf("got %d stray interrupts, not logging anymore\n",
664 			    INTR_STRAY_LOG_MAX);
665 		}
666 	}
667 	if (i != NULL)
668 		PIC_MASK(i->pic, i->intline, i->priv);
669 }
670 
671 void
672 powerpc_intr_mask(u_int irq)
673 {
674 	struct powerpc_intr *i;
675 
676 	i = intr_lookup(irq);
677 	if (i == NULL || i->pic == NULL)
678 		return;
679 
680 	PIC_MASK(i->pic, i->intline, i->priv);
681 }
682 
683 void
684 powerpc_intr_unmask(u_int irq)
685 {
686 	struct powerpc_intr *i;
687 
688 	i = intr_lookup(irq);
689 	if (i == NULL || i->pic == NULL)
690 		return;
691 
692 	PIC_UNMASK(i->pic, i->intline, i->priv);
693 }
694