Home | History | Annotate | Line # | Download | only in macppc
      1 /*	$NetBSD: pic_u3_ht.c,v 1.14 2023/01/12 01:19:21 macallan Exp $	*/
      2 /*-
      3  * Copyright (c) 2013 Phileas Fogg
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: pic_u3_ht.c,v 1.14 2023/01/12 01:19:21 macallan Exp $");
     30 
     31 #include "opt_openpic.h"
     32 #include "opt_interrupt.h"
     33 
     34 #include <sys/param.h>
     35 #include <sys/kmem.h>
     36 #include <sys/kernel.h>
     37 #include <sys/atomic.h>
     38 #include <sys/cpu.h>
     39 
     40 #include <machine/pio.h>
     41 #include <powerpc/openpic.h>
     42 
     43 #include <dev/ofw/openfirm.h>
     44 #include <dev/ofw/ofw_pci.h>
     45 #include <dev/pci/pcireg.h>
     46 
     47 #include <machine/autoconf.h>
     48 #include <arch/powerpc/pic/picvar.h>
     49 
     50 #ifdef U3_HT_PIC_DEBUG
     51 #define DPRINTF aprint_error
     52 #else
     53 #define DPRINTF if (0) printf
     54 #endif
     55 
     56 #define HTAPIC_REQUEST_EOI	0x20
     57 #define HTAPIC_TRIGGER_LEVEL	0x02
     58 #define HTAPIC_MASK		0x01
     59 
     60 struct u3_ht_irqmap {
     61 	int im_index;
     62 	int im_level;
     63 	volatile uint8_t *im_base;
     64 	volatile uint8_t *im_apple_base;
     65 	uint32_t im_data;
     66 };
     67 
     68 struct u3_ht_ops {
     69 	struct pic_ops pic;
     70 
     71 	volatile uint8_t *ht_base;
     72 
     73 	struct u3_ht_irqmap ht_irqmap[128];
     74 
     75 	uint32_t (*ht_read)(struct u3_ht_ops *, u_int);
     76 	void (*ht_write)(struct u3_ht_ops *, u_int, uint32_t);
     77 };
     78 
     79 #define u3_ht_read(ptr,reg)		(ptr)->ht_read(ptr, reg)
     80 #define u3_ht_write(ptr,reg,val)	(ptr)->ht_write(ptr, reg, val)
     81 
     82 static struct u3_ht_ops *setup_u3_ht(uint32_t, uint32_t, int, int);
     83 static int setup_u3_ht_workarounds(struct u3_ht_ops *);
     84 
     85 static void u3_ht_enable_irq(struct pic_ops *, int, int);
     86 static void u3_ht_disable_irq(struct pic_ops *, int);
     87 static int  u3_ht_get_irq(struct pic_ops *, int);
     88 static void u3_ht_ack_irq(struct pic_ops *, int);
     89 static void u3_ht_establish_irq(struct pic_ops *, int, int, int);
     90 static void u3_ht_finish_setup(struct pic_ops *);
     91 
     92 static int u3_ht_is_ht_irq(struct u3_ht_ops *, int);
     93 static void u3_ht_establish_ht_irq(struct u3_ht_ops *, int, int);
     94 static void u3_ht_enable_ht_irq(struct u3_ht_ops *, int);
     95 static void u3_ht_disable_ht_irq(struct u3_ht_ops *, int);
     96 static void u3_ht_ack_ht_irq(struct u3_ht_ops *, int);
     97 
     98 static void u3_ht_set_priority(struct u3_ht_ops *, int, int);
     99 void __u3_ht_set_priority(int, int);
    100 static int u3_ht_read_irq(struct u3_ht_ops *, int);
    101 static void u3_ht_eoi(struct u3_ht_ops *, int);
    102 
    103 static uint32_t u3_ht_read_be(struct u3_ht_ops *, u_int);
    104 static void u3_ht_write_be(struct u3_ht_ops *, u_int, uint32_t);
    105 static uint32_t u3_ht_read_le(struct u3_ht_ops *, u_int);
    106 static void u3_ht_write_le(struct u3_ht_ops *, u_int, uint32_t);
    107 
    108 static const char *u3_compat[] = {
    109 	"u3",
    110 	NULL
    111 };
    112 
    113 const char *pic_compat[] = {
    114 	"chrp,open-pic",
    115 	"open-pic",
    116 	"openpic",
    117 	NULL
    118 };
    119 
    120 static struct u3_ht_ops *u3ht0 = NULL;
    121 int have_u3_ht(void);
    122 
    123 #ifdef MULTIPROCESSOR
    124 
    125 extern struct ipi_ops ipiops;
    126 static void u3_ht_send_ipi(cpuid_t, uint32_t);
    127 static void u3_ht_establish_ipi(int, int, void *);
    128 
    129 #endif
    130 
    131 int init_u3_ht(void)
    132 {
    133 	int u4, pic, irq = -1;
    134 	uint32_t reg[2];
    135 	uint32_t base, len, tmp;
    136 	int bigendian;
    137 	volatile uint8_t *unin_reg;
    138 
    139 	u4 = OF_finddevice("/u4");
    140 	if (u4 == -1) {
    141 #ifdef U3HT_CASCADE
    142 		u4 = OF_finddevice("/u3");
    143 		if (u4 == -1)
    144 #endif
    145 			return FALSE;
    146 	}
    147 
    148 	if (! of_compatible(u4, u3_compat))
    149 		return FALSE;
    150 
    151 	pic = OF_child(u4);
    152  	while ((pic != 0) && !of_compatible(pic, pic_compat))
    153  		pic = OF_peer(pic);
    154 
    155 	if ((pic == -1) || (pic == 0))
    156 		return FALSE;
    157 
    158 	if (OF_getprop(u4, "reg", reg, sizeof(reg)) != 8)
    159 		return FALSE;
    160 
    161 	base = reg[1];
    162 
    163 	/* Enable and reset PIC */
    164 
    165 	unin_reg = mapiodev(base, PAGE_SIZE, false);
    166 	KASSERT(unin_reg != NULL);
    167 	tmp = in32(unin_reg + 0xe0);
    168 	tmp |= 0x06;
    169 	out32(unin_reg + 0xe0, tmp);
    170 
    171 	bigendian = 0;
    172 	if (OF_getprop(pic, "big-endian", reg, 4) > -1)
    173 		bigendian = 1;
    174 
    175 	if (OF_getprop(pic, "reg", reg, 8) != 8)
    176 		return FALSE;
    177 
    178 	base = reg[0];
    179 	len = reg[1];
    180 
    181 	if (OF_getprop(pic, "interrupts", reg, 8) > 4) {
    182 		/* this is a cascaded PIC */
    183 		irq = reg[0];
    184 		aprint_normal("found cascaded U3/U4 HT PIC at %08x, IRQ %d\n",
    185 		    base, irq);
    186 	} else
    187 		aprint_normal("found U3/U4 HT PIC at %08x\n", base);
    188 
    189 	setup_u3_ht(base, len, bigendian, irq);
    190 
    191 	return TRUE;
    192 }
    193 
    194 static struct u3_ht_ops *
    195 setup_u3_ht(uint32_t addr, uint32_t len, int bigendian, int cirq)
    196 {
    197 	struct u3_ht_ops *u3_ht;
    198 	struct pic_ops *pic;
    199 	int irq;
    200 	uint32_t x;
    201 
    202 	u3_ht = kmem_alloc(sizeof(struct u3_ht_ops), KM_SLEEP);
    203 	bzero(u3_ht, sizeof(struct u3_ht_ops));
    204 	pic = &u3_ht->pic;
    205 
    206 	u3_ht->ht_base = mapiodev(addr, len, false);
    207 	KASSERT(u3_ht->ht_base != NULL);
    208 
    209 	if (bigendian) {
    210 		u3_ht->ht_read = u3_ht_read_be;
    211 		u3_ht->ht_write = u3_ht_write_be;
    212 	} else {
    213 		u3_ht->ht_read = u3_ht_read_le;
    214 		u3_ht->ht_write = u3_ht_write_le;
    215 	}
    216 
    217 	setup_u3_ht_workarounds(u3_ht);
    218 
    219 	/* Reset PIC */
    220 
    221 	x = u3_ht_read(u3_ht, OPENPIC_CONFIG);
    222 	u3_ht_write(u3_ht, OPENPIC_CONFIG, x | OPENPIC_CONFIG_RESET);
    223 	do {
    224 		x = u3_ht_read(u3_ht, OPENPIC_CONFIG);
    225 	} while (x & OPENPIC_CONFIG_RESET);
    226 
    227 	x = u3_ht_read(u3_ht, OPENPIC_FEATURE);
    228 
    229 	aprint_normal("OpenPIC Version 1.%d: "
    230 	    "Supports %d CPUs and %d interrupt sources.\n",
    231 	    x & 0xff, ((x & 0x1f00) >> 8) + 1, ((x & 0x07ff0000) >> 16) + 1);
    232 
    233 	/* up to 128 interrupt sources, plus IPI */
    234 	pic->pic_numintrs = IPI_VECTOR + 1;
    235 	pic->pic_cookie = (void *) addr;
    236 	pic->pic_enable_irq = u3_ht_enable_irq;
    237 	pic->pic_reenable_irq = u3_ht_enable_irq;
    238 	pic->pic_disable_irq = u3_ht_disable_irq;
    239 	pic->pic_get_irq = u3_ht_get_irq;
    240 	pic->pic_ack_irq = u3_ht_ack_irq;
    241 	pic->pic_establish_irq = u3_ht_establish_irq;
    242 	pic->pic_finish_setup = u3_ht_finish_setup;
    243 	strcpy(pic->pic_name, "u3_ht");
    244 	pic_add(pic);
    245 
    246 	u3_ht_set_priority(u3_ht, 0, 15);
    247 
    248 	for (irq = 0; irq < 4; irq++) {
    249 		x = irq;
    250 		x |= OPENPIC_IMASK;
    251 		x |= OPENPIC_SENSE_LEVEL;
    252 		x |= 8 << OPENPIC_PRIORITY_SHIFT;
    253 		u3_ht_write(u3_ht, OPENPIC_SRC_VECTOR(irq), x);
    254 		u3_ht_write(u3_ht, OPENPIC_IDEST(irq), 1 << 0);
    255 	}
    256 	for (irq = 4; irq < pic->pic_numintrs; irq++) {
    257 		x = irq;
    258 		x |= OPENPIC_IMASK;
    259 		x |= OPENPIC_SENSE_EDGE;
    260 		x |= 8 << OPENPIC_PRIORITY_SHIFT;
    261 		u3_ht_write(u3_ht, OPENPIC_SRC_VECTOR(irq), x);
    262 		u3_ht_write(u3_ht, OPENPIC_IDEST(irq), 1 << 0);
    263 	}
    264 
    265 	x = u3_ht_read(u3_ht, OPENPIC_CONFIG);
    266 	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
    267 	u3_ht_write(u3_ht, OPENPIC_CONFIG, x);
    268 
    269 	u3_ht_write(u3_ht, OPENPIC_SPURIOUS_VECTOR, 0xff);
    270 
    271 	u3_ht_set_priority(u3_ht, 0, 0);
    272 
    273 	for (irq = 0; irq < pic->pic_numintrs; irq++) {
    274 		u3_ht_read_irq(u3_ht, 0);
    275 		u3_ht_eoi(u3_ht, 0);
    276 	}
    277 
    278 	if (cirq > -1) {
    279 		/* we're subordinate to a normal openpic */
    280 		intr_establish_xname(cirq, IST_EDGE, IPL_HIGH,
    281 		    pic_handle_intr, pic, "u3_ht");
    282 	}
    283 #ifdef MULTIPROCESSOR
    284 	else {
    285 		/* only handle IPIs if we're the only openpic */
    286 		ipiops.ppc_send_ipi = u3_ht_send_ipi;
    287 		ipiops.ppc_establish_ipi = u3_ht_establish_ipi;
    288 		ipiops.ppc_ipi_vector = IPI_VECTOR;
    289 
    290 		x = u3_ht_read(u3_ht, OPENPIC_IPI_VECTOR(1));
    291 		x &= ~(OPENPIC_IMASK | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK);
    292 		x |= (15 << OPENPIC_PRIORITY_SHIFT) | ipiops.ppc_ipi_vector;
    293 		u3_ht_write(u3_ht, OPENPIC_IPI_VECTOR(1), x);
    294 		u3ht0 = u3_ht;
    295 	}
    296 #endif /* MULTIPROCESSOR */
    297 
    298 	return u3_ht;
    299 }
    300 
    301 static int
    302 setup_u3_ht_workarounds(struct u3_ht_ops *u3_ht)
    303 {
    304 	struct u3_ht_irqmap *irqmap = u3_ht->ht_irqmap;
    305 	int parent, child;
    306 	uint32_t reg[5], tmp;
    307 	uint8_t pos;
    308 	uint16_t cr, ht_cr;
    309 	int nirq, irq, i;
    310 	volatile uint8_t *ht_reg, *dev_reg, *base;
    311 
    312 	parent = OF_finddevice("/ht");
    313 	if (parent == -1)
    314 		return FALSE;
    315 
    316 	if (OF_getprop(parent, "reg", reg, 12) != 12)
    317 		return FALSE;
    318 
    319 	ht_reg = mapiodev(reg[1], reg[2], false);
    320 	KASSERT(ht_reg != NULL);
    321 
    322 	memset(irqmap, 0, sizeof(u3_ht->ht_irqmap));
    323 
    324 	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
    325 		if (OF_getprop(child, "reg", reg, 4) != 4)
    326 			continue;
    327 
    328 		dev_reg = ht_reg + (reg[0] & (OFW_PCI_PHYS_HI_DEVICEMASK |
    329 		    OFW_PCI_PHYS_HI_FUNCTIONMASK));
    330 
    331 		tmp = in32rb(dev_reg + PCI_COMMAND_STATUS_REG);
    332 		if ((tmp & PCI_STATUS_CAPLIST_SUPPORT) == 0)
    333 			continue;
    334 
    335 		for (pos = in8rb(dev_reg + PCI_CAPLISTPTR_REG);
    336 		     pos != 0; pos = in8rb(dev_reg + pos + 0x01)) {
    337 		     	cr = in16rb(dev_reg + pos);
    338 			if (PCI_CAPLIST_CAP(cr) != 0x08)
    339 				continue;
    340 
    341 			ht_cr = in16rb(dev_reg + pos + 0x02);
    342 			if ((ht_cr & 0xf800) == 0x8000)
    343 				break;
    344 		}
    345 
    346 		if (pos == 0)
    347 			continue;
    348 
    349 		base = dev_reg + pos;
    350 
    351 		out8rb(base + 0x02, 0x01);
    352 		nirq = in32rb(base + 0x04);
    353 		nirq = (nirq >> 16) & 0xff;
    354 
    355 		DPRINTF("dev %08x nirq %d pos %08x\n", (uint32_t)base, nirq, (uint32_t)pos);
    356 		DPRINTF("devreg %08x\n", in32rb(dev_reg + PCI_ID_REG));
    357 		for (i = 0; i <= nirq; i++) {
    358 			out8rb(base + 0x02, 0x10 + (i << 1));
    359 			tmp = in32rb(base + 0x04);
    360 			irq = (tmp >> 16) & 0xff;
    361 			tmp |= HTAPIC_MASK;
    362 			out32rb(base + 0x04, tmp);
    363 
    364 			irqmap[irq].im_index = i;
    365 			irqmap[irq].im_level = 0;
    366 			irqmap[irq].im_base = base;
    367 
    368 			tmp = in32rb(dev_reg + PCI_ID_REG);
    369 			if (PCI_VENDOR(tmp) == 0x106b)
    370 				irqmap[irq].im_apple_base = dev_reg + 0x60;
    371 			else
    372 				irqmap[irq].im_apple_base = NULL;
    373 
    374 			out8rb(base + 0x02, 0x11 + (i << 1));
    375 			irqmap[irq].im_data = in32rb(base + 0x04);
    376 			irqmap[irq].im_data |= (1 << 31);
    377 		}
    378 	}
    379 
    380 	return TRUE;
    381 }
    382 
    383 static void
    384 u3_ht_enable_irq(struct pic_ops *pic, int irq, int type)
    385 {
    386 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    387 	u_int x;
    388 
    389 #ifdef MULTIPROCESSOR
    390 	if (irq == IPI_VECTOR) return;
    391 #endif
    392 	x = u3_ht_read(u3_ht, OPENPIC_SRC_VECTOR(irq));
    393  	x &= ~OPENPIC_IMASK;
    394  	u3_ht_write(u3_ht, OPENPIC_SRC_VECTOR(irq), x);
    395 
    396 	if (u3_ht_is_ht_irq(u3_ht, irq))
    397 		u3_ht_enable_ht_irq(u3_ht, irq);
    398 }
    399 
    400 static void
    401 u3_ht_disable_irq(struct pic_ops *pic, int irq)
    402 {
    403 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    404 	u_int x;
    405 
    406 #ifdef MULTIPROCESSOR
    407 	if (irq == IPI_VECTOR) return;
    408 #endif
    409  	x = u3_ht_read(u3_ht, OPENPIC_SRC_VECTOR(irq));
    410  	x |= OPENPIC_IMASK;
    411  	u3_ht_write(u3_ht, OPENPIC_SRC_VECTOR(irq), x);
    412 
    413 	if (u3_ht_is_ht_irq(u3_ht, irq))
    414 		u3_ht_disable_ht_irq(u3_ht, irq);
    415 }
    416 
    417 static int
    418 u3_ht_get_irq(struct pic_ops *pic, int mode)
    419 {
    420 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    421 
    422 	return u3_ht_read_irq(u3_ht, curcpu()->ci_index);
    423 }
    424 
    425 static void
    426 u3_ht_ack_irq(struct pic_ops *pic, int irq)
    427 {
    428 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    429 
    430 	if (u3_ht_is_ht_irq(u3_ht, irq))
    431 		u3_ht_ack_ht_irq(u3_ht, irq);
    432 
    433 	u3_ht_eoi(u3_ht, curcpu()->ci_index);
    434 }
    435 
    436 static void
    437 u3_ht_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
    438 {
    439 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    440 	int realpri = uimax(1, uimin(15, pri));
    441 	uint32_t x;
    442 
    443 	x = irq;
    444 	x |= OPENPIC_IMASK;
    445 
    446 	if (u3_ht_is_ht_irq(u3_ht, irq)) {
    447 		x |= OPENPIC_SENSE_EDGE;
    448 	} else {
    449 		if (type == IST_EDGE_FALLING || type == IST_EDGE_RISING)
    450 			x |= OPENPIC_SENSE_EDGE;
    451 		else
    452 			x |= OPENPIC_SENSE_LEVEL;
    453 	}
    454 
    455 	x |= realpri << OPENPIC_PRIORITY_SHIFT;
    456 	u3_ht_write(u3_ht, OPENPIC_SRC_VECTOR(irq), x);
    457 
    458 	if (u3_ht_is_ht_irq(u3_ht, irq))
    459 		u3_ht_establish_ht_irq(u3_ht, irq, type);
    460 
    461 	DPRINTF("%s: setting IRQ %d %d to priority %d %x\n", __func__, irq,
    462 	    type, realpri, x);
    463 }
    464 
    465 static void
    466 u3_ht_finish_setup(struct pic_ops *pic)
    467 {
    468 	struct u3_ht_ops *u3_ht = (struct u3_ht_ops *)pic;
    469 	uint32_t cpumask = 0;
    470 	int i;
    471 
    472 #ifdef OPENPIC_DISTRIBUTE
    473 	for (i = 0; i < ncpu; i++)
    474 		cpumask |= (1 << cpu_info[i].ci_cpuid);
    475 #else
    476 	cpumask = 1;
    477 #endif
    478 
    479 	for (i = 0; i < pic->pic_numintrs; i++)
    480 		u3_ht_write(u3_ht, OPENPIC_IDEST(i), cpumask);
    481 }
    482 
    483 static int
    484 u3_ht_is_ht_irq(struct u3_ht_ops *u3_ht, int irq)
    485 {
    486 	return (irq < 128) && (u3_ht->ht_irqmap[irq].im_base != NULL);
    487 }
    488 
    489 static void
    490 u3_ht_establish_ht_irq(struct u3_ht_ops *u3_ht, int irq, int type)
    491 {
    492 	struct u3_ht_irqmap *irqmap = &u3_ht->ht_irqmap[irq];
    493 	u_int x;
    494 
    495 	out8rb(irqmap->im_base + 0x02, 0x10 + (irqmap->im_index << 1));
    496 
    497 	x = in32rb(irqmap->im_base + 0x04);
    498 	/* mask interrupt */
    499 	out32rb(irqmap->im_base + 0x04, x | HTAPIC_MASK);
    500 
    501 	/* mask out EOI and LEVEL bits */
    502 	x &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI);
    503 
    504 	if (type == IST_LEVEL_HIGH || type == IST_LEVEL_LOW) {
    505 		irqmap->im_level = 1;
    506 		DPRINTF("level\n");
    507 		x |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI;
    508 	} else {
    509 		irqmap->im_level = 0;
    510 	}
    511 
    512 	out32rb(irqmap->im_base + 0x04, x);
    513 }
    514 
    515 static void
    516 u3_ht_enable_ht_irq(struct u3_ht_ops *u3_ht, int irq)
    517 {
    518 	struct u3_ht_irqmap *irqmap = &u3_ht->ht_irqmap[irq];
    519 	u_int x;
    520 
    521 	out8rb(irqmap->im_base + 0x02, 0x10 + (irqmap->im_index << 1));
    522 	x = in32rb(irqmap->im_base + 0x04);
    523 	x &= ~HTAPIC_MASK;
    524 	out32rb(irqmap->im_base + 0x04, x);
    525 
    526 	u3_ht_ack_ht_irq(u3_ht, irq);
    527 }
    528 
    529 static void
    530 u3_ht_disable_ht_irq(struct u3_ht_ops *u3_ht, int irq)
    531 {
    532 	struct u3_ht_irqmap *irqmap = &u3_ht->ht_irqmap[irq];
    533 	u_int x;
    534 
    535 	out8rb(irqmap->im_base + 0x02, 0x10 + (irqmap->im_index << 1));
    536 	x = in32rb(irqmap->im_base + 0x04);
    537 	x |= HTAPIC_MASK;
    538 	out32rb(irqmap->im_base + 0x04, x);
    539 }
    540 
    541 static void
    542 u3_ht_ack_ht_irq(struct u3_ht_ops *u3_ht, int irq)
    543 {
    544 	struct u3_ht_irqmap *irqmap = &u3_ht->ht_irqmap[irq];
    545 
    546 	if (irqmap->im_level != 0) {
    547 		if (irqmap->im_apple_base != NULL) {
    548 			out32rb(irqmap->im_apple_base + ((irqmap->im_index >> 3) & ~0x03),
    549 			    1 << (irqmap->im_index & 0x1f));
    550 		} else {
    551 			out8rb(irqmap->im_base + 0x02, 0x11 + (irqmap->im_index << 1));
    552 			out32rb(irqmap->im_base + 0x04, irqmap->im_data);
    553 		}
    554 	}
    555 }
    556 
    557 static void
    558 u3_ht_set_priority(struct u3_ht_ops *u3_ht, int cpu, int pri)
    559 {
    560 	u_int x;
    561 
    562 	x = u3_ht_read(u3_ht, OPENPIC_CPU_PRIORITY(cpu));
    563 	x &= ~OPENPIC_CPU_PRIORITY_MASK;
    564 	x |= pri;
    565 	u3_ht_write(u3_ht, OPENPIC_CPU_PRIORITY(cpu), x);
    566 }
    567 
    568 void
    569 __u3_ht_set_priority(int cpu, int pri)
    570 {
    571 	if (u3ht0 == NULL) return;
    572 
    573 	u3_ht_set_priority(u3ht0, cpu, pri);
    574 }
    575 
    576 static int
    577 u3_ht_read_irq(struct u3_ht_ops *u3_ht, int cpu)
    578 {
    579 	return u3_ht_read(u3_ht, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
    580 }
    581 
    582 static void
    583 u3_ht_eoi(struct u3_ht_ops *u3_ht, int cpu)
    584 {
    585 	u3_ht_write(u3_ht, OPENPIC_EOI(cpu), 0);
    586 	u3_ht_read(u3_ht, OPENPIC_EOI(cpu));
    587 }
    588 
    589 static uint32_t
    590 u3_ht_read_be(struct u3_ht_ops *u3_ht, u_int reg)
    591 {
    592 	volatile uint8_t *addr = u3_ht->ht_base + reg;
    593 
    594 	return in32(addr);
    595 }
    596 
    597 static void
    598 u3_ht_write_be(struct u3_ht_ops *u3_ht, u_int reg, uint32_t val)
    599 {
    600 	volatile uint8_t *addr = u3_ht->ht_base + reg;
    601 
    602 	out32(addr, val);
    603 }
    604 
    605 static uint32_t
    606 u3_ht_read_le(struct u3_ht_ops *u3_ht, u_int reg)
    607 {
    608 	volatile uint8_t *addr = u3_ht->ht_base + reg;
    609 
    610 	return in32rb(addr);
    611 }
    612 
    613 static void
    614 u3_ht_write_le(struct u3_ht_ops *u3_ht, u_int reg, uint32_t val)
    615 {
    616 	volatile uint8_t *addr = u3_ht->ht_base + reg;
    617 
    618 	out32rb(addr, val);
    619 }
    620 
    621 #ifdef MULTIPROCESSOR
    622 
    623 static void
    624 u3_ht_send_ipi(cpuid_t target, uint32_t mesg)
    625 {
    626 	struct cpu_info * const ci = curcpu();
    627 	uint32_t cpumask = 0;
    628 
    629 	switch (target) {
    630 		case IPI_DST_ALL:
    631 		case IPI_DST_NOTME:
    632 			for (u_int i = 0; i < ncpu; i++) {
    633 				struct cpu_info * const dst_ci = cpu_lookup(i);
    634 				if (target == IPI_DST_ALL || dst_ci != ci) {
    635 					cpumask |= 1 << cpu_index(dst_ci);
    636 					atomic_or_32(&dst_ci->ci_pending_ipis,
    637 					    mesg);
    638 				}
    639 			}
    640 			break;
    641 		default: {
    642 			struct cpu_info * const dst_ci = cpu_lookup(target);
    643 			cpumask = 1 << cpu_index(dst_ci);
    644 			atomic_or_32(&dst_ci->ci_pending_ipis, mesg);
    645 			break;
    646 		}
    647 	}
    648 	u3_ht_write(u3ht0, OPENPIC_IPI(cpu_index(ci), 1), cpumask);
    649 }
    650 
    651 static void
    652 u3_ht_establish_ipi(int type, int level, void *ih_args)
    653 {
    654 	intr_establish_xname(ipiops.ppc_ipi_vector, type, level, ipi_intr,
    655 	    ih_args, "u3_ht ipi");
    656 }
    657 
    658 #endif /*MULTIPROCESSOR*/
    659 
    660 int
    661 have_u3_ht(void)
    662 {
    663 	return (u3ht0 != NULL);
    664 }
    665