Home | History | Annotate | Line # | Download | only in pic
intr.c revision 1.15
      1  1.15      matt /*	$NetBSD: intr.c,v 1.15 2011/06/17 23:36:18 matt Exp $ */
      2   1.2   garbled 
      3   1.2   garbled /*-
      4   1.2   garbled  * Copyright (c) 2007 Michael Lorenz
      5   1.2   garbled  * All rights reserved.
      6   1.2   garbled  *
      7   1.2   garbled  * Redistribution and use in source and binary forms, with or without
      8   1.2   garbled  * modification, are permitted provided that the following conditions
      9   1.2   garbled  * are met:
     10   1.2   garbled  * 1. Redistributions of source code must retain the above copyright
     11   1.2   garbled  *    notice, this list of conditions and the following disclaimer.
     12   1.2   garbled  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.2   garbled  *    notice, this list of conditions and the following disclaimer in the
     14   1.2   garbled  *    documentation and/or other materials provided with the distribution.
     15   1.2   garbled  *
     16   1.2   garbled  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17   1.2   garbled  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18   1.2   garbled  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19   1.2   garbled  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20   1.2   garbled  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21   1.2   garbled  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22   1.2   garbled  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23   1.2   garbled  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24   1.2   garbled  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25   1.2   garbled  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26   1.2   garbled  * POSSIBILITY OF SUCH DAMAGE.
     27   1.2   garbled  */
     28   1.2   garbled 
     29   1.2   garbled #include <sys/cdefs.h>
     30  1.15      matt __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.15 2011/06/17 23:36:18 matt Exp $");
     31   1.2   garbled 
     32   1.2   garbled #include "opt_multiprocessor.h"
     33   1.2   garbled 
     34  1.12  macallan #define __INTR_PRIVATE
     35  1.12  macallan 
     36   1.2   garbled #include <sys/param.h>
     37   1.2   garbled #include <sys/malloc.h>
     38   1.2   garbled #include <sys/kernel.h>
     39   1.3        ad #include <sys/cpu.h>
     40   1.2   garbled 
     41   1.2   garbled #include <arch/powerpc/pic/picvar.h>
     42   1.2   garbled #include "opt_pic.h"
     43   1.2   garbled #include "opt_interrupt.h"
     44   1.2   garbled #if defined(PIC_I8259) || defined (PIC_PREPIVR)
     45   1.2   garbled #include <machine/isa_machdep.h>
     46   1.2   garbled #endif
     47   1.2   garbled 
     48   1.2   garbled #ifdef MULTIPROCESSOR
     49   1.2   garbled #include <arch/powerpc/pic/ipivar.h>
     50   1.2   garbled #endif
     51   1.2   garbled 
     52  1.12  macallan #ifdef __HAVE_FAST_SOFTINTS
     53  1.12  macallan #include <powerpc/softint.h>
     54  1.12  macallan #endif
     55  1.12  macallan 
     56   1.2   garbled #define MAX_PICS	8	/* 8 PICs ought to be enough for everyone */
     57   1.2   garbled 
     58  1.15      matt #define	PIC_VIRQ_LEGAL_P(x)	((u_int)(x) < NVIRQ)
     59   1.2   garbled 
     60   1.2   garbled struct pic_ops *pics[MAX_PICS];
     61   1.2   garbled int num_pics = 0;
     62   1.2   garbled int max_base = 0;
     63  1.15      matt uint8_t	virq_map[NIRQ];
     64  1.15      matt imask_t virq_mask = HWIRQ_MASK;
     65   1.8  kiyohara imask_t	imask[NIPL];
     66   1.2   garbled int	primary_pic = 0;
     67   1.2   garbled 
     68   1.2   garbled static int	fakeintr(void *);
     69  1.15      matt static int	mapirq(int);
     70   1.2   garbled static void	intr_calculatemasks(void);
     71  1.15      matt static struct pic_ops *find_pic_by_hwirq(int);
     72   1.2   garbled 
     73   1.2   garbled static struct intr_source intrsources[NVIRQ];
     74   1.2   garbled 
     75   1.2   garbled void
     76   1.2   garbled pic_init(void)
     77   1.2   garbled {
     78  1.15      matt 	/* everything is in bss, no reason to zero it. */
     79   1.2   garbled }
     80   1.2   garbled 
     81   1.2   garbled int
     82   1.2   garbled pic_add(struct pic_ops *pic)
     83   1.2   garbled {
     84   1.2   garbled 
     85   1.2   garbled 	if (num_pics >= MAX_PICS)
     86   1.2   garbled 		return -1;
     87   1.2   garbled 
     88   1.2   garbled 	pics[num_pics] = pic;
     89   1.2   garbled 	pic->pic_intrbase = max_base;
     90   1.2   garbled 	max_base += pic->pic_numintrs;
     91   1.2   garbled 	num_pics++;
     92   1.7  kiyohara 
     93   1.2   garbled 	return pic->pic_intrbase;
     94   1.2   garbled }
     95   1.2   garbled 
     96   1.2   garbled void
     97   1.2   garbled pic_finish_setup(void)
     98   1.2   garbled {
     99  1.15      matt 	for (size_t i = 0; i < num_pics; i++) {
    100  1.15      matt 		struct pic_ops * const pic = pics[i];
    101   1.2   garbled 		if (pic->pic_finish_setup != NULL)
    102   1.2   garbled 			pic->pic_finish_setup(pic);
    103   1.2   garbled 	}
    104   1.2   garbled }
    105   1.2   garbled 
    106   1.2   garbled static struct pic_ops *
    107  1.15      matt find_pic_by_hwirq(int hwirq)
    108   1.2   garbled {
    109  1.14      matt 	for (u_int base = 0; base < num_pics; base++) {
    110  1.14      matt 		struct pic_ops * const pic = pics[base];
    111  1.15      matt 		if (pic->pic_intrbase <= hwirq
    112  1.15      matt 		    && hwirq < pic->pic_intrbase + pic->pic_numintrs) {
    113  1.14      matt 			return pic;
    114   1.2   garbled 		}
    115   1.2   garbled 	}
    116   1.2   garbled 	return NULL;
    117   1.2   garbled }
    118   1.2   garbled 
    119   1.2   garbled static int
    120   1.2   garbled fakeintr(void *arg)
    121   1.2   garbled {
    122   1.2   garbled 
    123   1.2   garbled 	return 0;
    124   1.2   garbled }
    125   1.2   garbled 
    126   1.2   garbled /*
    127   1.2   garbled  * Register an interrupt handler.
    128   1.2   garbled  */
    129   1.2   garbled void *
    130  1.14      matt intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
    131   1.2   garbled     void *ih_arg)
    132   1.2   garbled {
    133   1.2   garbled 	struct intrhand **p, *q, *ih;
    134   1.2   garbled 	struct pic_ops *pic;
    135   1.2   garbled 	static struct intrhand fakehand;
    136  1.15      matt 	int maxipl = ipl;
    137   1.2   garbled 
    138  1.14      matt 	if (maxipl == IPL_NONE)
    139  1.14      matt 		maxipl = IPL_HIGH;
    140   1.2   garbled 
    141   1.2   garbled 	if (hwirq >= max_base) {
    142   1.2   garbled 		panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
    143   1.2   garbled 		    max_base - 1);
    144   1.2   garbled 	}
    145   1.2   garbled 
    146  1.15      matt 	pic = find_pic_by_hwirq(hwirq);
    147   1.2   garbled 	if (pic == NULL) {
    148   1.2   garbled 
    149   1.2   garbled 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
    150   1.2   garbled 	}
    151   1.2   garbled 
    152  1.15      matt 	const int virq = mapirq(hwirq);
    153   1.2   garbled 
    154   1.2   garbled 	/* no point in sleeping unless someone can free memory. */
    155   1.2   garbled 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
    156   1.2   garbled 	if (ih == NULL)
    157   1.2   garbled 		panic("intr_establish: can't malloc handler info");
    158   1.2   garbled 
    159  1.15      matt 	if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE)
    160  1.15      matt 		panic("intr_establish: bogus irq (%d) or type (%d)",
    161  1.15      matt 		    hwirq, type);
    162   1.2   garbled 
    163  1.15      matt 	struct intr_source * const is = &intrsources[virq];
    164   1.2   garbled 
    165   1.2   garbled 	switch (is->is_type) {
    166   1.2   garbled 	case IST_NONE:
    167   1.2   garbled 		is->is_type = type;
    168   1.2   garbled 		break;
    169   1.2   garbled 	case IST_EDGE:
    170   1.2   garbled 	case IST_LEVEL:
    171   1.2   garbled 		if (type == is->is_type)
    172   1.2   garbled 			break;
    173  1.15      matt 		/* FALLTHROUGH */
    174   1.2   garbled 	case IST_PULSE:
    175   1.2   garbled 		if (type != IST_NONE)
    176   1.2   garbled 			panic("intr_establish: can't share %s with %s",
    177   1.2   garbled 			    intr_typename(is->is_type),
    178   1.2   garbled 			    intr_typename(type));
    179   1.2   garbled 		break;
    180   1.2   garbled 	}
    181   1.2   garbled 	if (is->is_hand == NULL) {
    182   1.2   garbled 		snprintf(is->is_source, sizeof(is->is_source), "irq %d",
    183   1.2   garbled 		    is->is_hwirq);
    184   1.2   garbled 		evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
    185   1.2   garbled 		    pic->pic_name, is->is_source);
    186   1.2   garbled 	}
    187   1.2   garbled 
    188   1.2   garbled 	/*
    189   1.2   garbled 	 * Figure out where to put the handler.
    190   1.2   garbled 	 * This is O(N^2), but we want to preserve the order, and N is
    191   1.2   garbled 	 * generally small.
    192   1.2   garbled 	 */
    193   1.2   garbled 	for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
    194  1.14      matt 		maxipl = max(maxipl, q->ih_ipl);
    195   1.2   garbled 	}
    196   1.2   garbled 
    197   1.2   garbled 	/*
    198   1.2   garbled 	 * Actually install a fake handler momentarily, since we might be doing
    199   1.2   garbled 	 * this with interrupts enabled and don't want the real routine called
    200   1.2   garbled 	 * until masking is set up.
    201   1.2   garbled 	 */
    202  1.14      matt 	fakehand.ih_ipl = ipl;
    203   1.2   garbled 	fakehand.ih_fun = fakeintr;
    204   1.2   garbled 	*p = &fakehand;
    205   1.2   garbled 
    206   1.2   garbled 	/*
    207   1.2   garbled 	 * Poke the real handler in now.
    208   1.2   garbled 	 */
    209   1.2   garbled 	ih->ih_fun = ih_fun;
    210   1.2   garbled 	ih->ih_arg = ih_arg;
    211   1.2   garbled 	ih->ih_next = NULL;
    212  1.14      matt 	ih->ih_ipl = ipl;
    213  1.15      matt 	ih->ih_virq = virq;
    214   1.2   garbled 	*p = ih;
    215   1.2   garbled 
    216   1.2   garbled 	if (pic->pic_establish_irq != NULL)
    217   1.2   garbled 		pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
    218  1.14      matt 		    is->is_type, maxipl);
    219  1.14      matt 
    220  1.14      matt 	/*
    221  1.14      matt 	 * Remember the highest IPL used by this handler.
    222  1.14      matt 	 */
    223  1.14      matt 	is->is_ipl = maxipl;
    224   1.2   garbled 
    225   1.2   garbled 	/*
    226   1.2   garbled 	 * now that the handler is established we're actually ready to
    227   1.2   garbled 	 * calculate the masks
    228   1.2   garbled 	 */
    229   1.2   garbled 	intr_calculatemasks();
    230   1.2   garbled 
    231   1.2   garbled 
    232   1.2   garbled 	return ih;
    233   1.2   garbled }
    234   1.2   garbled 
    235   1.2   garbled void
    236   1.2   garbled dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
    237   1.2   garbled {
    238   1.2   garbled }
    239   1.2   garbled 
    240   1.2   garbled /*
    241   1.2   garbled  * Deregister an interrupt handler.
    242   1.2   garbled  */
    243   1.2   garbled void
    244   1.2   garbled intr_disestablish(void *arg)
    245   1.2   garbled {
    246  1.14      matt 	struct intrhand * const ih = arg;
    247  1.15      matt 	const int virq = ih->ih_virq;
    248  1.15      matt 	struct intr_source * const is = &intrsources[virq];
    249  1.14      matt 	struct intrhand **p, **q;
    250  1.14      matt 	int maxipl = IPL_NONE;
    251   1.2   garbled 
    252  1.15      matt 	if (!PIC_VIRQ_LEGAL_P(virq))
    253  1.15      matt 		panic("intr_disestablish: bogus virq %d", virq);
    254   1.2   garbled 
    255   1.2   garbled 	/*
    256   1.2   garbled 	 * Remove the handler from the chain.
    257   1.2   garbled 	 * This is O(n^2), too.
    258   1.2   garbled 	 */
    259  1.14      matt 	for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) {
    260  1.14      matt 		struct intrhand * const tmp_ih = *p;
    261  1.14      matt 		if (tmp_ih == ih) {
    262  1.14      matt 			q = p;
    263  1.14      matt 		} else {
    264  1.14      matt 			maxipl = max(maxipl, tmp_ih->ih_ipl);
    265  1.14      matt 		}
    266  1.14      matt 	}
    267   1.2   garbled 	if (q)
    268  1.14      matt 		*q = ih->ih_next;
    269   1.2   garbled 	else
    270   1.2   garbled 		panic("intr_disestablish: handler not registered");
    271   1.2   garbled 	free((void *)ih, M_DEVBUF);
    272   1.2   garbled 
    273  1.14      matt 	/*
    274  1.14      matt 	 * Reset the IPL for this source now that we've removed a handler.
    275  1.14      matt 	 */
    276  1.14      matt 	is->is_ipl = maxipl;
    277  1.14      matt 
    278   1.2   garbled 	intr_calculatemasks();
    279   1.2   garbled 
    280   1.2   garbled 	if (is->is_hand == NULL) {
    281   1.2   garbled 		is->is_type = IST_NONE;
    282   1.2   garbled 		evcnt_detach(&is->is_ev);
    283  1.15      matt 		/*
    284  1.15      matt 		 * Make the virutal IRQ available again.
    285  1.15      matt 		 */
    286  1.15      matt 		virq_map[virq] = 0;
    287  1.15      matt 		virq_mask |= PIC_VIRQ_TO_MASK(virq);
    288   1.2   garbled 	}
    289   1.2   garbled }
    290   1.2   garbled 
    291   1.2   garbled /*
    292   1.2   garbled  * Map max_base irqs into 32 (bits).
    293   1.2   garbled  */
    294   1.2   garbled static int
    295  1.15      matt mapirq(int hwirq)
    296   1.2   garbled {
    297   1.2   garbled 	struct pic_ops *pic;
    298   1.2   garbled 
    299  1.15      matt 	if (hwirq >= max_base)
    300  1.15      matt 		panic("invalid irq %d", hwirq);
    301   1.2   garbled 
    302  1.15      matt 	if ((pic = find_pic_by_hwirq(hwirq)) == NULL)
    303  1.15      matt 		panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq);
    304   1.2   garbled 
    305  1.15      matt 	if (virq_map[hwirq])
    306  1.15      matt 		return virq_map[hwirq];
    307   1.2   garbled 
    308  1.15      matt 	if (virq_mask == 0)
    309   1.2   garbled 		panic("virq overflow");
    310   1.2   garbled 
    311  1.15      matt 	const int virq = PIC_VIRQ_MS_PENDING(virq_mask);
    312  1.15      matt 	struct intr_source * const is = intrsources + virq;
    313  1.15      matt 
    314  1.15      matt 	virq_mask &= ~PIC_VIRQ_TO_MASK(virq);
    315  1.15      matt 
    316  1.15      matt 	is->is_hwirq = hwirq;
    317  1.15      matt 	is->is_pic = pic;
    318  1.15      matt 	virq_map[hwirq] = virq;
    319   1.2   garbled #ifdef PIC_DEBUG
    320  1.15      matt 	printf("mapping hwirq %d to virq %d\n", irq, virq);
    321   1.2   garbled #endif
    322  1.15      matt 	return virq;
    323   1.2   garbled }
    324   1.2   garbled 
    325   1.2   garbled static const char * const intr_typenames[] = {
    326   1.2   garbled    [IST_NONE]  = "none",
    327   1.2   garbled    [IST_PULSE] = "pulsed",
    328   1.2   garbled    [IST_EDGE]  = "edge-triggered",
    329   1.2   garbled    [IST_LEVEL] = "level-triggered",
    330   1.2   garbled };
    331   1.2   garbled 
    332   1.2   garbled const char *
    333   1.2   garbled intr_typename(int type)
    334   1.2   garbled {
    335   1.2   garbled 	KASSERT((unsigned int) type < __arraycount(intr_typenames));
    336   1.2   garbled 	KASSERT(intr_typenames[type] != NULL);
    337   1.2   garbled 	return intr_typenames[type];
    338   1.2   garbled }
    339   1.2   garbled 
    340   1.2   garbled /*
    341   1.2   garbled  * Recalculate the interrupt masks from scratch.
    342   1.2   garbled  * We could code special registry and deregistry versions of this function that
    343   1.2   garbled  * would be faster, but the code would be nastier, and we don't expect this to
    344   1.2   garbled  * happen very much anyway.
    345   1.2   garbled  */
    346   1.2   garbled static void
    347   1.2   garbled intr_calculatemasks(void)
    348   1.2   garbled {
    349  1.14      matt 	imask_t newmask[NIPL] = { [IPL_NONE...IPL_HIGH] = 0 };
    350   1.2   garbled 	struct intr_source *is;
    351  1.14      matt 	int irq;
    352   1.2   garbled 
    353  1.14      matt 	for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) {
    354  1.14      matt 		newmask[ipl] = 0;
    355   1.2   garbled 	}
    356   1.2   garbled 
    357  1.14      matt 	/* First, figure out which ipl each IRQ uses. */
    358  1.14      matt 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    359  1.15      matt 		newmask[is->is_ipl] |= PIC_VIRQ_TO_MASK(irq);
    360   1.2   garbled 	}
    361   1.2   garbled 
    362   1.2   garbled 	/*
    363   1.2   garbled 	 * IPL_NONE is used for hardware interrupts that are never blocked,
    364   1.2   garbled 	 * and do not block anything else.
    365   1.2   garbled 	 */
    366  1.14      matt 	newmask[IPL_NONE] = 0;
    367   1.2   garbled 
    368   1.2   garbled 	/*
    369   1.2   garbled 	 * strict hierarchy - all IPLs block everything blocked by any lower
    370   1.2   garbled 	 * IPL
    371   1.2   garbled 	 */
    372  1.14      matt 	for (u_int ipl = 1; ipl < NIPL; ipl++) {
    373  1.14      matt 		newmask[ipl] |= newmask[ipl - 1];
    374  1.14      matt 	}
    375   1.2   garbled 
    376   1.2   garbled #ifdef DEBUG_IPL
    377  1.14      matt 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    378  1.14      matt 		printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]);
    379   1.2   garbled 	}
    380   1.2   garbled #endif
    381   1.2   garbled 
    382  1.14      matt 	/*
    383  1.14      matt 	 * Disable all interrupts.
    384  1.14      matt 	 */
    385  1.14      matt 	for (u_int base = 0; base < num_pics; base++) {
    386  1.14      matt 		struct pic_ops * const pic = pics[base];
    387  1.14      matt 		for (u_int i = 0; i < pic->pic_numintrs; i++) {
    388  1.14      matt 			pic->pic_disable_irq(pic, i);
    389  1.14      matt 		}
    390   1.2   garbled 	}
    391   1.2   garbled 
    392  1.14      matt 	/*
    393  1.14      matt 	 * Now that all interrupts are disabled, update the ipl masks.
    394  1.14      matt 	 */
    395  1.14      matt 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    396  1.14      matt 		imask[ipl] = newmask[ipl];
    397   1.2   garbled 	}
    398   1.7  kiyohara 
    399  1.14      matt 	/*
    400  1.14      matt 	 * Lastly, enable IRQs actually in use.
    401  1.14      matt 	 */
    402   1.2   garbled 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    403   1.2   garbled 		if (is->is_hand)
    404   1.2   garbled 			pic_enable_irq(is->is_hwirq);
    405   1.2   garbled 	}
    406   1.2   garbled }
    407   1.2   garbled 
    408   1.2   garbled void
    409  1.15      matt pic_enable_irq(int hwirq)
    410   1.2   garbled {
    411  1.15      matt 	struct pic_ops * const pic = find_pic_by_hwirq(hwirq);
    412  1.15      matt 	if (pic == NULL)
    413  1.15      matt 		panic("%s: bogus IRQ %d", __func__, hwirq);
    414  1.15      matt 	const int type = intrsources[virq_map[hwirq]].is_type;
    415  1.15      matt 	(*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type);
    416   1.2   garbled }
    417   1.2   garbled 
    418   1.2   garbled void
    419  1.15      matt pic_mark_pending(int hwirq)
    420   1.2   garbled {
    421   1.2   garbled 	struct cpu_info * const ci = curcpu();
    422   1.2   garbled 
    423  1.15      matt 	const int virq = virq_map[hwirq];
    424  1.15      matt 	if (virq == 0)
    425  1.15      matt 		printf("IRQ %d maps to 0\n", hwirq);
    426   1.2   garbled 
    427  1.15      matt 	const register_t msr = mfmsr();
    428   1.2   garbled 	mtmsr(msr & ~PSL_EE);
    429  1.15      matt 	ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq);
    430   1.2   garbled 	mtmsr(msr);
    431   1.7  kiyohara }
    432   1.2   garbled 
    433  1.15      matt static void
    434  1.15      matt intr_deliver(struct intr_source *is, int virq)
    435  1.15      matt {
    436  1.15      matt 	bool locked = false;
    437  1.15      matt 	for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
    438  1.15      matt 		KASSERTMSG(ih->ih_fun != NULL,
    439  1.15      matt 		    ("%s: irq %d, hwirq %d, is %p ih %p: "
    440  1.15      matt 		     "NULL interrupt handler!\n", __func__,
    441  1.15      matt 		     virq, is->is_hwirq, is, ih));
    442  1.15      matt 		if (ih->ih_ipl == IPL_VM) {
    443  1.15      matt 			if (!locked) {
    444  1.15      matt 				KERNEL_LOCK(1, NULL);
    445  1.15      matt 				locked = true;
    446  1.15      matt 			}
    447  1.15      matt 		} else if (locked) {
    448  1.15      matt 			KERNEL_UNLOCK_ONE(NULL);
    449  1.15      matt 			locked = false;
    450  1.15      matt 		}
    451  1.15      matt 		(*ih->ih_fun)(ih->ih_arg);
    452  1.15      matt 	}
    453  1.15      matt 	if (locked) {
    454  1.15      matt 		KERNEL_UNLOCK_ONE(NULL);
    455  1.15      matt 	}
    456  1.15      matt 	is->is_ev.ev_count++;
    457  1.15      matt }
    458  1.15      matt 
    459   1.2   garbled void
    460   1.2   garbled pic_do_pending_int(void)
    461   1.2   garbled {
    462   1.2   garbled 	struct cpu_info * const ci = curcpu();
    463  1.15      matt 	imask_t vpend;
    464   1.2   garbled 
    465   1.2   garbled 	if (ci->ci_iactive)
    466   1.2   garbled 		return;
    467   1.2   garbled 
    468   1.2   garbled 	ci->ci_iactive = 1;
    469  1.15      matt 
    470  1.15      matt 	const register_t emsr = mfmsr();
    471  1.15      matt 	const register_t dmsr = emsr & ~PSL_EE;
    472  1.15      matt 
    473   1.2   garbled 	KASSERT(emsr & PSL_EE);
    474   1.2   garbled 	mtmsr(dmsr);
    475   1.2   garbled 
    476  1.15      matt 	const int pcpl = ci->ci_cpl;
    477   1.3        ad #ifdef __HAVE_FAST_SOFTINTS
    478   1.2   garbled again:
    479   1.3        ad #endif
    480   1.2   garbled 
    481   1.2   garbled 	/* Do now unmasked pendings */
    482  1.15      matt 	while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) {
    483  1.14      matt 		ci->ci_idepth++;
    484  1.15      matt 		KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0);
    485  1.15      matt 
    486   1.8  kiyohara 		/* Get most significant pending bit */
    487  1.15      matt 		const int virq = PIC_VIRQ_MS_PENDING(vpend);
    488  1.15      matt 		ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq);
    489  1.15      matt 
    490  1.15      matt 		struct intr_source * const is = &intrsources[virq];
    491  1.15      matt 		struct pic_ops * const pic = is->is_pic;
    492   1.2   garbled 
    493  1.14      matt 		splraise(is->is_ipl);
    494   1.2   garbled 		mtmsr(emsr);
    495  1.15      matt 		intr_deliver(is, virq);
    496   1.2   garbled 		mtmsr(dmsr);
    497  1.15      matt 		ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
    498   1.2   garbled 
    499   1.2   garbled 		pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase,
    500   1.2   garbled 		    is->is_type);
    501  1.14      matt 		ci->ci_idepth--;
    502   1.2   garbled 	}
    503   1.2   garbled 
    504   1.3        ad #ifdef __HAVE_FAST_SOFTINTS
    505  1.12  macallan 	const u_int softints = (ci->ci_data.cpu_softints << pcpl) & IPL_SOFTMASK;
    506  1.12  macallan 
    507  1.12  macallan 	if (__predict_false(softints != 0)) {
    508  1.15      matt 		ci->ci_cpl = IPL_HIGH;
    509  1.15      matt 		mtmsr(emsr);
    510  1.12  macallan 		powerpc_softint(ci, pcpl,
    511  1.12  macallan 		    (vaddr_t)__builtin_return_address(0));
    512  1.15      matt 		mtmsr(dmsr);
    513  1.12  macallan 		ci->ci_cpl = pcpl;
    514  1.15      matt 		if (__predict_false(ci->ci_ipending & ~imask[pcpl]))
    515  1.15      matt 			goto again;
    516  1.12  macallan 	}
    517  1.12  macallan #endif
    518   1.2   garbled 
    519   1.2   garbled 	ci->ci_iactive = 0;
    520   1.2   garbled 	mtmsr(emsr);
    521   1.2   garbled }
    522   1.2   garbled 
    523   1.2   garbled int
    524   1.2   garbled pic_handle_intr(void *cookie)
    525   1.2   garbled {
    526   1.2   garbled 	struct pic_ops *pic = cookie;
    527   1.2   garbled 	struct cpu_info *ci = curcpu();
    528  1.15      matt 	int picirq;
    529   1.2   garbled 
    530  1.15      matt 	picirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
    531  1.15      matt 	if (picirq == 255)
    532   1.2   garbled 		return 0;
    533   1.2   garbled 
    534  1.15      matt 	const register_t msr = mfmsr();
    535  1.15      matt 	const int pcpl = ci->ci_cpl;
    536   1.2   garbled 
    537  1.15      matt 	do {
    538   1.2   garbled #ifdef MULTIPROCESSOR
    539  1.15      matt 		/* THIS IS WRONG XXX */
    540  1.15      matt 		if (picirq == ipiops.ppc_ipi_vector) {
    541  1.15      matt 			ci->ci_cpl = IPL_HIGH;
    542  1.15      matt 			ipi_intr(NULL);
    543  1.15      matt 			ci->ci_cpl = pcpl;
    544  1.15      matt 			pic->pic_ack_irq(pic, picirq);
    545  1.15      matt 			continue;
    546  1.15      matt 		}
    547   1.2   garbled #endif
    548   1.2   garbled 
    549  1.15      matt 		const int virq = virq_map[picirq + pic->pic_intrbase];
    550  1.15      matt 		KASSERT(virq != 0);
    551  1.15      matt 		KASSERT(picirq < pic->pic_numintrs);
    552  1.15      matt 		imask_t v_imen = PIC_VIRQ_TO_MASK(virq);
    553  1.15      matt 		struct intr_source * const is = &intrsources[virq];
    554  1.15      matt 
    555  1.15      matt 		if ((imask[pcpl] & v_imen) != 0) {
    556  1.15      matt 			ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */
    557  1.15      matt 			pic->pic_disable_irq(pic, picirq);
    558  1.15      matt 		} else {
    559  1.15      matt 			/* this interrupt is no longer pending */
    560  1.15      matt 			ci->ci_ipending &= ~v_imen;
    561  1.15      matt 			ci->ci_idepth++;
    562  1.15      matt 
    563  1.15      matt 			splraise(is->is_ipl);
    564  1.15      matt 			mtmsr(msr | PSL_EE);
    565  1.15      matt 			intr_deliver(is, virq);
    566  1.15      matt 			mtmsr(msr);
    567  1.15      matt 			ci->ci_cpl = pcpl;
    568   1.7  kiyohara 
    569  1.15      matt 			ci->ci_data.cpu_nintr++;
    570  1.15      matt 			ci->ci_idepth--;
    571   1.2   garbled 		}
    572  1.15      matt 		pic->pic_ack_irq(pic, picirq);
    573  1.15      matt 	} while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255);
    574   1.2   garbled 
    575   1.2   garbled 	mtmsr(msr | PSL_EE);
    576   1.2   garbled 	splx(pcpl);	/* Process pendings. */
    577   1.2   garbled 	mtmsr(msr);
    578   1.2   garbled 
    579   1.2   garbled 	return 0;
    580   1.2   garbled }
    581   1.2   garbled 
    582   1.2   garbled void
    583   1.2   garbled pic_ext_intr(void)
    584   1.2   garbled {
    585   1.2   garbled 
    586   1.2   garbled 	KASSERT(pics[primary_pic] != NULL);
    587   1.2   garbled 	pic_handle_intr(pics[primary_pic]);
    588   1.2   garbled 
    589   1.2   garbled 	return;
    590   1.2   garbled 
    591   1.2   garbled }
    592   1.2   garbled 
    593   1.2   garbled int
    594   1.2   garbled splraise(int ncpl)
    595   1.2   garbled {
    596   1.2   garbled 	struct cpu_info *ci = curcpu();
    597   1.2   garbled 	int ocpl;
    598   1.2   garbled 
    599  1.12  macallan 	if (ncpl == ci->ci_cpl) return ncpl;
    600   1.2   garbled 	__asm volatile("sync; eieio");	/* don't reorder.... */
    601   1.2   garbled 	ocpl = ci->ci_cpl;
    602  1.12  macallan 	KASSERT(ncpl < NIPL);
    603  1.12  macallan 	ci->ci_cpl = max(ncpl, ocpl);
    604   1.2   garbled 	__asm volatile("sync; eieio");	/* reorder protect */
    605  1.12  macallan 	__insn_barrier();
    606   1.2   garbled 	return ocpl;
    607   1.2   garbled }
    608   1.2   garbled 
    609  1.13      matt static inline bool
    610  1.13      matt have_pending_intr_p(struct cpu_info *ci, int ncpl)
    611  1.13      matt {
    612  1.13      matt 	if (ci->ci_ipending & ~imask[ncpl])
    613  1.13      matt 		return true;
    614  1.13      matt #ifdef __HAVE_FAST_SOFTINTS
    615  1.13      matt 	if ((ci->ci_data.cpu_softints << ncpl) & IPL_SOFTMASK)
    616  1.13      matt 		return true;
    617  1.13      matt #endif
    618  1.13      matt 	return false;
    619  1.13      matt }
    620  1.13      matt 
    621   1.2   garbled void
    622   1.2   garbled splx(int ncpl)
    623   1.2   garbled {
    624   1.2   garbled 	struct cpu_info *ci = curcpu();
    625   1.7  kiyohara 
    626  1.12  macallan 	__insn_barrier();
    627   1.2   garbled 	__asm volatile("sync; eieio");	/* reorder protect */
    628   1.2   garbled 	ci->ci_cpl = ncpl;
    629  1.13      matt 	if (have_pending_intr_p(ci, ncpl))
    630   1.2   garbled 		pic_do_pending_int();
    631  1.13      matt 
    632   1.2   garbled 	__asm volatile("sync; eieio");	/* reorder protect */
    633   1.2   garbled }
    634   1.2   garbled 
    635   1.2   garbled int
    636   1.2   garbled spllower(int ncpl)
    637   1.2   garbled {
    638   1.2   garbled 	struct cpu_info *ci = curcpu();
    639   1.2   garbled 	int ocpl;
    640   1.2   garbled 
    641  1.12  macallan 	__insn_barrier();
    642   1.2   garbled 	__asm volatile("sync; eieio");	/* reorder protect */
    643   1.2   garbled 	ocpl = ci->ci_cpl;
    644   1.2   garbled 	ci->ci_cpl = ncpl;
    645  1.13      matt 	if (have_pending_intr_p(ci, ncpl))
    646   1.2   garbled 		pic_do_pending_int();
    647   1.2   garbled 	__asm volatile("sync; eieio");	/* reorder protect */
    648   1.2   garbled 	return ocpl;
    649   1.2   garbled }
    650   1.2   garbled 
    651   1.2   garbled void
    652   1.2   garbled genppc_cpu_configure(void)
    653   1.2   garbled {
    654   1.2   garbled 	aprint_normal("biomask %x netmask %x ttymask %x\n",
    655   1.8  kiyohara 	    (u_int)imask[IPL_BIO] & 0x1fffffff,
    656   1.8  kiyohara 	    (u_int)imask[IPL_NET] & 0x1fffffff,
    657   1.8  kiyohara 	    (u_int)imask[IPL_TTY] & 0x1fffffff);
    658   1.2   garbled 
    659   1.2   garbled 	spl0();
    660   1.2   garbled }
    661   1.2   garbled 
    662   1.2   garbled #if defined(PIC_PREPIVR) || defined(PIC_I8259)
    663   1.2   garbled /*
    664   1.2   garbled  * isa_intr_alloc needs to be done here, because it needs direct access to
    665   1.2   garbled  * the various interrupt handler structures.
    666   1.2   garbled  */
    667   1.2   garbled 
    668   1.2   garbled int
    669   1.2   garbled genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
    670   1.2   garbled     int mask, int type, int *irq_p)
    671   1.2   garbled {
    672   1.2   garbled 	int irq, vi;
    673   1.2   garbled 	int maybe_irq = -1;
    674   1.2   garbled 	int shared_depth = 0;
    675   1.2   garbled 	struct intr_source *is;
    676   1.2   garbled 
    677   1.2   garbled 	if (pic == NULL)
    678   1.2   garbled 		return 1;
    679   1.2   garbled 
    680   1.2   garbled 	for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
    681   1.2   garbled 	     mask >>= 1, irq++) {
    682   1.2   garbled 		if ((mask & 1) == 0)
    683   1.2   garbled 			continue;
    684  1.15      matt 		vi = virq_map[irq + pic->pic_intrbase];
    685   1.2   garbled 		if (!vi) {
    686   1.2   garbled 			*irq_p = irq;
    687   1.2   garbled 			return 0;
    688   1.2   garbled 		}
    689   1.2   garbled 		is = &intrsources[vi];
    690   1.2   garbled 		if (is->is_type == IST_NONE) {
    691   1.2   garbled 			*irq_p = irq;
    692   1.2   garbled 			return 0;
    693   1.2   garbled 		}
    694   1.2   garbled 		/* Level interrupts can be shared */
    695   1.2   garbled 		if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
    696   1.2   garbled 			struct intrhand *ih = is->is_hand;
    697   1.2   garbled 			int depth;
    698   1.2   garbled 
    699   1.2   garbled 			if (maybe_irq == -1) {
    700   1.2   garbled 				maybe_irq = irq;
    701   1.2   garbled 				continue;
    702   1.2   garbled 			}
    703   1.2   garbled 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    704   1.2   garbled 				depth++;
    705   1.2   garbled 			if (depth < shared_depth) {
    706   1.2   garbled 				maybe_irq = irq;
    707   1.2   garbled 				shared_depth = depth;
    708   1.2   garbled 			}
    709   1.2   garbled 		}
    710   1.2   garbled 	}
    711   1.2   garbled 	if (maybe_irq != -1) {
    712   1.2   garbled 		*irq_p = maybe_irq;
    713   1.2   garbled 		return 0;
    714   1.2   garbled 	}
    715   1.2   garbled 	return 1;
    716   1.2   garbled }
    717   1.2   garbled #endif
    718