xref: /freebsd/sys/powerpc/powermac/cpcht.c (revision 7aa383846770374466b1dcb2cefd71bde9acf463)
1 /*-
2  * Copyright (C) 2008-2010 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/module.h>
31 #include <sys/bus.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/pciio.h>
35 #include <sys/rman.h>
36 
37 #include <dev/ofw/openfirm.h>
38 #include <dev/ofw/ofw_pci.h>
39 
40 #include <dev/pci/pcivar.h>
41 #include <dev/pci/pcireg.h>
42 
43 #include <machine/bus.h>
44 #include <machine/intr_machdep.h>
45 #include <machine/md_var.h>
46 #include <machine/openpicvar.h>
47 #include <machine/pio.h>
48 #include <machine/resource.h>
49 
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 #include <vm/vm.h>
54 #include <vm/pmap.h>
55 
56 #include "pcib_if.h"
57 #include "pic_if.h"
58 
59 /*
60  * IBM CPC9X5 Hypertransport Device interface.
61  */
62 static int		cpcht_probe(device_t);
63 static int		cpcht_attach(device_t);
64 
65 static void		cpcht_configure_htbridge(device_t, phandle_t);
66 
67 /*
68  * Bus interface.
69  */
70 static int		cpcht_read_ivar(device_t, device_t, int,
71 			    uintptr_t *);
72 static struct resource *cpcht_alloc_resource(device_t bus, device_t child,
73 			    int type, int *rid, u_long start, u_long end,
74 			    u_long count, u_int flags);
75 static int		cpcht_activate_resource(device_t bus, device_t child,
76 			    int type, int rid, struct resource *res);
77 static int		cpcht_release_resource(device_t bus, device_t child,
78 			    int type, int rid, struct resource *res);
79 static int		cpcht_deactivate_resource(device_t bus, device_t child,
80 			    int type, int rid, struct resource *res);
81 
82 /*
83  * pcib interface.
84  */
85 static int		cpcht_maxslots(device_t);
86 static u_int32_t	cpcht_read_config(device_t, u_int, u_int, u_int,
87 			    u_int, int);
88 static void		cpcht_write_config(device_t, u_int, u_int, u_int,
89 			    u_int, u_int32_t, int);
90 static int		cpcht_route_interrupt(device_t bus, device_t dev,
91 			    int pin);
92 static int		cpcht_alloc_msi(device_t dev, device_t child,
93 			    int count, int maxcount, int *irqs);
94 static int		cpcht_release_msi(device_t dev, device_t child,
95 			    int count, int *irqs);
96 static int		cpcht_alloc_msix(device_t dev, device_t child,
97 			    int *irq);
98 static int		cpcht_release_msix(device_t dev, device_t child,
99 			    int irq);
100 static int		cpcht_map_msi(device_t dev, device_t child,
101 			    int irq, uint64_t *addr, uint32_t *data);
102 
103 /*
104  * ofw_bus interface
105  */
106 
107 static phandle_t	cpcht_get_node(device_t bus, device_t child);
108 
109 /*
110  * Driver methods.
111  */
112 static device_method_t	cpcht_methods[] = {
113 	/* Device interface */
114 	DEVMETHOD(device_probe,		cpcht_probe),
115 	DEVMETHOD(device_attach,	cpcht_attach),
116 
117 	/* Bus interface */
118 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
119 	DEVMETHOD(bus_read_ivar,	cpcht_read_ivar),
120 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
121 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
122 	DEVMETHOD(bus_alloc_resource,	cpcht_alloc_resource),
123 	DEVMETHOD(bus_release_resource,	cpcht_release_resource),
124 	DEVMETHOD(bus_activate_resource,	cpcht_activate_resource),
125 	DEVMETHOD(bus_deactivate_resource,	cpcht_deactivate_resource),
126 
127 	/* pcib interface */
128 	DEVMETHOD(pcib_maxslots,	cpcht_maxslots),
129 	DEVMETHOD(pcib_read_config,	cpcht_read_config),
130 	DEVMETHOD(pcib_write_config,	cpcht_write_config),
131 	DEVMETHOD(pcib_route_interrupt,	cpcht_route_interrupt),
132 	DEVMETHOD(pcib_alloc_msi,	cpcht_alloc_msi),
133 	DEVMETHOD(pcib_release_msi,	cpcht_release_msi),
134 	DEVMETHOD(pcib_alloc_msix,	cpcht_alloc_msix),
135 	DEVMETHOD(pcib_release_msix,	cpcht_release_msix),
136 	DEVMETHOD(pcib_map_msi,		cpcht_map_msi),
137 
138 	/* ofw_bus interface */
139 	DEVMETHOD(ofw_bus_get_node,     cpcht_get_node),
140 	{ 0, 0 }
141 };
142 
143 struct cpcht_irq {
144 	enum {
145 	    IRQ_NONE, IRQ_HT, IRQ_MSI, IRQ_INTERNAL
146 	}		irq_type;
147 
148 	int		ht_source;
149 
150 	vm_offset_t	ht_base;
151 	vm_offset_t	apple_eoi;
152 	uint32_t	eoi_data;
153 	int		edge;
154 };
155 
156 static struct cpcht_irq *cpcht_irqmap = NULL;
157 uint32_t cpcht_msipic = 0;
158 
159 struct cpcht_softc {
160 	device_t		sc_dev;
161 	phandle_t		sc_node;
162 	vm_offset_t		sc_data;
163 	uint64_t		sc_populated_slots;
164 	struct			rman sc_mem_rman;
165 
166 	struct cpcht_irq	htirq_map[128];
167 	struct mtx		htirq_mtx;
168 };
169 
170 static driver_t	cpcht_driver = {
171 	"pcib",
172 	cpcht_methods,
173 	sizeof(struct cpcht_softc)
174 };
175 
176 static devclass_t	cpcht_devclass;
177 
178 DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
179 
180 #define HTAPIC_REQUEST_EOI	0x20
181 #define HTAPIC_TRIGGER_LEVEL	0x02
182 #define HTAPIC_MASK		0x01
183 
184 struct cpcht_range {
185 	u_int32_t       pci_hi;
186 	u_int32_t       pci_mid;
187 	u_int32_t       pci_lo;
188 	u_int32_t       junk;
189 	u_int32_t       host_hi;
190 	u_int32_t       host_lo;
191 	u_int32_t       size_hi;
192 	u_int32_t       size_lo;
193 };
194 
195 static int
196 cpcht_probe(device_t dev)
197 {
198 	const char	*type, *compatible;
199 
200 	type = ofw_bus_get_type(dev);
201 	compatible = ofw_bus_get_compat(dev);
202 
203 	if (type == NULL || compatible == NULL)
204 		return (ENXIO);
205 
206 	if (strcmp(type, "ht") != 0)
207 		return (ENXIO);
208 
209 	if (strcmp(compatible, "u3-ht") != 0)
210 		return (ENXIO);
211 
212 
213 	device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel");
214 	return (0);
215 }
216 
217 static int
218 cpcht_attach(device_t dev)
219 {
220 	struct		cpcht_softc *sc;
221 	phandle_t	node, child;
222 	u_int32_t	reg[3];
223 	int		i, error;
224 
225 	node = ofw_bus_get_node(dev);
226 	sc = device_get_softc(dev);
227 
228 	if (OF_getprop(node, "reg", reg, sizeof(reg)) < 12)
229 		return (ENXIO);
230 
231 	sc->sc_dev = dev;
232 	sc->sc_node = node;
233 	sc->sc_populated_slots = 0;
234 	sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]);
235 
236 	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
237 	sc->sc_mem_rman.rm_descr = "CPCHT Device Memory";
238 	error = rman_init(&sc->sc_mem_rman);
239 
240 	if (error) {
241 		device_printf(dev, "rman_init() failed. error = %d\n", error);
242 		return (error);
243 	}
244 
245 	/*
246 	 * Set up the resource manager and the HT->MPIC mapping. For cpcht,
247 	 * the ranges are properties of the child bridges, and this is also
248 	 * where we get the HT interrupts properties.
249 	 */
250 
251 	bzero(sc->htirq_map, sizeof(sc->htirq_map));
252 	mtx_init(&sc->htirq_mtx, "cpcht irq", NULL, MTX_DEF);
253 	for (i = 0; i < 8; i++)
254 		sc->htirq_map[i].irq_type = IRQ_INTERNAL;
255 	for (child = OF_child(node); child != 0; child = OF_peer(child))
256 		cpcht_configure_htbridge(dev, child);
257 
258 	/* Now make the mapping table available to the MPIC */
259 	cpcht_irqmap = sc->htirq_map;
260 
261 	device_add_child(dev, "pci", device_get_unit(dev));
262 
263 	return (bus_generic_attach(dev));
264 }
265 
266 static void
267 cpcht_configure_htbridge(device_t dev, phandle_t child)
268 {
269 	struct cpcht_softc *sc;
270 	struct ofw_pci_register pcir;
271 	struct cpcht_range ranges[6], *rp;
272 	int nranges, ptr, nextptr;
273 	uint32_t vend, val;
274 	int i, nirq, irq;
275 	u_int f, s;
276 
277 	sc = device_get_softc(dev);
278 	if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
279 		return;
280 
281 	s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
282 	f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
283 
284 	/*
285 	 * Mark this slot is populated. The remote south bridge does
286 	 * not like us talking to unpopulated slots on the root bus.
287 	 */
288 	sc->sc_populated_slots |= (1 << s);
289 
290 	/*
291 	 * Next grab this child bus's bus ranges.
292 	 */
293 	bzero(ranges, sizeof(ranges));
294 	nranges = OF_getprop(child, "ranges", ranges, sizeof(ranges));
295 
296 	ranges[6].pci_hi = 0;
297 	for (rp = ranges; rp->pci_hi != 0; rp++) {
298 		switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
299 		case OFW_PCI_PHYS_HI_SPACE_CONFIG:
300 			break;
301 		case OFW_PCI_PHYS_HI_SPACE_IO:
302 		case OFW_PCI_PHYS_HI_SPACE_MEM32:
303 			rman_manage_region(&sc->sc_mem_rman, rp->pci_lo,
304 			    rp->pci_lo + rp->size_lo - 1);
305 			break;
306 		case OFW_PCI_PHYS_HI_SPACE_MEM64:
307 			panic("64-bit CPCHT reserved memory!");
308 			break;
309 		}
310 	}
311 
312 	/*
313 	 * Next build up any HT->MPIC mappings for this sub-bus. One would
314 	 * naively hope that enabling, disabling, and EOIing interrupts would
315 	 * cause the appropriate HT bus transactions to that effect. This is
316 	 * not the case.
317 	 *
318 	 * Instead, we have to muck about on the HT peer's root PCI bridges,
319 	 * figure out what interrupts they send, enable them, and cache
320 	 * the location of their WaitForEOI registers so that we can
321 	 * send EOIs later.
322 	 */
323 
324 	/* All the devices we are interested in have caps */
325 	if (!(PCIB_READ_CONFIG(dev, 0, s, f, PCIR_STATUS, 2)
326 	    & PCIM_STATUS_CAPPRESENT))
327 		return;
328 
329 	nextptr = PCIB_READ_CONFIG(dev, 0, s, f, PCIR_CAP_PTR, 1);
330 	while (nextptr != 0) {
331 		ptr = nextptr;
332 		nextptr = PCIB_READ_CONFIG(dev, 0, s, f,
333 		    ptr + PCICAP_NEXTPTR, 1);
334 
335 		/* Find the HT IRQ capabilities */
336 		if (PCIB_READ_CONFIG(dev, 0, s, f,
337 		    ptr + PCICAP_ID, 1) != PCIY_HT)
338 			continue;
339 
340 		val = PCIB_READ_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 2);
341 		if ((val & PCIM_HTCMD_CAP_MASK) != PCIM_HTCAP_INTERRUPT)
342 			continue;
343 
344 		/* Ask for the IRQ count */
345 		PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1);
346 		nirq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
347 		nirq = ((nirq >> 16) & 0xff) + 1;
348 
349 		device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f);
350 
351 		for (i = 0; i < nirq; i++) {
352 			PCIB_WRITE_CONFIG(dev, 0, s, f,
353 			     ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1);
354 			irq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
355 
356 			/*
357 			 * Mask this interrupt for now.
358 			 */
359 			PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + 4,
360 			    irq | HTAPIC_MASK, 4);
361 			irq = (irq >> 16) & 0xff;
362 
363 			sc->htirq_map[irq].irq_type = IRQ_HT;
364 			sc->htirq_map[irq].ht_source = i;
365 			sc->htirq_map[irq].ht_base = sc->sc_data +
366 			    (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr));
367 
368 			PCIB_WRITE_CONFIG(dev, 0, s, f,
369 			     ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1);
370 			sc->htirq_map[irq].eoi_data =
371 			    PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4) |
372 			    0x80000000;
373 
374 			/*
375 			 * Apple uses a non-compliant IO/APIC that differs
376 			 * in how we signal EOIs. Check if this device was
377 			 * made by Apple, and act accordingly.
378 			 */
379 			vend = PCIB_READ_CONFIG(dev, 0, s, f,
380 			    PCIR_DEVVENDOR, 4);
381 			if ((vend & 0xffff) == 0x106b)
382 				sc->htirq_map[irq].apple_eoi =
383 				 (sc->htirq_map[irq].ht_base - ptr) + 0x60;
384 		}
385 	}
386 }
387 
388 static int
389 cpcht_maxslots(device_t dev)
390 {
391 
392 	return (PCI_SLOTMAX);
393 }
394 
395 static u_int32_t
396 cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
397     int width)
398 {
399 	struct		cpcht_softc *sc;
400 	vm_offset_t	caoff;
401 
402 	sc = device_get_softc(dev);
403 	caoff = sc->sc_data +
404 		(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
405 
406 	if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
407 		return (0xffffffff);
408 
409 	if (bus > 0)
410 		caoff += 0x01000000UL + (bus << 16);
411 
412 	switch (width) {
413 	case 1:
414 		return (in8rb(caoff));
415 		break;
416 	case 2:
417 		return (in16rb(caoff));
418 		break;
419 	case 4:
420 		return (in32rb(caoff));
421 		break;
422 	}
423 
424 	return (0xffffffff);
425 }
426 
427 static void
428 cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func,
429     u_int reg, u_int32_t val, int width)
430 {
431 	struct		cpcht_softc *sc;
432 	vm_offset_t	caoff;
433 
434 	sc = device_get_softc(dev);
435 	caoff = sc->sc_data +
436 		(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
437 
438 	if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
439 		return;
440 
441 	if (bus > 0)
442 		caoff += 0x01000000UL + (bus << 16);
443 
444 	switch (width) {
445 	case 1:
446 		out8rb(caoff, val);
447 		break;
448 	case 2:
449 		out16rb(caoff, val);
450 		break;
451 	case 4:
452 		out32rb(caoff, val);
453 		break;
454 	}
455 }
456 
457 static int
458 cpcht_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
459 {
460 	struct	cpcht_softc *sc;
461 
462 	sc = device_get_softc(dev);
463 
464 	switch (which) {
465 	case PCIB_IVAR_DOMAIN:
466 		*result = device_get_unit(dev);
467 		return (0);
468 	case PCIB_IVAR_BUS:
469 		*result = 0;	/* Root bus */
470 		return (0);
471 	}
472 
473 	return (ENOENT);
474 }
475 
476 static phandle_t
477 cpcht_get_node(device_t bus, device_t dev)
478 {
479 	struct cpcht_softc *sc;
480 
481 	sc = device_get_softc(bus);
482 	/* We only have one child, the PCI bus, which needs our own node. */
483 	return (sc->sc_node);
484 }
485 
486 static int
487 cpcht_route_interrupt(device_t bus, device_t dev, int pin)
488 {
489 	return (pin);
490 }
491 
492 static struct resource *
493 cpcht_alloc_resource(device_t bus, device_t child, int type, int *rid,
494     u_long start, u_long end, u_long count, u_int flags)
495 {
496 	struct			cpcht_softc *sc;
497 	struct			resource *rv;
498 	struct			rman *rm;
499 	int			needactivate, err;
500 
501 	needactivate = flags & RF_ACTIVE;
502 	flags &= ~RF_ACTIVE;
503 
504 	sc = device_get_softc(bus);
505 	err = 0;
506 
507 	switch (type) {
508 	case SYS_RES_IOPORT:
509 		end = min(end, start + count);
510 
511 		/* FALLTHROUGH */
512 	case SYS_RES_MEMORY:
513 		rm = &sc->sc_mem_rman;
514 		break;
515 
516 	case SYS_RES_IRQ:
517 		return (bus_alloc_resource(bus, type, rid, start, end, count,
518 		    flags));
519 
520 	default:
521 		device_printf(bus, "unknown resource request from %s\n",
522 		    device_get_nameunit(child));
523 		return (NULL);
524 	}
525 
526 	rv = rman_reserve_resource(rm, start, end, count, flags, child);
527 	if (rv == NULL) {
528 		device_printf(bus, "failed to reserve resource for %s\n",
529 		    device_get_nameunit(child));
530 		return (NULL);
531 	}
532 
533 	rman_set_rid(rv, *rid);
534 
535 	if (needactivate) {
536 		if (bus_activate_resource(child, type, *rid, rv) != 0) {
537 			device_printf(bus,
538 			    "failed to activate resource for %s\n",
539 			    device_get_nameunit(child));
540 			rman_release_resource(rv);
541 			return (NULL);
542 		}
543 	}
544 
545 	return (rv);
546 }
547 
548 static int
549 cpcht_activate_resource(device_t bus, device_t child, int type, int rid,
550     struct resource *res)
551 {
552 	void	*p;
553 	struct	cpcht_softc *sc;
554 
555 	sc = device_get_softc(bus);
556 
557 	if (type == SYS_RES_IRQ)
558 		return (bus_activate_resource(bus, type, rid, res));
559 
560 	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
561 		vm_offset_t start;
562 
563 		start = (vm_offset_t)rman_get_start(res);
564 
565 		if (bootverbose)
566 			printf("cpcht mapdev: start %zx, len %ld\n", start,
567 			    rman_get_size(res));
568 
569 		p = pmap_mapdev(start, (vm_size_t)rman_get_size(res));
570 		if (p == NULL)
571 			return (ENOMEM);
572 		rman_set_virtual(res, p);
573 		rman_set_bustag(res, &bs_le_tag);
574 		rman_set_bushandle(res, (u_long)p);
575 	}
576 
577 	return (rman_activate_resource(res));
578 }
579 
580 static int
581 cpcht_release_resource(device_t bus, device_t child, int type, int rid,
582     struct resource *res)
583 {
584 
585 	if (rman_get_flags(res) & RF_ACTIVE) {
586 		int error = bus_deactivate_resource(child, type, rid, res);
587 		if (error)
588 			return error;
589 	}
590 
591 	return (rman_release_resource(res));
592 }
593 
594 static int
595 cpcht_deactivate_resource(device_t bus, device_t child, int type, int rid,
596     struct resource *res)
597 {
598 
599 	/*
600 	 * If this is a memory resource, unmap it.
601 	 */
602 	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
603 		u_int32_t psize;
604 
605 		psize = rman_get_size(res);
606 		pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
607 	}
608 
609 	return (rman_deactivate_resource(res));
610 }
611 
612 static int
613 cpcht_alloc_msi(device_t dev, device_t child, int count, int maxcount,
614     int *irqs)
615 {
616 	struct cpcht_softc *sc;
617 	int i, j;
618 
619 	sc = device_get_softc(dev);
620 	j = 0;
621 
622 	/* Bail if no MSI PIC yet */
623 	if (cpcht_msipic == 0)
624 		return (ENXIO);
625 
626 	mtx_lock(&sc->htirq_mtx);
627 	for (i = 8; i < 124 - count; i++) {
628 		for (j = 0; j < count; j++) {
629 			if (sc->htirq_map[i+j].irq_type != IRQ_NONE)
630 				break;
631 		}
632 		if (j == count)
633 			break;
634 
635 		i += j; /* We know there isn't a large enough run */
636 	}
637 
638 	if (j != count) {
639 		mtx_unlock(&sc->htirq_mtx);
640 		return (ENXIO);
641 	}
642 
643 	for (j = 0; j < count; j++) {
644 		irqs[j] = INTR_VEC(cpcht_msipic, i+j);
645 		sc->htirq_map[i+j].irq_type = IRQ_MSI;
646 	}
647 	mtx_unlock(&sc->htirq_mtx);
648 
649 	return (0);
650 }
651 
652 static int
653 cpcht_release_msi(device_t dev, device_t child, int count, int *irqs)
654 {
655 	struct cpcht_softc *sc;
656 	int i;
657 
658 	sc = device_get_softc(dev);
659 
660 	mtx_lock(&sc->htirq_mtx);
661 	for (i = 0; i < count; i++)
662 		sc->htirq_map[irqs[i] & 0xff].irq_type = IRQ_NONE;
663 	mtx_unlock(&sc->htirq_mtx);
664 
665 	return (0);
666 }
667 
668 static int
669 cpcht_alloc_msix(device_t dev, device_t child, int *irq)
670 {
671 	struct cpcht_softc *sc;
672 	int i;
673 
674 	sc = device_get_softc(dev);
675 
676 	/* Bail if no MSI PIC yet */
677 	if (cpcht_msipic == 0)
678 		return (ENXIO);
679 
680 	mtx_lock(&sc->htirq_mtx);
681 	for (i = 8; i < 124; i++) {
682 		if (sc->htirq_map[i].irq_type == IRQ_NONE) {
683 			sc->htirq_map[i].irq_type = IRQ_MSI;
684 			*irq = INTR_VEC(cpcht_msipic, i);
685 
686 			mtx_unlock(&sc->htirq_mtx);
687 			return (0);
688 		}
689 	}
690 	mtx_unlock(&sc->htirq_mtx);
691 
692 	return (ENXIO);
693 }
694 
695 static int
696 cpcht_release_msix(device_t dev, device_t child, int irq)
697 {
698 	struct cpcht_softc *sc;
699 
700 	sc = device_get_softc(dev);
701 
702 	mtx_lock(&sc->htirq_mtx);
703 	sc->htirq_map[irq & 0xff].irq_type = IRQ_NONE;
704 	mtx_unlock(&sc->htirq_mtx);
705 
706 	return (0);
707 }
708 
709 static int
710 cpcht_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
711     uint32_t *data)
712 {
713 	device_t pcib;
714 	struct pci_devinfo *dinfo;
715 	struct pcicfg_ht *ht = NULL;
716 
717 	for (pcib = child; pcib != dev; pcib =
718 	    device_get_parent(device_get_parent(pcib))) {
719 		dinfo = device_get_ivars(pcib);
720 		ht = &dinfo->cfg.ht;
721 
722 		if (ht == NULL)
723 			continue;
724 	}
725 
726 	if (ht == NULL)
727 		return (ENXIO);
728 
729 	*addr = ht->ht_msiaddr;
730 	*data = irq & 0xff;
731 
732 	return (0);
733 }
734 
735 /*
736  * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945)
737  */
738 
739 static int	openpic_cpcht_probe(device_t);
740 static int	openpic_cpcht_attach(device_t);
741 static void	openpic_cpcht_config(device_t, u_int irq,
742 		    enum intr_trigger trig, enum intr_polarity pol);
743 static void	openpic_cpcht_enable(device_t, u_int irq, u_int vector);
744 static void	openpic_cpcht_unmask(device_t, u_int irq);
745 static void	openpic_cpcht_eoi(device_t, u_int irq);
746 static uint32_t	openpic_cpcht_id(device_t);
747 
748 static device_method_t  openpic_cpcht_methods[] = {
749 	/* Device interface */
750 	DEVMETHOD(device_probe,		openpic_cpcht_probe),
751 	DEVMETHOD(device_attach,	openpic_cpcht_attach),
752 
753 	/* PIC interface */
754 	DEVMETHOD(pic_bind,		openpic_bind),
755 	DEVMETHOD(pic_config,		openpic_cpcht_config),
756 	DEVMETHOD(pic_dispatch,		openpic_dispatch),
757 	DEVMETHOD(pic_enable,		openpic_cpcht_enable),
758 	DEVMETHOD(pic_eoi,		openpic_cpcht_eoi),
759 	DEVMETHOD(pic_ipi,		openpic_ipi),
760 	DEVMETHOD(pic_mask,		openpic_mask),
761 	DEVMETHOD(pic_unmask,		openpic_cpcht_unmask),
762 	DEVMETHOD(pic_id,		openpic_cpcht_id),
763 
764 	{ 0, 0 },
765 };
766 
767 struct openpic_cpcht_softc {
768 	struct openpic_softc sc_openpic;
769 
770 	struct mtx sc_ht_mtx;
771 };
772 
773 static driver_t openpic_cpcht_driver = {
774 	"htpic",
775 	openpic_cpcht_methods,
776 	sizeof(struct openpic_cpcht_softc),
777 };
778 
779 DRIVER_MODULE(openpic, unin, openpic_cpcht_driver, openpic_devclass, 0, 0);
780 
781 static int
782 openpic_cpcht_probe(device_t dev)
783 {
784 	const char *type = ofw_bus_get_type(dev);
785 
786 	if (strcmp(type, "open-pic") != 0)
787                 return (ENXIO);
788 
789 	device_set_desc(dev, OPENPIC_DEVSTR);
790 	return (0);
791 }
792 
793 static int
794 openpic_cpcht_attach(device_t dev)
795 {
796 	struct openpic_cpcht_softc *sc;
797 	int err, irq;
798 
799 	err = openpic_attach(dev);
800 	if (err != 0)
801 		return (err);
802 
803 	/*
804 	 * The HT APIC stuff is not thread-safe, so we need a mutex to
805 	 * protect it.
806 	 */
807 	sc = device_get_softc(dev);
808 	mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN);
809 
810 	/*
811 	 * Interrupts 0-3 are internally sourced and are level triggered
812 	 * active low. Interrupts 4-123 are connected to a pulse generator
813 	 * and should be programmed as edge triggered low-to-high.
814 	 *
815 	 * IBM CPC945 Manual, Section 9.3.
816 	 */
817 
818 	for (irq = 0; irq < 4; irq++)
819 		openpic_config(dev, irq, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
820 	for (irq = 4; irq < 124; irq++)
821 		openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
822 
823 	/*
824 	 * Use this PIC for MSI only if it is the root PIC. This may not
825 	 * be necessary, but Linux does it, and I cannot find any U3 machines
826 	 * with MSI devices to test.
827 	 */
828 
829 	if (dev == root_pic)
830 		cpcht_msipic = PIC_ID(dev);
831 
832 	return (0);
833 }
834 
835 static void
836 openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig,
837     enum intr_polarity pol)
838 {
839 	struct openpic_cpcht_softc *sc;
840 	uint32_t ht_irq;
841 
842 	/*
843 	 * The interrupt settings for the MPIC are completely determined
844 	 * by the internal wiring in the northbridge. Real changes to these
845 	 * settings need to be negotiated with the remote IO-APIC on the HT
846 	 * link.
847 	 */
848 
849 	sc = device_get_softc(dev);
850 
851 	if (cpcht_irqmap != NULL && irq < 128 &&
852 	    cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
853 		mtx_lock_spin(&sc->sc_ht_mtx);
854 
855 		/* Program the data port */
856 		out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
857 		    0x10 + (cpcht_irqmap[irq].ht_source << 1));
858 
859 		/* Grab the IRQ config register */
860 		ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
861 
862 		/* Mask the IRQ while we fiddle settings */
863 		out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK);
864 
865 		/* Program the interrupt sense */
866 		ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI);
867 		if (trig == INTR_TRIGGER_EDGE) {
868 			cpcht_irqmap[irq].edge = 1;
869 		} else {
870 			cpcht_irqmap[irq].edge = 0;
871 			ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI;
872 		}
873 		out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
874 
875 		mtx_unlock_spin(&sc->sc_ht_mtx);
876 	}
877 }
878 
879 static void
880 openpic_cpcht_enable(device_t dev, u_int irq, u_int vec)
881 {
882 	struct openpic_cpcht_softc *sc;
883 	uint32_t ht_irq;
884 
885 	openpic_enable(dev, irq, vec);
886 
887 	sc = device_get_softc(dev);
888 
889 	if (cpcht_irqmap != NULL && irq < 128 &&
890 	    cpcht_irqmap[irq].ht_base > 0) {
891 		mtx_lock_spin(&sc->sc_ht_mtx);
892 
893 		/* Program the data port */
894 		out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
895 		    0x10 + (cpcht_irqmap[irq].ht_source << 1));
896 
897 		/* Unmask the interrupt */
898 		ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
899 		ht_irq &= ~HTAPIC_MASK;
900 		out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
901 
902 		mtx_unlock_spin(&sc->sc_ht_mtx);
903 	}
904 
905 	openpic_cpcht_eoi(dev, irq);
906 }
907 
908 static void
909 openpic_cpcht_unmask(device_t dev, u_int irq)
910 {
911 	struct openpic_cpcht_softc *sc;
912 	uint32_t ht_irq;
913 
914 	openpic_unmask(dev, irq);
915 
916 	sc = device_get_softc(dev);
917 
918 	if (cpcht_irqmap != NULL && irq < 128 &&
919 	    cpcht_irqmap[irq].ht_base > 0) {
920 		mtx_lock_spin(&sc->sc_ht_mtx);
921 
922 		/* Program the data port */
923 		out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
924 		    0x10 + (cpcht_irqmap[irq].ht_source << 1));
925 
926 		/* Unmask the interrupt */
927 		ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
928 		ht_irq &= ~HTAPIC_MASK;
929 		out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
930 
931 		mtx_unlock_spin(&sc->sc_ht_mtx);
932 	}
933 
934 	openpic_cpcht_eoi(dev, irq);
935 }
936 
937 static void
938 openpic_cpcht_eoi(device_t dev, u_int irq)
939 {
940 	struct openpic_cpcht_softc *sc;
941 	uint32_t off, mask;
942 
943 	if (irq == 255)
944 		return;
945 
946 	sc = device_get_softc(dev);
947 
948 	if (cpcht_irqmap != NULL && irq < 128 &&
949 	    cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
950 		/* If this is an HT IRQ, acknowledge it at the remote APIC */
951 
952 		if (cpcht_irqmap[irq].apple_eoi) {
953 			off = (cpcht_irqmap[irq].ht_source >> 3) & ~3;
954 			mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f);
955 			out32rb(cpcht_irqmap[irq].apple_eoi + off, mask);
956 		} else {
957 			mtx_lock_spin(&sc->sc_ht_mtx);
958 
959 			out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
960 			    0x11 + (cpcht_irqmap[irq].ht_source << 1));
961 			out32rb(cpcht_irqmap[irq].ht_base + 4,
962 			    cpcht_irqmap[irq].eoi_data);
963 
964 			mtx_unlock_spin(&sc->sc_ht_mtx);
965 		}
966 	}
967 
968 	openpic_eoi(dev, irq);
969 }
970 
971 static uint32_t
972 openpic_cpcht_id(device_t dev)
973 {
974 	return (ofw_bus_get_node(dev));
975 }
976 
977