Home | History | Annotate | Line # | Download | only in cavium
octeon_intr.c revision 1.1
      1  1.1  hikaru /*	$NetBSD: octeon_intr.c,v 1.1 2015/04/29 08:32:00 hikaru Exp $	*/
      2  1.1  hikaru /*
      3  1.1  hikaru  * Copyright 2001, 2002 Wasabi Systems, Inc.
      4  1.1  hikaru  * All rights reserved.
      5  1.1  hikaru  *
      6  1.1  hikaru  * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
      7  1.1  hikaru  *
      8  1.1  hikaru  * Redistribution and use in source and binary forms, with or without
      9  1.1  hikaru  * modification, are permitted provided that the following conditions
     10  1.1  hikaru  * are met:
     11  1.1  hikaru  * 1. Redistributions of source code must retain the above copyright
     12  1.1  hikaru  *    notice, this list of conditions and the following disclaimer.
     13  1.1  hikaru  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  hikaru  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  hikaru  *    documentation and/or other materials provided with the distribution.
     16  1.1  hikaru  * 3. All advertising materials mentioning features or use of this software
     17  1.1  hikaru  *    must display the following acknowledgement:
     18  1.1  hikaru  *      This product includes software developed for the NetBSD Project by
     19  1.1  hikaru  *      Wasabi Systems, Inc.
     20  1.1  hikaru  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     21  1.1  hikaru  *    or promote products derived from this software without specific prior
     22  1.1  hikaru  *    written permission.
     23  1.1  hikaru  *
     24  1.1  hikaru  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     25  1.1  hikaru  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     26  1.1  hikaru  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     27  1.1  hikaru  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     28  1.1  hikaru  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     29  1.1  hikaru  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     30  1.1  hikaru  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     31  1.1  hikaru  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     32  1.1  hikaru  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     33  1.1  hikaru  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34  1.1  hikaru  * POSSIBILITY OF SUCH DAMAGE.
     35  1.1  hikaru  */
     36  1.1  hikaru 
     37  1.1  hikaru /*
     38  1.1  hikaru  * Platform-specific interrupt support for the MIPS Malta.
     39  1.1  hikaru  */
     40  1.1  hikaru 
     41  1.1  hikaru #include "opt_octeon.h"
     42  1.1  hikaru #define __INTR_PRIVATE
     43  1.1  hikaru 
     44  1.1  hikaru #include <sys/cdefs.h>
     45  1.1  hikaru __KERNEL_RCSID(0, "$NetBSD: octeon_intr.c,v 1.1 2015/04/29 08:32:00 hikaru Exp $");
     46  1.1  hikaru 
     47  1.1  hikaru #include <sys/param.h>
     48  1.1  hikaru #include <sys/cpu.h>
     49  1.1  hikaru #include <sys/systm.h>
     50  1.1  hikaru #include <sys/device.h>
     51  1.1  hikaru #include <sys/intr.h>
     52  1.1  hikaru #include <sys/kernel.h>
     53  1.1  hikaru #include <sys/malloc.h>
     54  1.1  hikaru 
     55  1.1  hikaru #include <lib/libkern/libkern.h>
     56  1.1  hikaru 
     57  1.1  hikaru #include <mips/locore.h>
     58  1.1  hikaru 
     59  1.1  hikaru #include <mips/cavium/dev/octeon_ciureg.h>
     60  1.1  hikaru #include <mips/cavium/octeonvar.h>
     61  1.1  hikaru 
     62  1.1  hikaru /*
     63  1.1  hikaru  * This is a mask of bits to clear in the SR when we go to a
     64  1.1  hikaru  * given hardware interrupt priority level.
     65  1.1  hikaru  */
     66  1.1  hikaru static const struct ipl_sr_map octeon_ipl_sr_map = {
     67  1.1  hikaru     .sr_bits = {
     68  1.1  hikaru 	[IPL_NONE] =		0,
     69  1.1  hikaru 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
     70  1.1  hikaru 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
     71  1.1  hikaru 	[IPL_VM] =		MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
     72  1.1  hikaru 	[IPL_SCHED] =		MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
     73  1.1  hikaru 				    | MIPS_INT_MASK_5,
     74  1.1  hikaru 	[IPL_DDB] =		MIPS_INT_MASK,
     75  1.1  hikaru 	[IPL_HIGH] =		MIPS_INT_MASK,
     76  1.1  hikaru     },
     77  1.1  hikaru };
     78  1.1  hikaru 
     79  1.1  hikaru #define	NIRQS		64
     80  1.1  hikaru 
     81  1.1  hikaru const char *octeon_intrnames[NIRQS] = {
     82  1.1  hikaru 	"workq 0",
     83  1.1  hikaru 	"workq 1",
     84  1.1  hikaru 	"workq 2",
     85  1.1  hikaru 	"workq 3",
     86  1.1  hikaru 	"workq 4",
     87  1.1  hikaru 	"workq 5",
     88  1.1  hikaru 	"workq 6",
     89  1.1  hikaru 	"workq 7",
     90  1.1  hikaru 	"workq 8",
     91  1.1  hikaru 	"workq 9",
     92  1.1  hikaru 	"workq 10",
     93  1.1  hikaru 	"workq 11",
     94  1.1  hikaru 	"workq 12",
     95  1.1  hikaru 	"workq 13",
     96  1.1  hikaru 	"workq 14",
     97  1.1  hikaru 	"workq 15",
     98  1.1  hikaru 	"gpio 0",
     99  1.1  hikaru 	"gpio 1",
    100  1.1  hikaru 	"gpio 2",
    101  1.1  hikaru 	"gpio 3",
    102  1.1  hikaru 	"gpio 4",
    103  1.1  hikaru 	"gpio 5",
    104  1.1  hikaru 	"gpio 6",
    105  1.1  hikaru 	"gpio 7",
    106  1.1  hikaru 	"gpio 8",
    107  1.1  hikaru 	"gpio 9",
    108  1.1  hikaru 	"gpio 10",
    109  1.1  hikaru 	"gpio 11",
    110  1.1  hikaru 	"gpio 12",
    111  1.1  hikaru 	"gpio 13",
    112  1.1  hikaru 	"gpio 14",
    113  1.1  hikaru 	"gpio 15",
    114  1.1  hikaru 	"mbox 0-15",
    115  1.1  hikaru 	"mbox 16-31",
    116  1.1  hikaru 	"uart 0",
    117  1.1  hikaru 	"uart 1",
    118  1.1  hikaru 	"pci inta",
    119  1.1  hikaru 	"pci intb",
    120  1.1  hikaru 	"pci intc",
    121  1.1  hikaru 	"pci intd",
    122  1.1  hikaru 	"pci msi 0-15",
    123  1.1  hikaru 	"pci msi 16-31",
    124  1.1  hikaru 	"pci msi 32-47",
    125  1.1  hikaru 	"pci msi 48-63",
    126  1.1  hikaru 	"wdog summary",
    127  1.1  hikaru 	"twsi",
    128  1.1  hikaru 	"rml",
    129  1.1  hikaru 	"trace",
    130  1.1  hikaru 	"gmx drop",
    131  1.1  hikaru 	"reserved",
    132  1.1  hikaru 	"ipd drop",
    133  1.1  hikaru 	"reserved",
    134  1.1  hikaru 	"timer 0",
    135  1.1  hikaru 	"timer 1",
    136  1.1  hikaru 	"timer 2",
    137  1.1  hikaru 	"timer 3",
    138  1.1  hikaru 	"usb",
    139  1.1  hikaru 	"pcm/tdm",
    140  1.1  hikaru 	"mpi/spi",
    141  1.1  hikaru 	"reserved",
    142  1.1  hikaru 	"reserved",
    143  1.1  hikaru 	"reserved",
    144  1.1  hikaru 	"reserved",
    145  1.1  hikaru 	"reserved",
    146  1.1  hikaru };
    147  1.1  hikaru 
    148  1.1  hikaru struct octeon_intrhand {
    149  1.1  hikaru 	LIST_ENTRY(octeon_intrhand) ih_q;
    150  1.1  hikaru 	int (*ih_func)(void *);
    151  1.1  hikaru 	void *ih_arg;
    152  1.1  hikaru 	int ih_irq;
    153  1.1  hikaru 	int ih_ipl;
    154  1.1  hikaru 	int ih_intr;
    155  1.1  hikaru };
    156  1.1  hikaru 
    157  1.1  hikaru struct octeon_intrhead {
    158  1.1  hikaru 	LIST_HEAD(, octeon_intrhand) intr_list;
    159  1.1  hikaru 	int intr_refcnt;
    160  1.1  hikaru };
    161  1.1  hikaru 
    162  1.1  hikaru struct octeon_intrhead octeon_ciu_intrtab[NIRQS];
    163  1.1  hikaru 
    164  1.1  hikaru struct octeon_cpuintr {
    165  1.1  hikaru 	LIST_HEAD(, octeon_intrhand) cintr_list;
    166  1.1  hikaru 	struct evcnt cintr_count;
    167  1.1  hikaru };
    168  1.1  hikaru 
    169  1.1  hikaru #define	NINTRS		5	/* MIPS INT0 - INT4 */
    170  1.1  hikaru 
    171  1.1  hikaru struct octeon_cpuintr octeon_cpuintrs[NINTRS];
    172  1.1  hikaru const char *octeon_cpuintrnames[NINTRS] = {
    173  1.1  hikaru 	"int 0 (IP2)",
    174  1.1  hikaru 	"int 1 (IP3)",
    175  1.1  hikaru 	"int 2 ",
    176  1.1  hikaru 	"int 3 ",
    177  1.1  hikaru 	"int 4 ",
    178  1.1  hikaru };
    179  1.1  hikaru 
    180  1.1  hikaru 
    181  1.1  hikaru /* temporary interrupt enable bits */
    182  1.1  hikaru uint64_t int0_enable0;
    183  1.1  hikaru uint64_t int1_enable0;
    184  1.1  hikaru 
    185  1.1  hikaru 
    186  1.1  hikaru #if 0
    187  1.1  hikaru /*
    188  1.1  hikaru  * NOTE: This routine must be called with interrupts disabled in the CPSR.
    189  1.1  hikaru  */
    190  1.1  hikaru static void
    191  1.1  hikaru octeon_intr_calculate_masks(void)
    192  1.1  hikaru {
    193  1.1  hikaru 	struct octeon_intrhand *ih;
    194  1.1  hikaru 	int level, ipl, irq;
    195  1.1  hikaru 
    196  1.1  hikaru 	/* First, figure out which IPLs each INT has. */
    197  1.1  hikaru 	for (level = 0; level < NINTRS; level++) {
    198  1.1  hikaru 		int levels = 0;
    199  1.1  hikaru 
    200  1.1  hikaru 		for (irq = 0; irq < NIRQS; irq++)
    201  1.1  hikaru 			LIST_FOREACH(ih, &octeon_intrtab[irq].intr_list, ih_q)
    202  1.1  hikaru 				if (ih->ih_intr == level)
    203  1.1  hikaru 					levels |= 1 << ih->ih_ipl;
    204  1.1  hikaru 		octeon_cpuintrs[level].cintr_levels = levels;
    205  1.1  hikaru 	}
    206  1.1  hikaru 
    207  1.1  hikaru 	/* Next, figure out which INTs are used by each IPL. */
    208  1.1  hikaru 	for (ipl = 0; ipl < _IPL_N; ipl++) {
    209  1.1  hikaru 		int irqs = 0;
    210  1.1  hikaru 
    211  1.1  hikaru 		for (level = 0; level < NINTRS; level++)
    212  1.1  hikaru 			if (1 << ipl & octeon_cpuintrs[level].cintr_levels)
    213  1.1  hikaru 				irqs |= MIPS_INT_MASK_0 << level;
    214  1.1  hikaru 		ipl_sr_bits[ipl] = irqs;
    215  1.1  hikaru 	}
    216  1.1  hikaru 
    217  1.1  hikaru 	/*
    218  1.1  hikaru 	 * IPL_CLOCK should mask clock interrupt even if interrupt handler
    219  1.1  hikaru 	 * is not registered.
    220  1.1  hikaru 	 */
    221  1.1  hikaru 	ipl_sr_bits[IPL_CLOCK] |= MIPS_INT_MASK_5;
    222  1.1  hikaru 
    223  1.1  hikaru 	/*
    224  1.1  hikaru 	 * IPL_NONE is used for hardware interrupts that are never blocked,
    225  1.1  hikaru 	 * and do not block anything else.
    226  1.1  hikaru 	 */
    227  1.1  hikaru 	ipl_sr_bits[IPL_NONE] = 0;
    228  1.1  hikaru 
    229  1.1  hikaru 	/*
    230  1.1  hikaru 	 * Initialize the soft interrupt masks to block themselves.
    231  1.1  hikaru 	 */
    232  1.1  hikaru 	ipl_sr_bits[IPL_SOFTCLOCK] |= SI_TO_SRBIT(SI_SOFTCLOCK);
    233  1.1  hikaru 	ipl_sr_bits[IPL_SOFTNET] |= SI_TO_SRBIT(SI_SOFTNET);
    234  1.1  hikaru 	ipl_sr_bits[IPL_SOFTSERIAL] |= SI_TO_SRBIT(SI_SOFTSERIAL);
    235  1.1  hikaru 
    236  1.1  hikaru 	/*
    237  1.1  hikaru 	 * Enforce a heirarchy that gives "slow" device (or devices with
    238  1.1  hikaru 	 * limited input buffer space/"real-time" requirements) a better
    239  1.1  hikaru 	 * chance at not dropping data.
    240  1.1  hikaru 	 */
    241  1.1  hikaru 	for (ipl = 1; ipl < _IPL_N; ipl++)
    242  1.1  hikaru 		ipl_sr_bits[ipl] |= ipl_sr_bits[ipl - 1];
    243  1.1  hikaru 
    244  1.1  hikaru 	/*
    245  1.1  hikaru 	 * splhigh() must block "everything".
    246  1.1  hikaru 	 */
    247  1.1  hikaru 	ipl_sr_bits[IPL_HIGH] = MIPS_INT_MASK;
    248  1.1  hikaru 
    249  1.1  hikaru 	/*
    250  1.1  hikaru 	 * Now compute which INTs must be blocked when servicing any
    251  1.1  hikaru 	 * given INT.
    252  1.1  hikaru 	 */
    253  1.1  hikaru 	for (level = 0; level < NINTRS; level++) {
    254  1.1  hikaru 		int irqs = (MIPS_INT_MASK_0 << level);
    255  1.1  hikaru 
    256  1.1  hikaru 		for (irq = 0; irq < NIRQS; irq++)
    257  1.1  hikaru 			LIST_FOREACH(ih, &octeon_intrtab[irq].intr_list, ih_q)
    258  1.1  hikaru 				if (ih->ih_intr == level)
    259  1.1  hikaru 					irqs |= ipl_sr_bits[ih->ih_ipl];
    260  1.1  hikaru 		octeon_cpuintrs[level].cintr_mask = irqs;
    261  1.1  hikaru 	}
    262  1.1  hikaru 
    263  1.1  hikaru //	for (ipl = 0; ipl < _IPL_N; ipl++)
    264  1.1  hikaru //		printf("debug: ipl_sr_bits[%.2d] = %.8x\n", ipl, ipl_sr_bits[ipl]);
    265  1.1  hikaru }
    266  1.1  hikaru #endif
    267  1.1  hikaru 
    268  1.1  hikaru void
    269  1.1  hikaru octeon_intr_init(void)
    270  1.1  hikaru {
    271  1.1  hikaru 	ipl_sr_map = octeon_ipl_sr_map;
    272  1.1  hikaru 
    273  1.1  hikaru 	octeon_write_csr(CIU_INT0_EN0, 0);
    274  1.1  hikaru 	octeon_write_csr(CIU_INT1_EN0, 0);
    275  1.1  hikaru 	octeon_write_csr(CIU_INT32_EN0, 0);
    276  1.1  hikaru 	octeon_write_csr(CIU_INT0_EN1, 0);
    277  1.1  hikaru 	octeon_write_csr(CIU_INT1_EN1, 0);
    278  1.1  hikaru 	octeon_write_csr(CIU_INT32_EN1, 0);
    279  1.1  hikaru 
    280  1.1  hikaru 	for (size_t i = 0; i < NINTRS; i++) {
    281  1.1  hikaru 		LIST_INIT(&octeon_cpuintrs[i].cintr_list);
    282  1.1  hikaru 		evcnt_attach_dynamic(&octeon_cpuintrs[i].cintr_count,
    283  1.1  hikaru 		    EVCNT_TYPE_INTR, NULL, "mips", octeon_cpuintrnames[i]);
    284  1.1  hikaru 	}
    285  1.1  hikaru 
    286  1.1  hikaru 	for (size_t i = 0; i < NIRQS; i++) {
    287  1.1  hikaru 		LIST_INIT(&octeon_ciu_intrtab[i].intr_list);
    288  1.1  hikaru 		octeon_ciu_intrtab[i].intr_refcnt = 0;
    289  1.1  hikaru 	}
    290  1.1  hikaru }
    291  1.1  hikaru 
    292  1.1  hikaru void
    293  1.1  hikaru octeon_cal_timer(int corefreq)
    294  1.1  hikaru {
    295  1.1  hikaru 	/* Compute the number of cycles per second. */
    296  1.1  hikaru 	curcpu()->ci_cpu_freq = corefreq;
    297  1.1  hikaru 
    298  1.1  hikaru 	/* Compute the number of ticks for hz. */
    299  1.1  hikaru 	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
    300  1.1  hikaru 
    301  1.1  hikaru 	/* Compute the delay divisor and reciprical. */
    302  1.1  hikaru 	curcpu()->ci_divisor_delay =
    303  1.1  hikaru 	    ((curcpu()->ci_cpu_freq + 500000) / 1000000);
    304  1.1  hikaru #if 0
    305  1.1  hikaru 	MIPS_SET_CI_RECIPRICAL(curcpu());
    306  1.1  hikaru #endif
    307  1.1  hikaru 
    308  1.1  hikaru 	mips3_cp0_count_write(0);
    309  1.1  hikaru 	mips3_cp0_compare_write(0);
    310  1.1  hikaru }
    311  1.1  hikaru 
    312  1.1  hikaru void *
    313  1.1  hikaru octeon_intr_establish(int irq, int req, int level,
    314  1.1  hikaru     int (*func)(void *), void *arg)
    315  1.1  hikaru {
    316  1.1  hikaru 	struct octeon_intrhand *ih;
    317  1.1  hikaru 	u_int64_t irq_mask;
    318  1.1  hikaru 	int s;
    319  1.1  hikaru 
    320  1.1  hikaru 	if (irq >= NIRQS)
    321  1.1  hikaru 		panic("octeon_intr_establish: bogus IRQ %d", irq);
    322  1.1  hikaru 	if (req > 1)
    323  1.1  hikaru 		panic("octeon_intr_establish: bogus request %d", req);
    324  1.1  hikaru 
    325  1.1  hikaru 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    326  1.1  hikaru 	if (ih == NULL)
    327  1.1  hikaru 		return (NULL);
    328  1.1  hikaru 
    329  1.1  hikaru 	ih->ih_func = func;
    330  1.1  hikaru 	ih->ih_arg = arg;
    331  1.1  hikaru 	ih->ih_irq = irq;
    332  1.1  hikaru 	ih->ih_ipl = level;
    333  1.1  hikaru 	ih->ih_intr = req;
    334  1.1  hikaru 
    335  1.1  hikaru 	s = splhigh();
    336  1.1  hikaru 
    337  1.1  hikaru 	/*
    338  1.1  hikaru 	 * First, link it into the tables.
    339  1.1  hikaru 	 * XXX do we want a separate list (really, should only be one item, not
    340  1.1  hikaru 	 *     a list anyway) per irq, not per CPU interrupt?
    341  1.1  hikaru 	 */
    342  1.1  hikaru 	LIST_INSERT_HEAD(&octeon_ciu_intrtab[irq].intr_list, ih, ih_q);
    343  1.1  hikaru 
    344  1.1  hikaru 	/*
    345  1.1  hikaru 	 * Now enable it.
    346  1.1  hikaru 	 */
    347  1.1  hikaru 	if (octeon_ciu_intrtab[irq].intr_refcnt++ == 0) {
    348  1.1  hikaru 		irq_mask = 1ULL << irq;
    349  1.1  hikaru 
    350  1.1  hikaru 		switch (req) {
    351  1.1  hikaru 		case 0:
    352  1.1  hikaru 			int0_enable0 |= irq_mask;
    353  1.1  hikaru 			octeon_write_csr(CIU_INT0_EN0, int0_enable0);
    354  1.1  hikaru 			break;
    355  1.1  hikaru 
    356  1.1  hikaru 		case 1:
    357  1.1  hikaru 			int1_enable0 |= irq_mask;
    358  1.1  hikaru 			octeon_write_csr(CIU_INT1_EN0, int1_enable0);
    359  1.1  hikaru 			break;
    360  1.1  hikaru 		}
    361  1.1  hikaru 	}
    362  1.1  hikaru 	splx(s);
    363  1.1  hikaru 
    364  1.1  hikaru 	return (ih);
    365  1.1  hikaru }
    366  1.1  hikaru 
    367  1.1  hikaru void
    368  1.1  hikaru octeon_intr_disestablish(void *cookie)
    369  1.1  hikaru {
    370  1.1  hikaru 	struct octeon_intrhand *ih = cookie;
    371  1.1  hikaru 	u_int64_t irq_mask;
    372  1.1  hikaru 	int irq, req, s;
    373  1.1  hikaru 
    374  1.1  hikaru 	irq = ih->ih_irq;
    375  1.1  hikaru 	req = ih->ih_intr;
    376  1.1  hikaru 
    377  1.1  hikaru 	s = splhigh();
    378  1.1  hikaru 
    379  1.1  hikaru 	/*
    380  1.1  hikaru 	 * First, remove it from the table.
    381  1.1  hikaru 	 */
    382  1.1  hikaru 	LIST_REMOVE(ih, ih_q);
    383  1.1  hikaru 
    384  1.1  hikaru 	/*
    385  1.1  hikaru 	 * Now, disable it, if there is nothing remaining on the
    386  1.1  hikaru 	 * list.
    387  1.1  hikaru 	 */
    388  1.1  hikaru 	if (octeon_ciu_intrtab[irq].intr_refcnt-- == 1) {
    389  1.1  hikaru 		irq &= 63;	/* throw away high bit if set */
    390  1.1  hikaru 		req &= 1;	/* throw away high bit if set */
    391  1.1  hikaru 		irq_mask = ~(1ULL << irq);
    392  1.1  hikaru 
    393  1.1  hikaru 		switch (req) {
    394  1.1  hikaru 		case 0:
    395  1.1  hikaru 			int0_enable0 &= irq_mask;
    396  1.1  hikaru 			octeon_write_csr(CIU_INT0_EN0, int0_enable0);
    397  1.1  hikaru 			break;
    398  1.1  hikaru 
    399  1.1  hikaru 		case 1:
    400  1.1  hikaru 			int1_enable0 &= irq_mask;
    401  1.1  hikaru 			octeon_write_csr(CIU_INT1_EN0, int1_enable0);
    402  1.1  hikaru 			break;
    403  1.1  hikaru 		}
    404  1.1  hikaru 	}
    405  1.1  hikaru 	free(ih, M_DEVBUF);
    406  1.1  hikaru 
    407  1.1  hikaru 	splx(s);
    408  1.1  hikaru }
    409  1.1  hikaru 
    410  1.1  hikaru void
    411  1.1  hikaru octeon_iointr(int ipl, vaddr_t pc, uint32_t ipending)
    412  1.1  hikaru {
    413  1.1  hikaru 	struct octeon_intrhand *ih;
    414  1.1  hikaru 	int level, irq;
    415  1.1  hikaru 	uint64_t hwpend = 0;
    416  1.1  hikaru 
    417  1.1  hikaru 	asm (".set mips64; clz %0,%1; .set mips0" : "=r"(level) : "r"(ipending));
    418  1.1  hikaru 	switch (level = 21 - level) {
    419  1.1  hikaru 	case 0: // MIPS_INT_MASK_0
    420  1.1  hikaru 		hwpend = octeon_read_csr(CIU_INT0_SUM0) & int0_enable0;
    421  1.1  hikaru 		break;
    422  1.1  hikaru 
    423  1.1  hikaru 	case 1: // MIPS_INT_MASK_1
    424  1.1  hikaru 		hwpend = octeon_read_csr(CIU_INT1_SUM0) & int1_enable0;
    425  1.1  hikaru 		break;
    426  1.1  hikaru 
    427  1.1  hikaru 	default:
    428  1.1  hikaru 		panic("octeon_iointr: illegal interrupt");
    429  1.1  hikaru 	}
    430  1.1  hikaru 	if ((irq = ffs64(hwpend) - 1) < 0)
    431  1.1  hikaru 		return;
    432  1.1  hikaru 	LIST_FOREACH(ih, &octeon_ciu_intrtab[irq].intr_list, ih_q) {
    433  1.1  hikaru 		(*ih->ih_func)(ih->ih_arg);
    434  1.1  hikaru 	}
    435  1.1  hikaru }
    436