]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powermac/cpcht.c
Upgrade our Clang in base to r114020, from upstream's release_28 branch.
[FreeBSD/FreeBSD.git] / sys / powerpc / powermac / cpcht.c
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