The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/powermac/cpcht.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/module.h>
   32 #include <sys/bus.h>
   33 #include <sys/conf.h>
   34 #include <sys/kernel.h>
   35 #include <sys/pciio.h>
   36 #include <sys/rman.h>
   37 
   38 #include <dev/ofw/openfirm.h>
   39 #include <dev/ofw/ofw_pci.h>
   40 
   41 #include <dev/pci/pcivar.h>
   42 #include <dev/pci/pcireg.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/intr_machdep.h>
   46 #include <machine/md_var.h>
   47 #include <machine/openpicvar.h>
   48 #include <machine/pio.h>
   49 #include <machine/resource.h>
   50 
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 #include <powerpc/ofw/ofw_pci.h>
   54 
   55 #include <vm/vm.h>
   56 #include <vm/pmap.h>
   57 
   58 #include "pcib_if.h"
   59 #include "pic_if.h"
   60 
   61 /*
   62  * IBM CPC9X5 Hypertransport Device interface.
   63  */
   64 static int              cpcht_probe(device_t);
   65 static int              cpcht_attach(device_t);
   66 
   67 static void             cpcht_configure_htbridge(device_t, phandle_t);
   68 
   69 /*
   70  * pcib interface.
   71  */
   72 static u_int32_t        cpcht_read_config(device_t, u_int, u_int, u_int,
   73                             u_int, int);
   74 static void             cpcht_write_config(device_t, u_int, u_int, u_int,
   75                             u_int, u_int32_t, int);
   76 static int              cpcht_route_interrupt(device_t, device_t, int);
   77 static int              cpcht_alloc_msi(device_t dev, device_t child,
   78                             int count, int maxcount, int *irqs);
   79 static int              cpcht_release_msi(device_t dev, device_t child,
   80                             int count, int *irqs);
   81 static int              cpcht_alloc_msix(device_t dev, device_t child,
   82                             int *irq);
   83 static int              cpcht_release_msix(device_t dev, device_t child,
   84                             int irq);
   85 static int              cpcht_map_msi(device_t dev, device_t child,
   86                             int irq, uint64_t *addr, uint32_t *data);
   87 
   88 /*
   89  * Driver methods.
   90  */
   91 static device_method_t  cpcht_methods[] = {
   92         /* Device interface */
   93         DEVMETHOD(device_probe,         cpcht_probe),
   94         DEVMETHOD(device_attach,        cpcht_attach),
   95 
   96         /* pcib interface */
   97         DEVMETHOD(pcib_read_config,     cpcht_read_config),
   98         DEVMETHOD(pcib_write_config,    cpcht_write_config),
   99         DEVMETHOD(pcib_route_interrupt, cpcht_route_interrupt),
  100         DEVMETHOD(pcib_alloc_msi,       cpcht_alloc_msi),
  101         DEVMETHOD(pcib_release_msi,     cpcht_release_msi),
  102         DEVMETHOD(pcib_alloc_msix,      cpcht_alloc_msix),
  103         DEVMETHOD(pcib_release_msix,    cpcht_release_msix),
  104         DEVMETHOD(pcib_map_msi,         cpcht_map_msi),
  105 
  106         DEVMETHOD_END
  107 };
  108 
  109 struct cpcht_irq {
  110         enum {
  111             IRQ_NONE, IRQ_HT, IRQ_MSI, IRQ_INTERNAL
  112         }               irq_type; 
  113 
  114         int             ht_source;
  115 
  116         vm_offset_t     ht_base;
  117         vm_offset_t     apple_eoi;
  118         uint32_t        eoi_data;
  119         int             edge;
  120 };
  121 
  122 static struct cpcht_irq *cpcht_irqmap = NULL;
  123 uint32_t cpcht_msipic = 0;
  124 
  125 struct cpcht_softc {
  126         struct ofw_pci_softc    pci_sc;
  127         vm_offset_t             sc_data;
  128         uint64_t                sc_populated_slots;
  129 
  130         struct cpcht_irq        htirq_map[128];
  131         struct mtx              htirq_mtx;
  132 };
  133 
  134 static devclass_t       cpcht_devclass;
  135 DEFINE_CLASS_1(pcib, cpcht_driver, cpcht_methods, sizeof(struct cpcht_softc),
  136     ofw_pci_driver);
  137 DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
  138 
  139 #define CPCHT_IOPORT_BASE       0xf4000000UL /* Hardwired */
  140 #define CPCHT_IOPORT_SIZE       0x00400000UL
  141 
  142 #define HTAPIC_REQUEST_EOI      0x20
  143 #define HTAPIC_TRIGGER_LEVEL    0x02
  144 #define HTAPIC_MASK             0x01
  145 
  146 static int
  147 cpcht_probe(device_t dev)
  148 {
  149         const char      *type, *compatible;
  150 
  151         type = ofw_bus_get_type(dev);
  152         compatible = ofw_bus_get_compat(dev);
  153 
  154         if (type == NULL || compatible == NULL)
  155                 return (ENXIO);
  156 
  157         if (strcmp(type, "ht") != 0)
  158                 return (ENXIO);
  159 
  160         if (strcmp(compatible, "u3-ht") != 0)
  161                 return (ENXIO);
  162 
  163         device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel");
  164         return (0);
  165 }
  166 
  167 static int
  168 cpcht_attach(device_t dev)
  169 {
  170         struct          cpcht_softc *sc;
  171         phandle_t       node, child;
  172         u_int32_t       reg[3];
  173         int             i;
  174 
  175         node = ofw_bus_get_node(dev);
  176         sc = device_get_softc(dev);
  177 
  178         if (OF_getprop(node, "reg", reg, sizeof(reg)) < 12)
  179                 return (ENXIO);
  180 
  181         if (OF_getproplen(node, "ranges") <= 0)
  182                 sc->pci_sc.sc_quirks = OFW_PCI_QUIRK_RANGES_ON_CHILDREN;
  183         sc->sc_populated_slots = 0;
  184         sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]);
  185 
  186         /*
  187          * Set up the resource manager and the HT->MPIC mapping. For cpcht,
  188          * the ranges are properties of the child bridges, and this is also
  189          * where we get the HT interrupts properties.
  190          */
  191 
  192 #if 0
  193         /* I/O port mappings are usually not in the device tree */
  194         rman_manage_region(&sc->pci_sc.sc_io_rman, 0, CPCHT_IOPORT_SIZE - 1);
  195 #endif
  196 
  197         bzero(sc->htirq_map, sizeof(sc->htirq_map));
  198         mtx_init(&sc->htirq_mtx, "cpcht irq", NULL, MTX_DEF);
  199         for (i = 0; i < 8; i++)
  200                 sc->htirq_map[i].irq_type = IRQ_INTERNAL;
  201         for (child = OF_child(node); child != 0; child = OF_peer(child))
  202                 cpcht_configure_htbridge(dev, child);
  203 
  204         /* Now make the mapping table available to the MPIC */
  205         cpcht_irqmap = sc->htirq_map;
  206 
  207         return (ofw_pci_attach(dev));
  208 }
  209 
  210 static void
  211 cpcht_configure_htbridge(device_t dev, phandle_t child)
  212 {
  213         struct cpcht_softc *sc;
  214         struct ofw_pci_register pcir;
  215         int ptr, nextptr;
  216         uint32_t vend, val;
  217         int i, nirq, irq;
  218         u_int b, f, s;
  219 
  220         sc = device_get_softc(dev);
  221         if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
  222                 return;
  223 
  224         b = OFW_PCI_PHYS_HI_BUS(pcir.phys_hi);
  225         s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
  226         f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
  227 
  228         /*
  229          * Mark this slot is populated. The remote south bridge does
  230          * not like us talking to unpopulated slots on the root bus.
  231          */
  232         sc->sc_populated_slots |= (1 << s);
  233 
  234         /*
  235          * Next build up any HT->MPIC mappings for this sub-bus. One would
  236          * naively hope that enabling, disabling, and EOIing interrupts would
  237          * cause the appropriate HT bus transactions to that effect. This is
  238          * not the case.
  239          *
  240          * Instead, we have to muck about on the HT peer's root PCI bridges,
  241          * figure out what interrupts they send, enable them, and cache
  242          * the location of their WaitForEOI registers so that we can
  243          * send EOIs later.
  244          */
  245 
  246         /* All the devices we are interested in have caps */
  247         if (!(PCIB_READ_CONFIG(dev, b, s, f, PCIR_STATUS, 2)
  248             & PCIM_STATUS_CAPPRESENT))
  249                 return;
  250 
  251         nextptr = PCIB_READ_CONFIG(dev, b, s, f, PCIR_CAP_PTR, 1);
  252         while (nextptr != 0) {
  253                 ptr = nextptr;
  254                 nextptr = PCIB_READ_CONFIG(dev, b, s, f,
  255                     ptr + PCICAP_NEXTPTR, 1);
  256 
  257                 /* Find the HT IRQ capabilities */
  258                 if (PCIB_READ_CONFIG(dev, b, s, f,
  259                     ptr + PCICAP_ID, 1) != PCIY_HT)
  260                         continue;
  261 
  262                 val = PCIB_READ_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 2);
  263                 if ((val & PCIM_HTCMD_CAP_MASK) != PCIM_HTCAP_INTERRUPT)
  264                         continue;
  265 
  266                 /* Ask for the IRQ count */
  267                 PCIB_WRITE_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1);
  268                 nirq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4);
  269                 nirq = ((nirq >> 16) & 0xff) + 1;
  270 
  271                 device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f);
  272 
  273                 for (i = 0; i < nirq; i++) {
  274                         PCIB_WRITE_CONFIG(dev, b, s, f,
  275                              ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1);
  276                         irq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4);
  277 
  278                         /*
  279                          * Mask this interrupt for now.
  280                          */
  281                         PCIB_WRITE_CONFIG(dev, b, s, f, ptr + 4,
  282                             irq | HTAPIC_MASK, 4);
  283                         irq = (irq >> 16) & 0xff;
  284 
  285                         sc->htirq_map[irq].irq_type = IRQ_HT;
  286                         sc->htirq_map[irq].ht_source = i;
  287                         sc->htirq_map[irq].ht_base = sc->sc_data + 
  288                             (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr));
  289 
  290                         PCIB_WRITE_CONFIG(dev, b, s, f,
  291                              ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1);
  292                         sc->htirq_map[irq].eoi_data =
  293                             PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4) |
  294                             0x80000000;
  295 
  296                         /*
  297                          * Apple uses a non-compliant IO/APIC that differs
  298                          * in how we signal EOIs. Check if this device was 
  299                          * made by Apple, and act accordingly.
  300                          */
  301                         vend = PCIB_READ_CONFIG(dev, b, s, f,
  302                             PCIR_DEVVENDOR, 4);
  303                         if ((vend & 0xffff) == 0x106b)
  304                                 sc->htirq_map[irq].apple_eoi = 
  305                                  (sc->htirq_map[irq].ht_base - ptr) + 0x60;
  306                 }
  307         }
  308 }
  309 
  310 static u_int32_t
  311 cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
  312     int width)
  313 {
  314         struct          cpcht_softc *sc;
  315         vm_offset_t     caoff;
  316 
  317         sc = device_get_softc(dev);
  318         caoff = sc->sc_data + 
  319                 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
  320 
  321         if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
  322                 return (0xffffffff);
  323 
  324         if (bus > 0)
  325                 caoff += 0x01000000UL + (bus << 16);
  326 
  327         switch (width) {
  328         case 1:
  329                 return (in8rb(caoff));
  330                 break;
  331         case 2:
  332                 return (in16rb(caoff));
  333                 break;
  334         case 4:
  335                 return (in32rb(caoff));
  336                 break;
  337         }
  338 
  339         return (0xffffffff);
  340 }
  341 
  342 static void
  343 cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func,
  344     u_int reg, u_int32_t val, int width)
  345 {
  346         struct          cpcht_softc *sc;
  347         vm_offset_t     caoff;
  348 
  349         sc = device_get_softc(dev);
  350         caoff = sc->sc_data + 
  351                 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
  352 
  353         if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
  354                 return;
  355 
  356         if (bus > 0)
  357                 caoff += 0x01000000UL + (bus << 16);
  358 
  359         switch (width) {
  360         case 1:
  361                 out8rb(caoff, val);
  362                 break;
  363         case 2:
  364                 out16rb(caoff, val);
  365                 break;
  366         case 4:
  367                 out32rb(caoff, val);
  368                 break;
  369         }
  370 }
  371 
  372 static int
  373 cpcht_route_interrupt(device_t bus, device_t dev, int pin)
  374 {
  375         return (pin);
  376 }
  377 
  378 static int
  379 cpcht_alloc_msi(device_t dev, device_t child, int count, int maxcount,
  380     int *irqs)
  381 {
  382         struct cpcht_softc *sc;
  383         int i, j;
  384 
  385         sc = device_get_softc(dev);
  386         j = 0;
  387 
  388         /* Bail if no MSI PIC yet */
  389         if (cpcht_msipic == 0)
  390                 return (ENXIO);
  391 
  392         mtx_lock(&sc->htirq_mtx);
  393         for (i = 8; i < 124 - count; i++) {
  394                 for (j = 0; j < count; j++) {
  395                         if (sc->htirq_map[i+j].irq_type != IRQ_NONE)
  396                                 break;
  397                 }
  398                 if (j == count)
  399                         break;
  400 
  401                 i += j; /* We know there isn't a large enough run */
  402         }
  403 
  404         if (j != count) {
  405                 mtx_unlock(&sc->htirq_mtx);
  406                 return (ENXIO);
  407         }
  408 
  409         for (j = 0; j < count; j++) {
  410                 irqs[j] = MAP_IRQ(cpcht_msipic, i+j);
  411                 sc->htirq_map[i+j].irq_type = IRQ_MSI;
  412         }
  413         mtx_unlock(&sc->htirq_mtx);
  414 
  415         return (0);
  416 }
  417 
  418 static int
  419 cpcht_release_msi(device_t dev, device_t child, int count, int *irqs)
  420 {
  421         struct cpcht_softc *sc;
  422         int i;
  423 
  424         sc = device_get_softc(dev);
  425 
  426         mtx_lock(&sc->htirq_mtx);
  427         for (i = 0; i < count; i++)
  428                 sc->htirq_map[irqs[i] & 0xff].irq_type = IRQ_NONE;
  429         mtx_unlock(&sc->htirq_mtx);
  430 
  431         return (0);
  432 }
  433 
  434 static int
  435 cpcht_alloc_msix(device_t dev, device_t child, int *irq)
  436 {
  437         struct cpcht_softc *sc;
  438         int i;
  439 
  440         sc = device_get_softc(dev);
  441 
  442         /* Bail if no MSI PIC yet */
  443         if (cpcht_msipic == 0)
  444                 return (ENXIO);
  445 
  446         mtx_lock(&sc->htirq_mtx);
  447         for (i = 8; i < 124; i++) {
  448                 if (sc->htirq_map[i].irq_type == IRQ_NONE) {
  449                         sc->htirq_map[i].irq_type = IRQ_MSI;
  450                         *irq = MAP_IRQ(cpcht_msipic, i);
  451 
  452                         mtx_unlock(&sc->htirq_mtx);
  453                         return (0);
  454                 }
  455         }
  456         mtx_unlock(&sc->htirq_mtx);
  457 
  458         return (ENXIO);
  459 }
  460         
  461 static int
  462 cpcht_release_msix(device_t dev, device_t child, int irq)
  463 {
  464         struct cpcht_softc *sc;
  465 
  466         sc = device_get_softc(dev);
  467 
  468         mtx_lock(&sc->htirq_mtx);
  469         sc->htirq_map[irq & 0xff].irq_type = IRQ_NONE;
  470         mtx_unlock(&sc->htirq_mtx);
  471 
  472         return (0);
  473 }
  474 
  475 static int
  476 cpcht_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
  477     uint32_t *data)
  478 {
  479         device_t pcib;
  480         struct pci_devinfo *dinfo;
  481         struct pcicfg_ht *ht = NULL;
  482 
  483         for (pcib = child; pcib != dev; pcib =
  484             device_get_parent(device_get_parent(pcib))) {
  485                 dinfo = device_get_ivars(pcib);
  486                 ht = &dinfo->cfg.ht;
  487 
  488                 if (ht == NULL)
  489                         continue;
  490         }
  491 
  492         if (ht == NULL)
  493                 return (ENXIO);
  494 
  495         *addr = ht->ht_msiaddr;
  496         *data = irq & 0xff;
  497 
  498         return (0);
  499 }
  500 
  501 /*
  502  * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945)
  503  */
  504 
  505 static int      openpic_cpcht_probe(device_t);
  506 static int      openpic_cpcht_attach(device_t);
  507 static void     openpic_cpcht_config(device_t, u_int irq,
  508                     enum intr_trigger trig, enum intr_polarity pol);
  509 static void     openpic_cpcht_enable(device_t, u_int irq, u_int vector);
  510 static void     openpic_cpcht_unmask(device_t, u_int irq);
  511 static void     openpic_cpcht_eoi(device_t, u_int irq);
  512 
  513 static device_method_t  openpic_cpcht_methods[] = {
  514         /* Device interface */
  515         DEVMETHOD(device_probe,         openpic_cpcht_probe),
  516         DEVMETHOD(device_attach,        openpic_cpcht_attach),
  517 
  518         /* PIC interface */
  519         DEVMETHOD(pic_bind,             openpic_bind),
  520         DEVMETHOD(pic_config,           openpic_cpcht_config),
  521         DEVMETHOD(pic_dispatch,         openpic_dispatch),
  522         DEVMETHOD(pic_enable,           openpic_cpcht_enable),
  523         DEVMETHOD(pic_eoi,              openpic_cpcht_eoi),
  524         DEVMETHOD(pic_ipi,              openpic_ipi),
  525         DEVMETHOD(pic_mask,             openpic_mask),
  526         DEVMETHOD(pic_unmask,           openpic_cpcht_unmask),
  527 
  528         { 0, 0 },
  529 };
  530 
  531 struct openpic_cpcht_softc {
  532         struct openpic_softc sc_openpic;
  533 
  534         struct mtx sc_ht_mtx;
  535 };
  536 
  537 static driver_t openpic_cpcht_driver = {
  538         "htpic",
  539         openpic_cpcht_methods,
  540         sizeof(struct openpic_cpcht_softc),
  541 };
  542 
  543 DRIVER_MODULE(openpic, unin, openpic_cpcht_driver, openpic_devclass, 0, 0);
  544 
  545 static int
  546 openpic_cpcht_probe(device_t dev)
  547 {
  548         const char *type = ofw_bus_get_type(dev);
  549 
  550         if (strcmp(type, "open-pic") != 0)
  551                 return (ENXIO);
  552 
  553         device_set_desc(dev, OPENPIC_DEVSTR);
  554         return (0);
  555 }
  556 
  557 static int
  558 openpic_cpcht_attach(device_t dev)
  559 {
  560         struct openpic_cpcht_softc *sc;
  561         phandle_t node;
  562         int err, irq;
  563 
  564         node = ofw_bus_get_node(dev);
  565         err = openpic_common_attach(dev, node);
  566         if (err != 0)
  567                 return (err);
  568 
  569         /*
  570          * The HT APIC stuff is not thread-safe, so we need a mutex to
  571          * protect it.
  572          */
  573         sc = device_get_softc(dev);
  574         mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN);
  575 
  576         /*
  577          * Interrupts 0-3 are internally sourced and are level triggered
  578          * active low. Interrupts 4-123 are connected to a pulse generator
  579          * and should be programmed as edge triggered low-to-high.
  580          * 
  581          * IBM CPC945 Manual, Section 9.3.
  582          */
  583 
  584         for (irq = 0; irq < 4; irq++)
  585                 openpic_config(dev, irq, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
  586         for (irq = 4; irq < 124; irq++)
  587                 openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
  588 
  589         /*
  590          * Use this PIC for MSI only if it is the root PIC. This may not
  591          * be necessary, but Linux does it, and I cannot find any U3 machines
  592          * with MSI devices to test.
  593          */
  594         if (dev == root_pic)
  595                 cpcht_msipic = node;
  596 
  597         return (0);
  598 }
  599 
  600 static void
  601 openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig,
  602     enum intr_polarity pol)
  603 {
  604         struct openpic_cpcht_softc *sc;
  605         uint32_t ht_irq;
  606 
  607         /*
  608          * The interrupt settings for the MPIC are completely determined
  609          * by the internal wiring in the northbridge. Real changes to these
  610          * settings need to be negotiated with the remote IO-APIC on the HT
  611          * link.
  612          */
  613 
  614         sc = device_get_softc(dev);
  615 
  616         if (cpcht_irqmap != NULL && irq < 128 &&
  617             cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
  618                 mtx_lock_spin(&sc->sc_ht_mtx);
  619 
  620                 /* Program the data port */
  621                 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  622                     0x10 + (cpcht_irqmap[irq].ht_source << 1));
  623 
  624                 /* Grab the IRQ config register */
  625                 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  626 
  627                 /* Mask the IRQ while we fiddle settings */
  628                 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK);
  629                 
  630                 /* Program the interrupt sense */
  631                 ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI);
  632                 if (trig == INTR_TRIGGER_EDGE) {
  633                         cpcht_irqmap[irq].edge = 1;
  634                 } else {
  635                         cpcht_irqmap[irq].edge = 0;
  636                         ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI;
  637                 }
  638                 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  639 
  640                 mtx_unlock_spin(&sc->sc_ht_mtx);
  641         }
  642 }
  643 
  644 static void
  645 openpic_cpcht_enable(device_t dev, u_int irq, u_int vec)
  646 {
  647         struct openpic_cpcht_softc *sc;
  648         uint32_t ht_irq;
  649 
  650         openpic_enable(dev, irq, vec);
  651 
  652         sc = device_get_softc(dev);
  653 
  654         if (cpcht_irqmap != NULL && irq < 128 &&
  655             cpcht_irqmap[irq].ht_base > 0) {
  656                 mtx_lock_spin(&sc->sc_ht_mtx);
  657 
  658                 /* Program the data port */
  659                 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  660                     0x10 + (cpcht_irqmap[irq].ht_source << 1));
  661 
  662                 /* Unmask the interrupt */
  663                 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  664                 ht_irq &= ~HTAPIC_MASK;
  665                 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  666 
  667                 mtx_unlock_spin(&sc->sc_ht_mtx);
  668         }
  669                 
  670         openpic_cpcht_eoi(dev, irq);
  671 }
  672 
  673 static void
  674 openpic_cpcht_unmask(device_t dev, u_int irq)
  675 {
  676         struct openpic_cpcht_softc *sc;
  677         uint32_t ht_irq;
  678 
  679         openpic_unmask(dev, irq);
  680 
  681         sc = device_get_softc(dev);
  682 
  683         if (cpcht_irqmap != NULL && irq < 128 &&
  684             cpcht_irqmap[irq].ht_base > 0) {
  685                 mtx_lock_spin(&sc->sc_ht_mtx);
  686 
  687                 /* Program the data port */
  688                 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  689                     0x10 + (cpcht_irqmap[irq].ht_source << 1));
  690 
  691                 /* Unmask the interrupt */
  692                 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  693                 ht_irq &= ~HTAPIC_MASK;
  694                 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  695 
  696                 mtx_unlock_spin(&sc->sc_ht_mtx);
  697         }
  698 
  699         openpic_cpcht_eoi(dev, irq);
  700 }
  701 
  702 static void
  703 openpic_cpcht_eoi(device_t dev, u_int irq)
  704 {
  705         struct openpic_cpcht_softc *sc;
  706         uint32_t off, mask;
  707 
  708         if (irq == 255)
  709                 return;
  710 
  711         sc = device_get_softc(dev);
  712 
  713         if (cpcht_irqmap != NULL && irq < 128 &&
  714             cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
  715                 /* If this is an HT IRQ, acknowledge it at the remote APIC */
  716 
  717                 if (cpcht_irqmap[irq].apple_eoi) {
  718                         off = (cpcht_irqmap[irq].ht_source >> 3) & ~3;
  719                         mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f);
  720                         out32rb(cpcht_irqmap[irq].apple_eoi + off, mask);
  721                 } else {
  722                         mtx_lock_spin(&sc->sc_ht_mtx);
  723 
  724                         out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  725                             0x11 + (cpcht_irqmap[irq].ht_source << 1));
  726                         out32rb(cpcht_irqmap[irq].ht_base + 4,
  727                             cpcht_irqmap[irq].eoi_data);
  728 
  729                         mtx_unlock_spin(&sc->sc_ht_mtx);
  730                 }
  731         }
  732 
  733         openpic_eoi(dev, irq);
  734 }

Cache object: e56c8177e782b5d2cc4448985ef7fae8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.