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/dev/pci/if_ex_pci.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 /*      $NetBSD: if_ex_pci.c,v 1.35.4.1 2004/08/22 14:22:20 tron Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Frank van der Linden; Jason R. Thorpe of the Numerical Aerospace
    9  * Simulation Facility, NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __KERNEL_RCSID(0, "$NetBSD: if_ex_pci.c,v 1.35.4.1 2004/08/22 14:22:20 tron Exp $");
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/mbuf.h> 
   46 #include <sys/socket.h> 
   47 #include <sys/ioctl.h>
   48 #include <sys/errno.h>
   49 #include <sys/syslog.h>
   50 #include <sys/select.h>
   51 #include <sys/device.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_dl.h>
   55 #include <net/if_ether.h>
   56 #include <net/if_media.h>
   57 
   58 #include <machine/cpu.h>
   59 #include <machine/bus.h>
   60 #include <machine/intr.h>
   61 
   62 #include <dev/mii/miivar.h>
   63 #include <dev/mii/mii.h>
   64 
   65 #include <dev/ic/elink3var.h>
   66 #include <dev/ic/elink3reg.h>
   67 #include <dev/ic/elinkxlreg.h>
   68 #include <dev/ic/elinkxlvar.h>
   69 
   70 #include <dev/pci/pcivar.h>
   71 #include <dev/pci/pcireg.h>
   72 #include <dev/pci/pcidevs.h>
   73 
   74 struct ex_pci_softc {
   75         struct ex_softc sc_ex;
   76 
   77         /* PCI function status space. 556,556B requests it. */
   78         bus_space_tag_t sc_funct;
   79         bus_space_handle_t sc_funch;
   80 
   81         pci_chipset_tag_t psc_pc;       /* pci chipset tag */
   82         pcireg_t psc_regs[0x20>>2];     /* saved PCI config regs (sparse) */
   83         pcitag_t psc_tag;               /* pci device tag */
   84 
   85         int psc_pwrmgmt_csr_reg;        /* ACPI power management register */
   86         pcireg_t psc_pwrmgmt_csr;       /* ...and the contents at D0 */
   87 };
   88 
   89 /*
   90  * PCI constants.
   91  * XXX These should be in a common file!
   92  */
   93 #define PCI_CONN                0x48    /* Connector type */
   94 #define PCI_CBIO                0x10    /* Configuration Base IO Address */
   95 #define PCI_POWERCTL            0xe0
   96 #define PCI_FUNCMEM             0x18
   97 
   98 #define PCI_INTR                4
   99 #define PCI_INTRACK             0x00008000
  100 
  101 int ex_pci_match __P((struct device *, struct cfdata *, void *));
  102 void ex_pci_attach __P((struct device *, struct device *, void *));
  103 void ex_pci_intr_ack __P((struct ex_softc *));
  104 
  105 int ex_pci_enable __P((struct ex_softc *));
  106 void ex_pci_disable __P((struct ex_softc *));
  107 
  108 void ex_pci_confreg_restore __P((struct ex_pci_softc *));
  109 void ex_d3tod0 __P(( struct ex_softc *, struct pci_attach_args *));
  110 
  111 CFATTACH_DECL(ex_pci, sizeof(struct ex_pci_softc),
  112     ex_pci_match, ex_pci_attach, NULL, NULL);
  113 
  114 const struct ex_pci_product {
  115         u_int32_t       epp_prodid;     /* PCI product ID */
  116         int             epp_flags;      /* initial softc flags */
  117         const char      *epp_name;      /* device name */
  118 } ex_pci_products[] = {
  119         { PCI_PRODUCT_3COM_3C900TPO,    0,
  120           "3c900-TPO Ethernet" },
  121         { PCI_PRODUCT_3COM_3C900COMBO,  0,
  122           "3c900-COMBO Ethernet" },
  123 
  124         { PCI_PRODUCT_3COM_3C905TX,     EX_CONF_MII,
  125           "3c905-TX 10/100 Ethernet" },
  126         { PCI_PRODUCT_3COM_3C905T4,     EX_CONF_MII,
  127           "3c905-T4 10/100 Ethernet" },
  128 
  129         { PCI_PRODUCT_3COM_3C900BTPO,   EX_CONF_90XB,
  130           "3c900B-TPO Ethernet" },
  131         { PCI_PRODUCT_3COM_3C900BCOMBO, EX_CONF_90XB,
  132           "3c900B-COMBO Ethernet" },
  133         { PCI_PRODUCT_3COM_3C900BTPC,   EX_CONF_90XB,
  134           "3c900B-TPC Ethernet" },
  135 
  136         { PCI_PRODUCT_3COM_3C905BTX,    EX_CONF_90XB|EX_CONF_MII|EX_CONF_INTPHY,
  137           "3c905B-TX 10/100 Ethernet" },
  138         { PCI_PRODUCT_3COM_3C905BT4,    EX_CONF_90XB|EX_CONF_MII,
  139           "3c905B-T4 10/100 Ethernet" },
  140         { PCI_PRODUCT_3COM_3C905BCOMBO, EX_CONF_90XB/*|EX_CONF_MII|EX_CONF_INTPHY*/,
  141           "3c905B-COMBO 10/100 Ethernet" },
  142         { PCI_PRODUCT_3COM_3C905BFX,    EX_CONF_90XB,
  143           "3c905B-FX 10/100 Ethernet" },
  144 
  145         /* XXX Internal PHY? */
  146         { PCI_PRODUCT_3COM_3C980SRV,    EX_CONF_90XB,
  147           "3c980 Server Adapter 10/100 Ethernet" },
  148         { PCI_PRODUCT_3COM_3C980CTXM,   EX_CONF_90XB|EX_CONF_MII,
  149           "3c980C-TXM 10/100 Ethernet" },
  150 
  151         { PCI_PRODUCT_3COM_3C905CTX,    EX_CONF_90XB|EX_CONF_MII,
  152           "3c905C-TX 10/100 Ethernet with mngmt" },
  153 
  154         { PCI_PRODUCT_3COM_3C450TX,             EX_CONF_90XB,
  155           "3c450-TX 10/100 Ethernet" },
  156 
  157         { PCI_PRODUCT_3COM_3CSOHO100TX, EX_CONF_90XB,
  158           "3cSOHO100-TX 10/100 Ethernet" },
  159 
  160         { PCI_PRODUCT_3COM_3C555,
  161            EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
  162            EX_CONF_EEPROM_8BIT,
  163           "3c555 MiniPCI 10/100 Ethernet" },
  164 
  165         { PCI_PRODUCT_3COM_3C556,
  166            EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
  167            EX_CONF_PCI_FUNCREG | EX_CONF_RESETHACK | EX_CONF_INV_LED_POLARITY |
  168            EX_CONF_PHY_POWER | EX_CONF_EEPROM_8BIT,
  169           "3c556 MiniPCI 10/100 Ethernet" },
  170 
  171         { PCI_PRODUCT_3COM_3C556B,
  172            EX_CONF_90XB | EX_CONF_MII | EX_CONF_EEPROM_OFF |
  173            EX_CONF_PCI_FUNCREG | EX_CONF_RESETHACK | EX_CONF_INV_LED_POLARITY |
  174            EX_CONF_PHY_POWER | EX_CONF_NO_XCVR_PWR,
  175           "3c556B MiniPCI 10/100 Ethernet" },
  176 
  177         { PCI_PRODUCT_3COM_3C905CXTX,   EX_CONF_90XB|EX_CONF_MII,
  178           "3c905CX-TX 10/100 Ethernet with mngmt" },
  179 
  180         { PCI_PRODUCT_3COM_3C920BEMBW,  EX_CONF_90XB|EX_CONF_MII,
  181           "3c920B-EMB-WNM Integrated Fast Ethernet" },
  182 
  183         { 0,                            0,
  184           NULL },
  185 };
  186 
  187 const struct ex_pci_product *ex_pci_lookup
  188     __P((const struct pci_attach_args *));
  189 
  190 const struct ex_pci_product *
  191 ex_pci_lookup(pa)
  192         const struct pci_attach_args *pa;
  193 {
  194         const struct ex_pci_product *epp;
  195 
  196         if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3COM)
  197                 return (NULL);
  198 
  199         for (epp = ex_pci_products; epp->epp_name != NULL; epp++)
  200                 if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid)
  201                         return (epp);
  202         return (NULL);
  203 }
  204 
  205 int
  206 ex_pci_match(parent, match, aux)
  207         struct device *parent;
  208         struct cfdata *match;
  209         void *aux;
  210 {
  211         struct pci_attach_args *pa = (struct pci_attach_args *) aux;
  212 
  213         if (ex_pci_lookup(pa) != NULL)
  214                 return (2);     /* beat ep_pci */
  215 
  216         return (0);
  217 }
  218 
  219 void
  220 ex_pci_attach(parent, self, aux)
  221         struct device *parent, *self;
  222         void *aux;
  223 {
  224         struct ex_softc *sc = (void *)self;
  225         struct ex_pci_softc *psc = (void *)self;
  226         struct pci_attach_args *pa = aux;
  227         pci_chipset_tag_t pc = pa->pa_pc;
  228         pci_intr_handle_t ih;
  229         const struct ex_pci_product *epp;
  230         const char *intrstr = NULL;
  231         int rev, pmreg;
  232         pcireg_t reg;
  233 
  234         aprint_naive(": Ethernet controller\n");
  235 
  236         if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
  237             &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
  238                 aprint_error(": can't map i/o space\n");
  239                 return;
  240         }
  241 
  242         epp = ex_pci_lookup(pa);
  243         if (epp == NULL) {
  244                 printf("\n");
  245                 panic("ex_pci_attach: impossible");
  246         }
  247 
  248         rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG));
  249         aprint_normal(": 3Com %s (rev. 0x%x)\n", epp->epp_name, rev);
  250 
  251         sc->sc_dmat = pa->pa_dmat;
  252 
  253         sc->ex_bustype = EX_BUS_PCI;
  254         sc->ex_conf = epp->epp_flags;
  255 
  256         /* Enable the card. */
  257         pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
  258             pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
  259             PCI_COMMAND_MASTER_ENABLE);
  260 
  261         psc->psc_pc = pc;
  262         psc->psc_tag = pa->pa_tag;
  263         psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] = 
  264             pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  265         psc->psc_regs[PCI_BHLC_REG>>2] =
  266             pci_conf_read(pc, pa->pa_tag, PCI_BHLC_REG); 
  267         psc->psc_regs[PCI_CBIO>>2] =
  268             pci_conf_read(pc, pa->pa_tag, PCI_CBIO);
  269 
  270         if (sc->ex_conf & EX_CONF_PCI_FUNCREG) {
  271                 /* Map PCI function status window. */
  272                 if (pci_mapreg_map(pa, PCI_FUNCMEM, PCI_MAPREG_TYPE_MEM, 0,
  273                     &psc->sc_funct, &psc->sc_funch, NULL, NULL)) {
  274                         aprint_error(
  275                             "%s: unable to map function status window\n",
  276                             sc->sc_dev.dv_xname);
  277                         return;
  278                 }
  279                 sc->intr_ack = ex_pci_intr_ack;
  280 
  281                 psc->psc_regs[PCI_FUNCMEM>>2] =
  282                     pci_conf_read(pc, pa->pa_tag, PCI_FUNCMEM);
  283         }
  284 
  285         psc->psc_regs[PCI_INTERRUPT_REG>>2] =
  286             pci_conf_read(pc, pa->pa_tag, PCI_INTERRUPT_REG);
  287 
  288         /* Get it out of power save mode if needed (BIOS bugs) */
  289         if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
  290                 sc->enable = ex_pci_enable;
  291                 sc->disable = ex_pci_disable;
  292 
  293                 psc->psc_pwrmgmt_csr_reg = pmreg + PCI_PMCSR;
  294                 reg = pci_conf_read(pc, pa->pa_tag, psc->psc_pwrmgmt_csr_reg);
  295 
  296                 psc->psc_pwrmgmt_csr = (reg & ~PCI_PMCSR_STATE_MASK) |
  297                     PCI_PMCSR_STATE_D0;
  298 
  299                 switch (reg & PCI_PMCSR_STATE_MASK) {
  300                 case PCI_PMCSR_STATE_D3:
  301                         aprint_normal("%s: found in power state D3, "
  302                             "attempting to recover.\n", sc->sc_dev.dv_xname);
  303                         ex_d3tod0(sc, pa);
  304                         aprint_normal("%s: changed power state to D0.\n",
  305                             sc->sc_dev.dv_xname);
  306                         break;
  307                 case PCI_PMCSR_STATE_D1:
  308                 case PCI_PMCSR_STATE_D2:
  309                         aprint_normal("%s: waking up from power state D%d\n",
  310                             sc->sc_dev.dv_xname, reg);
  311                         pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
  312                             (reg & ~PCI_PMCSR_STATE_MASK) | PCI_PMCSR_STATE_D0);
  313                         break;
  314                 }
  315         }
  316 
  317         sc->enabled = 1;
  318 
  319         /* Map and establish the interrupt. */
  320         if (pci_intr_map(pa, &ih)) {
  321                 aprint_error("%s: couldn't map interrupt\n",
  322                     sc->sc_dev.dv_xname);
  323                 return;
  324         }
  325 
  326         intrstr = pci_intr_string(pc, ih);
  327         sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, ex_intr, sc);
  328         if (sc->sc_ih == NULL) {
  329                 aprint_error("%s: couldn't establish interrupt",
  330                     sc->sc_dev.dv_xname);
  331                 if (intrstr != NULL)
  332                         aprint_normal(" at %s", intrstr);
  333                 aprint_normal("\n");
  334                 return;
  335         }
  336         aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
  337 
  338         ex_config(sc);
  339 
  340         if (sc->ex_conf & EX_CONF_PCI_FUNCREG)
  341                 bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR, 
  342                     PCI_INTRACK);
  343 
  344         if (sc->disable != NULL)
  345                 ex_disable(sc);
  346 }
  347 
  348 void            
  349 ex_pci_intr_ack(sc)
  350         struct ex_softc *sc;
  351 {
  352         struct ex_pci_softc *psc = (struct ex_pci_softc *)sc;
  353         
  354         bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR,
  355             PCI_INTRACK);
  356 }
  357 
  358 void
  359 ex_d3tod0(sc, pa)
  360         struct ex_softc         *sc;
  361         struct pci_attach_args  *pa;
  362 {
  363 
  364 #define PCI_CACHE_LAT_BIST      0x0c
  365 #define PCI_BAR0                0x10
  366 #define PCI_BAR1                0x14
  367 #define PCI_BAR2                0x18
  368 #define PCI_BAR3                0x1C
  369 #define PCI_BAR4                0x20
  370 #define PCI_BAR5                0x24
  371 #define PCI_EXP_ROM_BAR         0x30
  372 #define PCI_INT_GNT_LAT         0x3c
  373 
  374         pci_chipset_tag_t pc = pa->pa_pc;
  375 
  376         u_int32_t base0;
  377         u_int32_t base1;
  378         u_int32_t romaddr;
  379         u_int32_t pci_command;
  380         u_int32_t pci_int_lat;
  381         u_int32_t pci_cache_lat;
  382 
  383         pci_command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  384         base0 = pci_conf_read(pc, pa->pa_tag, PCI_BAR0);
  385         base1 = pci_conf_read(pc, pa->pa_tag, PCI_BAR1);
  386         romaddr = pci_conf_read(pc, pa->pa_tag, PCI_EXP_ROM_BAR);
  387         pci_cache_lat= pci_conf_read(pc, pa->pa_tag, PCI_CACHE_LAT_BIST);
  388         pci_int_lat = pci_conf_read(pc, pa->pa_tag, PCI_INT_GNT_LAT);
  389 
  390         pci_conf_write(pc, pa->pa_tag, PCI_POWERCTL, 0);
  391         pci_conf_write(pc, pa->pa_tag, PCI_BAR0, base0);
  392         pci_conf_write(pc, pa->pa_tag, PCI_BAR1, base1);
  393         pci_conf_write(pc, pa->pa_tag, PCI_EXP_ROM_BAR, romaddr);
  394         pci_conf_write(pc, pa->pa_tag, PCI_INT_GNT_LAT, pci_int_lat);
  395         pci_conf_write(pc, pa->pa_tag, PCI_CACHE_LAT_BIST, pci_cache_lat);
  396         pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 
  397             (PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE));
  398 }
  399 
  400 void
  401 ex_pci_confreg_restore(psc)
  402         struct ex_pci_softc *psc;
  403 {
  404         struct ex_softc *sc = (void *) psc;
  405         pcireg_t reg;
  406 
  407         reg = pci_conf_read(psc->psc_pc, psc->psc_tag, PCI_COMMAND_STATUS_REG);
  408 
  409         pci_conf_write(psc->psc_pc, psc->psc_tag,
  410             PCI_COMMAND_STATUS_REG,
  411             (reg & 0xffff0000) |
  412             (psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] & 0xffff));
  413         pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_BHLC_REG,
  414             psc->psc_regs[PCI_BHLC_REG>>2]);
  415         pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_CBIO,
  416             psc->psc_regs[PCI_CBIO>>2]);
  417         if (sc->ex_conf & EX_CONF_PCI_FUNCREG)
  418                 pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_FUNCMEM,
  419                     psc->psc_regs[PCI_FUNCMEM>>2]);
  420         pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_INTERRUPT_REG,
  421             psc->psc_regs[PCI_INTERRUPT_REG>>2]);
  422 }
  423 
  424 int
  425 ex_pci_enable(sc)
  426         struct ex_softc *sc;
  427 {
  428         struct ex_pci_softc *psc = (void *) sc;
  429 
  430 #if 0
  431         printf("%s: going to power state D0\n", sc->sc_dev.dv_xname);
  432 #endif
  433 
  434         /* Bring the device into D0 power state. */
  435         pci_conf_write(psc->psc_pc, psc->psc_tag,
  436             psc->psc_pwrmgmt_csr_reg, psc->psc_pwrmgmt_csr);
  437 
  438         /* Now restore the configuration registers. */
  439         ex_pci_confreg_restore(psc);
  440 
  441         return (0);
  442 }
  443 
  444 void
  445 ex_pci_disable(sc)
  446         struct ex_softc *sc;
  447 {
  448         struct ex_pci_softc *psc = (void *) sc;
  449 
  450 #if 0
  451         printf("%s: going to power state D3\n", sc->sc_dev.dv_xname);
  452 #endif
  453 
  454         /* Put the device into D3 state. */
  455         pci_conf_write(psc->psc_pc, psc->psc_tag,
  456             psc->psc_pwrmgmt_csr_reg, (psc->psc_pwrmgmt_csr &
  457             ~PCI_PMCSR_STATE_MASK) | PCI_PMCSR_STATE_D3);
  458 }

Cache object: a51002999ea4d0439f97a2f799de8bfe


[ 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.