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/psci/psci.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) 2014 Robin Randhawa
    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 AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  */
   27 
   28 /*
   29  * This implements support for ARM's Power State Co-ordination Interface
   30  * [PSCI]. The implementation adheres to version 0.2 of the PSCI specification
   31  * but also supports v0.1. PSCI standardizes operations such as system reset, CPU
   32  * on/off/suspend. PSCI requires a compliant firmware implementation.
   33  *
   34  * The PSCI specification used for this implementation is available at:
   35  *
   36  * <http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html>.
   37  *
   38  * TODO:
   39  * - Add support for remaining PSCI calls [this implementation only
   40  *   supports get_version, system_reset and cpu_on].
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __FBSDID("$FreeBSD$");
   45 
   46 #include "opt_acpi.h"
   47 #include "opt_platform.h"
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/bus.h>
   52 #include <sys/eventhandler.h>
   53 #include <sys/kernel.h>
   54 #include <sys/module.h>
   55 #include <sys/reboot.h>
   56 
   57 #include <machine/bus.h>
   58 #include <machine/machdep.h>
   59 
   60 #ifdef DEV_ACPI
   61 #include <contrib/dev/acpica/include/acpi.h>
   62 #include <dev/acpica/acpivar.h>
   63 #endif
   64 
   65 #ifdef FDT
   66 #include <dev/fdt/fdt_common.h>
   67 #include <dev/ofw/openfirm.h>
   68 #include <dev/ofw/ofw_bus.h>
   69 #include <dev/ofw/ofw_bus_subr.h>
   70 #endif
   71 
   72 #include <dev/psci/psci.h>
   73 
   74 struct psci_softc {
   75         device_t        dev;
   76 
   77         uint32_t        psci_version;
   78         uint32_t        psci_fnids[PSCI_FN_MAX];
   79 };
   80 
   81 #ifdef FDT
   82 static int psci_v0_1_init(device_t dev, int default_version);
   83 #endif
   84 static int psci_v0_2_init(device_t dev, int default_version);
   85 
   86 struct psci_softc *psci_softc = NULL;
   87 bool psci_present;
   88 
   89 #ifdef __arm__
   90 #define USE_ACPI        0
   91 #define USE_FDT         1
   92 #elif defined(__aarch64__)
   93 #define USE_ACPI        (arm64_bus_method == ARM64_BUS_ACPI)
   94 #define USE_FDT         (arm64_bus_method == ARM64_BUS_FDT)
   95 #else
   96 #error Unknown architecture
   97 #endif
   98 
   99 #ifdef FDT
  100 struct psci_init_def {
  101         int             default_version;
  102         psci_initfn_t   psci_init;
  103 };
  104 
  105 static struct psci_init_def psci_v1_0_init_def = {
  106         .default_version = (1 << 16) | 0,
  107         .psci_init = psci_v0_2_init
  108 };
  109 
  110 static struct psci_init_def psci_v0_2_init_def = {
  111         .default_version = (0 << 16) | 2,
  112         .psci_init = psci_v0_2_init
  113 };
  114 
  115 static struct psci_init_def psci_v0_1_init_def = {
  116         .default_version = (0 << 16) | 1,
  117         .psci_init = psci_v0_1_init
  118 };
  119 
  120 static struct ofw_compat_data compat_data[] = {
  121         {"arm,psci-1.0",        (uintptr_t)&psci_v1_0_init_def},
  122         {"arm,psci-0.2",        (uintptr_t)&psci_v0_2_init_def},
  123         {"arm,psci",            (uintptr_t)&psci_v0_1_init_def},
  124         {NULL,                  0}
  125 };
  126 #endif
  127 
  128 static int psci_attach(device_t, psci_initfn_t, int);
  129 static void psci_shutdown(void *, int);
  130 
  131 static int psci_find_callfn(psci_callfn_t *);
  132 static int psci_def_callfn(register_t, register_t, register_t, register_t,
  133         register_t, register_t, register_t, register_t,
  134         struct arm_smccc_res *res);
  135 
  136 psci_callfn_t psci_callfn = psci_def_callfn;
  137 
  138 static void
  139 psci_init(void *dummy)
  140 {
  141         psci_callfn_t new_callfn;
  142 
  143         if (psci_find_callfn(&new_callfn) != PSCI_RETVAL_SUCCESS) {
  144                 printf("No PSCI/SMCCC call function found\n");
  145                 return;
  146         }
  147 
  148         psci_callfn = new_callfn;
  149         psci_present = true;
  150 }
  151 /* This needs to be before cpu_mp at SI_SUB_CPU, SI_ORDER_THIRD */
  152 SYSINIT(psci_start, SI_SUB_CPU, SI_ORDER_FIRST, psci_init, NULL);
  153 
  154 static int
  155 psci_def_callfn(register_t a __unused, register_t b __unused,
  156     register_t c __unused, register_t d __unused,
  157     register_t e __unused, register_t f __unused,
  158     register_t g __unused, register_t h __unused,
  159     struct arm_smccc_res *res __unused)
  160 {
  161 
  162         panic("No PSCI/SMCCC call function set");
  163 }
  164 
  165 #ifdef FDT
  166 static int psci_fdt_probe(device_t dev);
  167 static int psci_fdt_attach(device_t dev);
  168 
  169 static device_method_t psci_fdt_methods[] = {
  170         DEVMETHOD(device_probe,     psci_fdt_probe),
  171         DEVMETHOD(device_attach,    psci_fdt_attach),
  172 
  173         DEVMETHOD_END
  174 };
  175 
  176 static driver_t psci_fdt_driver = {
  177         "psci",
  178         psci_fdt_methods,
  179         sizeof(struct psci_softc),
  180 };
  181 
  182 EARLY_DRIVER_MODULE(psci, simplebus, psci_fdt_driver, 0, 0,
  183     BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
  184 EARLY_DRIVER_MODULE(psci, ofwbus, psci_fdt_driver, 0, 0,
  185     BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
  186 
  187 static psci_callfn_t
  188 psci_fdt_get_callfn(phandle_t node)
  189 {
  190         char method[16];
  191 
  192         if ((OF_getprop(node, "method", method, sizeof(method))) > 0) {
  193                 if (strcmp(method, "hvc") == 0)
  194                         return (arm_smccc_hvc);
  195                 else if (strcmp(method, "smc") == 0)
  196                         return (arm_smccc_smc);
  197                 else
  198                         printf("psci: PSCI conduit \"%s\" invalid\n", method);
  199         } else
  200                 printf("psci: PSCI conduit not supplied in the device tree\n");
  201 
  202         return (NULL);
  203 }
  204 
  205 static int
  206 psci_fdt_probe(device_t dev)
  207 {
  208         const struct ofw_compat_data *ocd;
  209 
  210         if (!ofw_bus_status_okay(dev))
  211                 return (ENXIO);
  212 
  213         ocd = ofw_bus_search_compatible(dev, compat_data);
  214         if (ocd->ocd_str == NULL)
  215                 return (ENXIO);
  216 
  217         device_set_desc(dev, "ARM Power State Co-ordination Interface Driver");
  218 
  219         return (BUS_PROBE_SPECIFIC);
  220 }
  221 
  222 static int
  223 psci_fdt_attach(device_t dev)
  224 {
  225         const struct ofw_compat_data *ocd;
  226         struct psci_init_def *psci_init_def;
  227 
  228         ocd = ofw_bus_search_compatible(dev, compat_data);
  229         psci_init_def = (struct psci_init_def *)ocd->ocd_data;
  230 
  231         return (psci_attach(dev, psci_init_def->psci_init,
  232             psci_init_def->default_version));
  233 }
  234 #endif
  235 
  236 #ifdef DEV_ACPI
  237 static void psci_acpi_identify(driver_t *, device_t);
  238 static int psci_acpi_probe(device_t);
  239 static int psci_acpi_attach(device_t);
  240 
  241 static device_method_t psci_acpi_methods[] = {
  242         /* Device interface */
  243         DEVMETHOD(device_identify,      psci_acpi_identify),
  244         DEVMETHOD(device_probe,         psci_acpi_probe),
  245         DEVMETHOD(device_attach,        psci_acpi_attach),
  246 
  247         DEVMETHOD_END
  248 };
  249 
  250 static driver_t psci_acpi_driver = {
  251         "psci",
  252         psci_acpi_methods,
  253         sizeof(struct psci_softc),
  254 };
  255 
  256 EARLY_DRIVER_MODULE(psci, acpi, psci_acpi_driver, 0, 0,
  257     BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
  258 
  259 static int
  260 psci_acpi_bootflags(void)
  261 {
  262         ACPI_TABLE_FADT *fadt;
  263         vm_paddr_t physaddr;
  264         int flags;
  265 
  266         physaddr = acpi_find_table(ACPI_SIG_FADT);
  267         if (physaddr == 0)
  268                 return (0);
  269 
  270         fadt = acpi_map_table(physaddr, ACPI_SIG_FADT);
  271         if (fadt == NULL) {
  272                 printf("psci: Unable to map the FADT\n");
  273                 return (0);
  274         }
  275 
  276         flags = fadt->ArmBootFlags;
  277 
  278         acpi_unmap_table(fadt);
  279         return (flags);
  280 }
  281 
  282 static psci_callfn_t
  283 psci_acpi_get_callfn(int flags)
  284 {
  285 
  286         if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) {
  287                 if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0)
  288                         return (arm_smccc_hvc);
  289                 else
  290                         return (arm_smccc_smc);
  291         } else {
  292                 printf("psci: PSCI conduit not supplied in the device tree\n");
  293         }
  294 
  295         return (NULL);
  296 }
  297 
  298 static void
  299 psci_acpi_identify(driver_t *driver, device_t parent)
  300 {
  301         device_t dev;
  302         int flags;
  303 
  304         flags = psci_acpi_bootflags();
  305         if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) {
  306                 dev = BUS_ADD_CHILD(parent,
  307                     BUS_PASS_CPU + BUS_PASS_ORDER_FIRST, "psci", -1);
  308 
  309                 if (dev != NULL)
  310                         acpi_set_private(dev, (void *)(uintptr_t)flags);
  311         }
  312 }
  313 
  314 static int
  315 psci_acpi_probe(device_t dev)
  316 {
  317         uintptr_t flags;
  318 
  319         flags = (uintptr_t)acpi_get_private(dev);
  320         if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0)
  321                 return (ENXIO);
  322 
  323         device_set_desc(dev, "ARM Power State Co-ordination Interface Driver");
  324         return (BUS_PROBE_SPECIFIC);
  325 }
  326 
  327 static int
  328 psci_acpi_attach(device_t dev)
  329 {
  330 
  331         return (psci_attach(dev, psci_v0_2_init, PSCI_RETVAL_NOT_SUPPORTED));
  332 }
  333 #endif
  334 
  335 static int
  336 psci_attach(device_t dev, psci_initfn_t psci_init, int default_version)
  337 {
  338         struct psci_softc *sc = device_get_softc(dev);
  339 
  340         if (psci_softc != NULL)
  341                 return (ENXIO);
  342 
  343         KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL"));
  344         if (psci_init(dev, default_version))
  345                 return (ENXIO);
  346 
  347         psci_softc = sc;
  348 
  349         return (0);
  350 }
  351 
  352 static int
  353 _psci_get_version(struct psci_softc *sc)
  354 {
  355         uint32_t fnid;
  356 
  357         /* PSCI version wasn't supported in v0.1. */
  358         fnid = sc->psci_fnids[PSCI_FN_VERSION];
  359         if (fnid)
  360                 return (psci_call(fnid, 0, 0, 0));
  361 
  362         return (PSCI_RETVAL_NOT_SUPPORTED);
  363 }
  364 
  365 int
  366 psci_get_version(void)
  367 {
  368 
  369         if (psci_softc == NULL)
  370                 return (PSCI_RETVAL_NOT_SUPPORTED);
  371         return (_psci_get_version(psci_softc));
  372 }
  373 
  374 #ifdef FDT
  375 static int
  376 psci_fdt_callfn(psci_callfn_t *callfn)
  377 {
  378         phandle_t node;
  379 
  380         node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-0.2");
  381         if (node == 0) {
  382                 node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-1.0");
  383                 if (node == 0)
  384                         return (PSCI_MISSING);
  385         }
  386 
  387         *callfn = psci_fdt_get_callfn(node);
  388         return (0);
  389 }
  390 #endif
  391 
  392 #ifdef DEV_ACPI
  393 static int
  394 psci_acpi_callfn(psci_callfn_t *callfn)
  395 {
  396         int flags;
  397 
  398         flags = psci_acpi_bootflags();
  399         if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0)
  400                 return (PSCI_MISSING);
  401 
  402         *callfn = psci_acpi_get_callfn(flags);
  403         return (0);
  404 }
  405 #endif
  406 
  407 static int
  408 psci_find_callfn(psci_callfn_t *callfn)
  409 {
  410         int error;
  411 
  412         *callfn = NULL;
  413 #ifdef FDT
  414         if (USE_FDT) {
  415                 error = psci_fdt_callfn(callfn);
  416                 if (error != 0)
  417                         return (error);
  418         }
  419 #endif
  420 #ifdef DEV_ACPI
  421         if (*callfn == NULL && USE_ACPI) {
  422                 error = psci_acpi_callfn(callfn);
  423                 if (error != 0)
  424                         return (error);
  425         }
  426 #endif
  427 
  428         if (*callfn == NULL)
  429                 return (PSCI_MISSING);
  430 
  431         return (PSCI_RETVAL_SUCCESS);
  432 }
  433 
  434 int32_t
  435 psci_features(uint32_t psci_func_id)
  436 {
  437 
  438         if (psci_softc == NULL)
  439                 return (PSCI_RETVAL_NOT_SUPPORTED);
  440 
  441         /* The feature flags were added to PSCI 1.0 */
  442         if (PSCI_VER_MAJOR(psci_softc->psci_version) < 1)
  443                 return (PSCI_RETVAL_NOT_SUPPORTED);
  444 
  445         return (psci_call(PSCI_FNID_FEATURES, psci_func_id, 0, 0));
  446 }
  447 
  448 int
  449 psci_cpu_on(unsigned long cpu, unsigned long entry, unsigned long context_id)
  450 {
  451         uint32_t fnid;
  452 
  453         fnid = PSCI_FNID_CPU_ON;
  454         if (psci_softc != NULL)
  455                 fnid = psci_softc->psci_fnids[PSCI_FN_CPU_ON];
  456 
  457         /* PSCI v0.1 and v0.2 both support cpu_on. */
  458         return (psci_call(fnid, cpu, entry, context_id));
  459 }
  460 
  461 static void
  462 psci_shutdown(void *xsc, int howto)
  463 {
  464         uint32_t fn = 0;
  465 
  466         if (psci_softc == NULL)
  467                 return;
  468 
  469         /* PSCI system_off and system_reset werent't supported in v0.1. */
  470         if ((howto & RB_POWEROFF) != 0)
  471                 fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_OFF];
  472         else if ((howto & RB_HALT) == 0)
  473                 fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_RESET];
  474 
  475         if (fn)
  476                 psci_call(fn, 0, 0, 0);
  477 
  478         /* System reset and off do not return. */
  479 }
  480 
  481 void
  482 psci_reset(void)
  483 {
  484 
  485         psci_shutdown(NULL, 0);
  486 }
  487 
  488 #ifdef FDT
  489 /* Only support PSCI 0.1 on FDT */
  490 static int
  491 psci_v0_1_init(device_t dev, int default_version __unused)
  492 {
  493         struct psci_softc *sc = device_get_softc(dev);
  494         int psci_fn;
  495         uint32_t psci_fnid;
  496         phandle_t node;
  497         int len;
  498 
  499         /* Zero out the function ID table - Is this needed ? */
  500         for (psci_fn = PSCI_FN_VERSION, psci_fnid = PSCI_FNID_VERSION;
  501             psci_fn < PSCI_FN_MAX; psci_fn++, psci_fnid++)
  502                 sc->psci_fnids[psci_fn] = 0;
  503 
  504         /* PSCI v0.1 doesn't specify function IDs. Get them from DT */
  505         node = ofw_bus_get_node(dev);
  506 
  507         if ((len = OF_getproplen(node, "cpu_suspend")) > 0) {
  508                 OF_getencprop(node, "cpu_suspend", &psci_fnid, len);
  509                 sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = psci_fnid;
  510         }
  511 
  512         if ((len = OF_getproplen(node, "cpu_on")) > 0) {
  513                 OF_getencprop(node, "cpu_on", &psci_fnid, len);
  514                 sc->psci_fnids[PSCI_FN_CPU_ON] = psci_fnid;
  515         }
  516 
  517         if ((len = OF_getproplen(node, "cpu_off")) > 0) {
  518                 OF_getencprop(node, "cpu_off", &psci_fnid, len);
  519                 sc->psci_fnids[PSCI_FN_CPU_OFF] = psci_fnid;
  520         }
  521 
  522         if ((len = OF_getproplen(node, "migrate")) > 0) {
  523                 OF_getencprop(node, "migrate", &psci_fnid, len);
  524                 sc->psci_fnids[PSCI_FN_MIGRATE] = psci_fnid;
  525         }
  526 
  527         sc->psci_version = (0 << 16) | 1;
  528         if (bootverbose)
  529                 device_printf(dev, "PSCI version 0.1 available\n");
  530 
  531         return(0);
  532 }
  533 #endif
  534 
  535 static int
  536 psci_v0_2_init(device_t dev, int default_version)
  537 {
  538         struct psci_softc *sc = device_get_softc(dev);
  539         int version;
  540 
  541         /* PSCI v0.2 specifies explicit function IDs. */
  542         sc->psci_fnids[PSCI_FN_VERSION]             = PSCI_FNID_VERSION;
  543         sc->psci_fnids[PSCI_FN_CPU_SUSPEND]         = PSCI_FNID_CPU_SUSPEND;
  544         sc->psci_fnids[PSCI_FN_CPU_OFF]             = PSCI_FNID_CPU_OFF;
  545         sc->psci_fnids[PSCI_FN_CPU_ON]              = PSCI_FNID_CPU_ON;
  546         sc->psci_fnids[PSCI_FN_AFFINITY_INFO]       = PSCI_FNID_AFFINITY_INFO;
  547         sc->psci_fnids[PSCI_FN_MIGRATE]             = PSCI_FNID_MIGRATE;
  548         sc->psci_fnids[PSCI_FN_MIGRATE_INFO_TYPE]   = PSCI_FNID_MIGRATE_INFO_TYPE;
  549         sc->psci_fnids[PSCI_FN_MIGRATE_INFO_UP_CPU] = PSCI_FNID_MIGRATE_INFO_UP_CPU;
  550         sc->psci_fnids[PSCI_FN_SYSTEM_OFF]          = PSCI_FNID_SYSTEM_OFF;
  551         sc->psci_fnids[PSCI_FN_SYSTEM_RESET]        = PSCI_FNID_SYSTEM_RESET;
  552 
  553         version = _psci_get_version(sc);
  554 
  555         /*
  556          * U-Boot PSCI implementation doesn't have psci_get_version()
  557          * method implemented for many boards. In this case, use the version
  558          * readed from FDT as fallback. No fallback method for ACPI.
  559          */
  560         if (version == PSCI_RETVAL_NOT_SUPPORTED) {
  561                 if (default_version == PSCI_RETVAL_NOT_SUPPORTED)
  562                         return (1);
  563 
  564                 version = default_version;
  565                 printf("PSCI get_version() function is not implemented, "
  566                     " assuming v%d.%d\n", PSCI_VER_MAJOR(version),
  567                     PSCI_VER_MINOR(version));
  568         }
  569 
  570         sc->psci_version = version;
  571         if ((PSCI_VER_MAJOR(version) == 0 && PSCI_VER_MINOR(version) == 2) ||
  572             PSCI_VER_MAJOR(version) == 1) {
  573                 if (bootverbose)
  574                         device_printf(dev, "PSCI version 0.2 compatible\n");
  575 
  576                 /*
  577                  * We only register this for v0.2 since v0.1 doesn't support
  578                  * system_reset.
  579                  */
  580                 EVENTHANDLER_REGISTER(shutdown_final, psci_shutdown, sc,
  581                     SHUTDOWN_PRI_LAST);
  582 
  583                 return (0);
  584         }
  585 
  586         device_printf(dev, "PSCI version number mismatched with DT\n");
  587         return (1);
  588 }

Cache object: 1f269b6ac7a62fbf506a02b202dc93a0


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