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/bhnd/siba/siba.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) 2015-2016 Landon Fuller <landon@landonf.org>
    3  * Copyright (c) 2017 The FreeBSD Foundation
    4  * All rights reserved.
    5  *
    6  * Portions of this software were developed by Landon Fuller
    7  * under sponsorship from the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer,
   14  *    without modification.
   15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   17  *    redistribution must be conditioned upon including a substantially
   18  *    similar Disclaimer requirement for further binary redistribution.
   19  *
   20  * NO WARRANTY
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   31  * THE POSSIBILITY OF SUCH DAMAGES.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/module.h>
   42 #include <sys/refcount.h>
   43 #include <sys/systm.h>
   44 
   45 #include <machine/bus.h>
   46 
   47 #include <dev/bhnd/cores/chipc/chipc.h>
   48 #include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h>
   49 
   50 #include "siba_eromvar.h"
   51 
   52 #include "sibareg.h"
   53 #include "sibavar.h"
   54 
   55 /* RID used when allocating EROM resources */
   56 #define SIBA_EROM_RID   0
   57 
   58 static bhnd_erom_class_t *
   59 siba_get_erom_class(driver_t *driver)
   60 {
   61         return (&siba_erom_parser);
   62 }
   63 
   64 int
   65 siba_probe(device_t dev)
   66 {
   67         device_set_desc(dev, "SIBA BHND bus");
   68         return (BUS_PROBE_DEFAULT);
   69 }
   70 
   71 /**
   72  * Default siba(4) bus driver implementation of DEVICE_ATTACH().
   73  * 
   74  * This implementation initializes internal siba(4) state and performs
   75  * bus enumeration, and must be called by subclassing drivers in
   76  * DEVICE_ATTACH() before any other bus methods.
   77  */
   78 int
   79 siba_attach(device_t dev)
   80 {
   81         struct siba_softc       *sc;
   82         int                      error;
   83 
   84         sc = device_get_softc(dev);
   85         sc->dev = dev;
   86 
   87         SIBA_LOCK_INIT(sc);
   88 
   89         /* Enumerate children */
   90         if ((error = siba_add_children(dev))) {
   91                 device_delete_children(dev);
   92                 SIBA_LOCK_DESTROY(sc);
   93                 return (error);
   94         }
   95 
   96         return (0);
   97 }
   98 
   99 int
  100 siba_detach(device_t dev)
  101 {
  102         struct siba_softc       *sc;
  103         int                      error;
  104 
  105         sc = device_get_softc(dev);
  106 
  107         if ((error = bhnd_generic_detach(dev)))
  108                 return (error);
  109 
  110         SIBA_LOCK_DESTROY(sc);
  111 
  112         return (0);
  113 }
  114 
  115 int
  116 siba_resume(device_t dev)
  117 {
  118         return (bhnd_generic_resume(dev));
  119 }
  120 
  121 int
  122 siba_suspend(device_t dev)
  123 {
  124         return (bhnd_generic_suspend(dev));
  125 }
  126 
  127 static int
  128 siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  129 {
  130         struct siba_softc               *sc;
  131         const struct siba_devinfo       *dinfo;
  132         const struct bhnd_core_info     *cfg;
  133 
  134         sc = device_get_softc(dev);
  135         dinfo = device_get_ivars(child);
  136         cfg = &dinfo->core_id.core_info;
  137 
  138         switch (index) {
  139         case BHND_IVAR_VENDOR:
  140                 *result = cfg->vendor;
  141                 return (0);
  142         case BHND_IVAR_DEVICE:
  143                 *result = cfg->device;
  144                 return (0);
  145         case BHND_IVAR_HWREV:
  146                 *result = cfg->hwrev;
  147                 return (0);
  148         case BHND_IVAR_DEVICE_CLASS:
  149                 *result = bhnd_core_class(cfg);
  150                 return (0);
  151         case BHND_IVAR_VENDOR_NAME:
  152                 *result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
  153                 return (0);
  154         case BHND_IVAR_DEVICE_NAME:
  155                 *result = (uintptr_t) bhnd_core_name(cfg);
  156                 return (0);
  157         case BHND_IVAR_CORE_INDEX:
  158                 *result = cfg->core_idx;
  159                 return (0);
  160         case BHND_IVAR_CORE_UNIT:
  161                 *result = cfg->unit;
  162                 return (0);
  163         case BHND_IVAR_PMU_INFO:
  164                 SIBA_LOCK(sc);
  165                 switch (dinfo->pmu_state) {
  166                 case SIBA_PMU_NONE:
  167                         *result = (uintptr_t)NULL;
  168                         SIBA_UNLOCK(sc);
  169                         return (0);
  170 
  171                 case SIBA_PMU_BHND:
  172                         *result = (uintptr_t)dinfo->pmu.bhnd_info;
  173                         SIBA_UNLOCK(sc);
  174                         return (0);
  175 
  176                 case SIBA_PMU_PWRCTL:
  177                 case SIBA_PMU_FIXED:
  178                         *result = (uintptr_t)NULL;
  179                         SIBA_UNLOCK(sc);
  180                         return (0);
  181                 }
  182 
  183                 panic("invalid PMU state: %d", dinfo->pmu_state);
  184                 return (ENXIO);
  185 
  186         default:
  187                 return (ENOENT);
  188         }
  189 }
  190 
  191 static int
  192 siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
  193 {
  194         struct siba_softc       *sc;
  195         struct siba_devinfo     *dinfo;
  196 
  197         sc = device_get_softc(dev);
  198         dinfo = device_get_ivars(child);
  199 
  200         switch (index) {
  201         case BHND_IVAR_VENDOR:
  202         case BHND_IVAR_DEVICE:
  203         case BHND_IVAR_HWREV:
  204         case BHND_IVAR_DEVICE_CLASS:
  205         case BHND_IVAR_VENDOR_NAME:
  206         case BHND_IVAR_DEVICE_NAME:
  207         case BHND_IVAR_CORE_INDEX:
  208         case BHND_IVAR_CORE_UNIT:
  209                 return (EINVAL);
  210         case BHND_IVAR_PMU_INFO:
  211                 SIBA_LOCK(sc);
  212                 switch (dinfo->pmu_state) {
  213                 case SIBA_PMU_NONE:
  214                 case SIBA_PMU_BHND:
  215                         dinfo->pmu.bhnd_info = (void *)value;
  216                         dinfo->pmu_state = SIBA_PMU_BHND;
  217                         SIBA_UNLOCK(sc);
  218                         return (0);
  219 
  220                 case SIBA_PMU_PWRCTL:
  221                 case SIBA_PMU_FIXED:
  222                         panic("bhnd_set_pmu_info() called with siba PMU state "
  223                             "%d", dinfo->pmu_state);
  224                         return (ENXIO);
  225                 }
  226 
  227                 panic("invalid PMU state: %d", dinfo->pmu_state);
  228                 return (ENXIO);
  229 
  230         default:
  231                 return (ENOENT);
  232         }
  233 }
  234 
  235 static struct resource_list *
  236 siba_get_resource_list(device_t dev, device_t child)
  237 {
  238         struct siba_devinfo *dinfo = device_get_ivars(child);
  239         return (&dinfo->resources);
  240 }
  241 
  242 /* BHND_BUS_ALLOC_PMU() */
  243 static int
  244 siba_alloc_pmu(device_t dev, device_t child)
  245 {
  246         struct siba_softc       *sc;
  247         struct siba_devinfo     *dinfo;
  248         device_t                 chipc;
  249         device_t                 pwrctl;
  250         struct chipc_caps        ccaps;
  251         siba_pmu_state           pmu_state;
  252         int                      error;
  253 
  254         if (device_get_parent(child) != dev)
  255                 return (EINVAL);
  256 
  257         sc = device_get_softc(dev);
  258         dinfo = device_get_ivars(child);
  259         pwrctl = NULL;
  260 
  261         /* Fetch ChipCommon capability flags */
  262         chipc = bhnd_retain_provider(child, BHND_SERVICE_CHIPC);
  263         if (chipc != NULL) {
  264                 ccaps = *BHND_CHIPC_GET_CAPS(chipc);
  265                 bhnd_release_provider(child, chipc, BHND_SERVICE_CHIPC);
  266         } else {
  267                 memset(&ccaps, 0, sizeof(ccaps));
  268         }
  269 
  270         /* Defer to bhnd(4)'s PMU implementation if ChipCommon exists and
  271          * advertises PMU support */
  272         if (ccaps.pmu) {
  273                 if ((error = bhnd_generic_alloc_pmu(dev, child)))
  274                         return (error);
  275 
  276                 KASSERT(dinfo->pmu_state == SIBA_PMU_BHND,
  277                     ("unexpected PMU state: %d", dinfo->pmu_state));
  278 
  279                 return (0);
  280         }
  281 
  282         /*
  283          * This is either a legacy PWRCTL chipset, or the device does not
  284          * support dynamic clock control.
  285          * 
  286          * We need to map all bhnd(4) bus PMU to PWRCTL or no-op operations.
  287          */
  288         if (ccaps.pwr_ctrl) {
  289                 pmu_state = SIBA_PMU_PWRCTL;
  290                 pwrctl = bhnd_retain_provider(child, BHND_SERVICE_PWRCTL);
  291                 if (pwrctl == NULL) {
  292                         device_printf(dev, "PWRCTL not found\n");
  293                         return (ENODEV);
  294                 }
  295         } else {
  296                 pmu_state = SIBA_PMU_FIXED;
  297                 pwrctl = NULL;
  298         }
  299 
  300         SIBA_LOCK(sc);
  301 
  302         /* Per-core PMU state already allocated? */
  303         if (dinfo->pmu_state != SIBA_PMU_NONE) {
  304                 panic("duplicate PMU allocation for %s",
  305                     device_get_nameunit(child));
  306         }
  307 
  308         /* Update the child's PMU allocation state, and transfer ownership of
  309          * the PWRCTL provider reference (if any) */
  310         dinfo->pmu_state = pmu_state;
  311         dinfo->pmu.pwrctl = pwrctl;
  312 
  313         SIBA_UNLOCK(sc);
  314 
  315         return (0);
  316 }
  317 
  318 /* BHND_BUS_RELEASE_PMU() */
  319 static int
  320 siba_release_pmu(device_t dev, device_t child)
  321 {
  322         struct siba_softc       *sc;
  323         struct siba_devinfo     *dinfo;
  324         device_t                 pwrctl;
  325         int                      error;
  326 
  327         if (device_get_parent(child) != dev)
  328                 return (EINVAL);
  329 
  330         sc = device_get_softc(dev);
  331         dinfo = device_get_ivars(child);
  332 
  333         SIBA_LOCK(sc);
  334         switch(dinfo->pmu_state) {
  335         case SIBA_PMU_NONE:
  336                 panic("pmu over-release for %s", device_get_nameunit(child));
  337                 SIBA_UNLOCK(sc);
  338                 return (ENXIO);
  339 
  340         case SIBA_PMU_BHND:
  341                 SIBA_UNLOCK(sc);
  342                 return (bhnd_generic_release_pmu(dev, child));
  343 
  344         case SIBA_PMU_PWRCTL:
  345                 /* Requesting BHND_CLOCK_DYN releases any outstanding clock
  346                  * reservations */
  347                 pwrctl = dinfo->pmu.pwrctl;
  348                 error = bhnd_pwrctl_request_clock(pwrctl, child,
  349                     BHND_CLOCK_DYN);
  350                 if (error) {
  351                         SIBA_UNLOCK(sc);
  352                         return (error);
  353                 }
  354 
  355                 /* Clean up the child's PMU state */
  356                 dinfo->pmu_state = SIBA_PMU_NONE;
  357                 dinfo->pmu.pwrctl = NULL;
  358                 SIBA_UNLOCK(sc);
  359 
  360                 /* Release the provider reference */
  361                 bhnd_release_provider(child, pwrctl, BHND_SERVICE_PWRCTL);
  362                 return (0);
  363 
  364         case SIBA_PMU_FIXED:
  365                 /* Clean up the child's PMU state */
  366                 KASSERT(dinfo->pmu.pwrctl == NULL,
  367                     ("PWRCTL reference with FIXED state"));
  368 
  369                 dinfo->pmu_state = SIBA_PMU_NONE;
  370                 dinfo->pmu.pwrctl = NULL;
  371                 SIBA_UNLOCK(sc);
  372         }
  373 
  374         panic("invalid PMU state: %d", dinfo->pmu_state);
  375 }
  376 
  377 /* BHND_BUS_GET_CLOCK_LATENCY() */
  378 static int
  379 siba_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
  380     u_int *latency)
  381 {
  382         struct siba_softc       *sc;
  383         struct siba_devinfo     *dinfo;
  384         int                      error;
  385 
  386         if (device_get_parent(child) != dev)
  387                 return (EINVAL);
  388 
  389         sc = device_get_softc(dev);
  390         dinfo = device_get_ivars(child);
  391 
  392         SIBA_LOCK(sc);
  393         switch(dinfo->pmu_state) {
  394         case SIBA_PMU_NONE:
  395                 panic("no active PMU request state");
  396 
  397                 SIBA_UNLOCK(sc);
  398                 return (ENXIO);
  399 
  400         case SIBA_PMU_BHND:
  401                 SIBA_UNLOCK(sc);
  402                 return (bhnd_generic_get_clock_latency(dev, child, clock,
  403                     latency));
  404 
  405         case SIBA_PMU_PWRCTL:
  406                  error = bhnd_pwrctl_get_clock_latency(dinfo->pmu.pwrctl, clock,
  407                     latency);
  408                  SIBA_UNLOCK(sc);
  409 
  410                  return (error);
  411 
  412         case SIBA_PMU_FIXED:
  413                 SIBA_UNLOCK(sc);
  414 
  415                 /* HT clock is always available, and incurs no transition
  416                  * delay. */
  417                 switch (clock) {
  418                 case BHND_CLOCK_HT:
  419                         *latency = 0;
  420                         return (0);
  421 
  422                 default:
  423                         return (ENODEV);
  424                 }
  425 
  426                 return (ENODEV);
  427         }
  428 
  429         panic("invalid PMU state: %d", dinfo->pmu_state);
  430 }
  431 
  432 /* BHND_BUS_GET_CLOCK_FREQ() */
  433 static int
  434 siba_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
  435     u_int *freq)
  436 {
  437         struct siba_softc       *sc;
  438         struct siba_devinfo     *dinfo;
  439         int                      error;
  440 
  441         if (device_get_parent(child) != dev)
  442                 return (EINVAL);
  443 
  444         sc = device_get_softc(dev);
  445         dinfo = device_get_ivars(child);
  446 
  447         SIBA_LOCK(sc);
  448         switch(dinfo->pmu_state) {
  449         case SIBA_PMU_NONE:
  450                 panic("no active PMU request state");
  451 
  452                 SIBA_UNLOCK(sc);
  453                 return (ENXIO);
  454 
  455         case SIBA_PMU_BHND:
  456                 SIBA_UNLOCK(sc);
  457                 return (bhnd_generic_get_clock_freq(dev, child, clock, freq));
  458 
  459         case SIBA_PMU_PWRCTL:
  460                 error = bhnd_pwrctl_get_clock_freq(dinfo->pmu.pwrctl, clock,
  461                     freq);
  462                 SIBA_UNLOCK(sc);
  463 
  464                 return (error);
  465 
  466         case SIBA_PMU_FIXED:
  467                 SIBA_UNLOCK(sc);
  468 
  469                 return (ENODEV);
  470         }
  471 
  472         panic("invalid PMU state: %d", dinfo->pmu_state);
  473 }
  474 
  475 /* BHND_BUS_REQUEST_EXT_RSRC() */
  476 static int
  477 siba_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
  478 {
  479         struct siba_softc       *sc;
  480         struct siba_devinfo     *dinfo;
  481 
  482         if (device_get_parent(child) != dev)
  483                 return (EINVAL);
  484 
  485         sc = device_get_softc(dev);
  486         dinfo = device_get_ivars(child);
  487 
  488         SIBA_LOCK(sc);
  489         switch(dinfo->pmu_state) {
  490         case SIBA_PMU_NONE:
  491                 panic("no active PMU request state");
  492 
  493                 SIBA_UNLOCK(sc);
  494                 return (ENXIO);
  495 
  496         case SIBA_PMU_BHND:
  497                 SIBA_UNLOCK(sc);
  498                 return (bhnd_generic_request_ext_rsrc(dev, child, rsrc));
  499 
  500         case SIBA_PMU_PWRCTL:
  501         case SIBA_PMU_FIXED:
  502                 /* HW does not support per-core external resources */
  503                 SIBA_UNLOCK(sc);
  504                 return (ENODEV);
  505         }
  506 
  507         panic("invalid PMU state: %d", dinfo->pmu_state);
  508 }
  509 
  510 /* BHND_BUS_RELEASE_EXT_RSRC() */
  511 static int
  512 siba_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
  513 {
  514         struct siba_softc       *sc;
  515         struct siba_devinfo     *dinfo;
  516 
  517         if (device_get_parent(child) != dev)
  518                 return (EINVAL);
  519 
  520         sc = device_get_softc(dev);
  521         dinfo = device_get_ivars(child);
  522 
  523         SIBA_LOCK(sc);
  524         switch(dinfo->pmu_state) {
  525         case SIBA_PMU_NONE:
  526                 panic("no active PMU request state");
  527 
  528                 SIBA_UNLOCK(sc);
  529                 return (ENXIO);
  530 
  531         case SIBA_PMU_BHND:
  532                 SIBA_UNLOCK(sc);
  533                 return (bhnd_generic_release_ext_rsrc(dev, child, rsrc));
  534 
  535         case SIBA_PMU_PWRCTL:
  536         case SIBA_PMU_FIXED:
  537                 /* HW does not support per-core external resources */
  538                 SIBA_UNLOCK(sc);
  539                 return (ENODEV);
  540         }
  541 
  542         panic("invalid PMU state: %d", dinfo->pmu_state);
  543 }
  544 
  545 /* BHND_BUS_REQUEST_CLOCK() */
  546 static int
  547 siba_request_clock(device_t dev, device_t child, bhnd_clock clock)
  548 {
  549         struct siba_softc       *sc;
  550         struct siba_devinfo     *dinfo;
  551         int                      error;
  552 
  553         if (device_get_parent(child) != dev)
  554                 return (EINVAL);
  555 
  556         sc = device_get_softc(dev);
  557         dinfo = device_get_ivars(child);
  558 
  559         SIBA_LOCK(sc);
  560         switch(dinfo->pmu_state) {
  561         case SIBA_PMU_NONE:
  562                 panic("no active PMU request state");
  563 
  564                 SIBA_UNLOCK(sc);
  565                 return (ENXIO);
  566 
  567         case SIBA_PMU_BHND:
  568                 SIBA_UNLOCK(sc);
  569                 return (bhnd_generic_request_clock(dev, child, clock));
  570 
  571         case SIBA_PMU_PWRCTL:
  572                 error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
  573                     clock);
  574                 SIBA_UNLOCK(sc);
  575 
  576                 return (error);
  577 
  578         case SIBA_PMU_FIXED:
  579                 SIBA_UNLOCK(sc);
  580 
  581                 /* HT clock is always available, and fulfills any of the
  582                  * following clock requests */
  583                 switch (clock) {
  584                 case BHND_CLOCK_DYN:
  585                 case BHND_CLOCK_ILP:
  586                 case BHND_CLOCK_ALP:
  587                 case BHND_CLOCK_HT:
  588                         return (0);
  589 
  590                 default:
  591                         return (ENODEV);
  592                 }
  593         }
  594 
  595         panic("invalid PMU state: %d", dinfo->pmu_state);
  596 }
  597 
  598 /* BHND_BUS_ENABLE_CLOCKS() */
  599 static int
  600 siba_enable_clocks(device_t dev, device_t child, uint32_t clocks)
  601 {
  602         struct siba_softc       *sc;
  603         struct siba_devinfo     *dinfo;
  604 
  605         if (device_get_parent(child) != dev)
  606                 return (EINVAL);
  607 
  608         sc = device_get_softc(dev);
  609         dinfo = device_get_ivars(child);
  610 
  611         SIBA_LOCK(sc);
  612         switch(dinfo->pmu_state) {
  613         case SIBA_PMU_NONE:
  614                 panic("no active PMU request state");
  615 
  616                 SIBA_UNLOCK(sc);
  617                 return (ENXIO);
  618 
  619         case SIBA_PMU_BHND:
  620                 SIBA_UNLOCK(sc);
  621                 return (bhnd_generic_enable_clocks(dev, child, clocks));
  622 
  623         case SIBA_PMU_PWRCTL:
  624         case SIBA_PMU_FIXED:
  625                 SIBA_UNLOCK(sc);
  626 
  627                 /* All (supported) clocks are already enabled by default */
  628                 clocks &= ~(BHND_CLOCK_DYN |
  629                             BHND_CLOCK_ILP |
  630                             BHND_CLOCK_ALP |
  631                             BHND_CLOCK_HT);
  632 
  633                 if (clocks != 0) {
  634                         device_printf(dev, "%s requested unknown clocks: %#x\n",
  635                             device_get_nameunit(child), clocks);
  636                         return (ENODEV);
  637                 }
  638 
  639                 return (0);
  640         }
  641 
  642         panic("invalid PMU state: %d", dinfo->pmu_state);
  643 }
  644 
  645 static int
  646 siba_read_iost(device_t dev, device_t child, uint16_t *iost)
  647 {
  648         uint32_t        tmhigh;
  649         int             error;
  650 
  651         error = bhnd_read_config(child, SIBA_CFG0_TMSTATEHIGH, &tmhigh, 4);
  652         if (error)
  653                 return (error);
  654 
  655         *iost = (SIBA_REG_GET(tmhigh, TMH_SISF));
  656         return (0);
  657 }
  658 
  659 static int
  660 siba_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
  661 {
  662         uint32_t        ts_low;
  663         int             error;
  664 
  665         if ((error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4)))
  666                 return (error);
  667 
  668         *ioctl = (SIBA_REG_GET(ts_low, TML_SICF));
  669         return (0);
  670 }
  671 
  672 static int
  673 siba_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
  674 {
  675         struct siba_devinfo     *dinfo;
  676         struct bhnd_resource    *r;
  677         uint32_t                 ts_low, ts_mask;
  678 
  679         if (device_get_parent(child) != dev)
  680                 return (EINVAL);
  681 
  682         /* Fetch CFG0 mapping */
  683         dinfo = device_get_ivars(child);
  684         if ((r = dinfo->cfg_res[0]) == NULL)
  685                 return (ENODEV);
  686 
  687         /* Mask and set TMSTATELOW core flag bits */
  688         ts_mask = (mask << SIBA_TML_SICF_SHIFT) & SIBA_TML_SICF_MASK;
  689         ts_low = (value << SIBA_TML_SICF_SHIFT) & ts_mask;
  690 
  691         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
  692             ts_low, ts_mask);
  693         return (0);
  694 }
  695 
  696 static bool
  697 siba_is_hw_suspended(device_t dev, device_t child)
  698 {
  699         uint32_t                ts_low;
  700         uint16_t                ioctl;
  701         int                     error;
  702 
  703         /* Fetch target state */
  704         error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4);
  705         if (error) {
  706                 device_printf(child, "error reading HW reset state: %d\n",
  707                     error);
  708                 return (true);
  709         }
  710 
  711         /* Is core held in RESET? */
  712         if (ts_low & SIBA_TML_RESET)
  713                 return (true);
  714 
  715         /* Is target reject enabled? */
  716         if (ts_low & SIBA_TML_REJ_MASK)
  717                 return (true);
  718 
  719         /* Is core clocked? */
  720         ioctl = SIBA_REG_GET(ts_low, TML_SICF);
  721         if (!(ioctl & BHND_IOCTL_CLK_EN))
  722                 return (true);
  723 
  724         return (false);
  725 }
  726 
  727 static int
  728 siba_reset_hw(device_t dev, device_t child, uint16_t ioctl,
  729     uint16_t reset_ioctl)
  730 {
  731         struct siba_devinfo             *dinfo;
  732         struct bhnd_resource            *r;
  733         uint32_t                         ts_low, imstate;
  734         uint16_t                         clkflags;
  735         int                              error;
  736 
  737         if (device_get_parent(child) != dev)
  738                 return (EINVAL);
  739 
  740         dinfo = device_get_ivars(child);
  741 
  742         /* Can't suspend the core without access to the CFG0 registers */
  743         if ((r = dinfo->cfg_res[0]) == NULL)
  744                 return (ENODEV);
  745 
  746         /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
  747         clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
  748         if (ioctl & clkflags)
  749                 return (EINVAL);
  750 
  751         /* Place core into known RESET state */
  752         if ((error = bhnd_suspend_hw(child, reset_ioctl)))
  753                 return (error);
  754 
  755         /* Set RESET, clear REJ, set the caller's IOCTL flags, and
  756          * force clocks to ensure the signal propagates throughout the
  757          * core. */
  758         ts_low = SIBA_TML_RESET |
  759                  (ioctl << SIBA_TML_SICF_SHIFT) |
  760                  (BHND_IOCTL_CLK_EN << SIBA_TML_SICF_SHIFT) |
  761                  (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT);
  762 
  763         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
  764             ts_low, UINT32_MAX);
  765 
  766         /* Clear any target errors */
  767         if (bhnd_bus_read_4(r, SIBA_CFG0_TMSTATEHIGH) & SIBA_TMH_SERR) {
  768                 siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATEHIGH,
  769                     0x0, SIBA_TMH_SERR);
  770         }
  771 
  772         /* Clear any initiator errors */
  773         imstate = bhnd_bus_read_4(r, SIBA_CFG0_IMSTATE);
  774         if (imstate & (SIBA_IM_IBE|SIBA_IM_TO)) {
  775                 siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE, 0x0,
  776                     SIBA_IM_IBE|SIBA_IM_TO);
  777         }
  778 
  779         /* Release from RESET while leaving clocks forced, ensuring the
  780          * signal propagates throughout the core */
  781         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
  782             SIBA_TML_RESET);
  783 
  784         /* The core should now be active; we can clear the BHND_IOCTL_CLK_FORCE
  785          * bit and allow the core to manage clock gating. */
  786         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
  787             (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT));
  788 
  789         return (0);
  790 }
  791 
  792 static int
  793 siba_suspend_hw(device_t dev, device_t child, uint16_t ioctl)
  794 {
  795         struct siba_softc               *sc;
  796         struct siba_devinfo             *dinfo;
  797         struct bhnd_resource            *r;
  798         uint32_t                         idl, ts_low, ts_mask;
  799         uint16_t                         cflags, clkflags;
  800         int                              error;
  801 
  802         if (device_get_parent(child) != dev)
  803                 return (EINVAL);
  804 
  805         sc = device_get_softc(dev);
  806         dinfo = device_get_ivars(child);
  807 
  808         /* Can't suspend the core without access to the CFG0 registers */
  809         if ((r = dinfo->cfg_res[0]) == NULL)
  810                 return (ENODEV);
  811 
  812         /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
  813         clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
  814         if (ioctl & clkflags)
  815                 return (EINVAL);
  816 
  817         /* Already in RESET? */
  818         ts_low = bhnd_bus_read_4(r, SIBA_CFG0_TMSTATELOW);
  819         if (ts_low & SIBA_TML_RESET)
  820                 return (0);
  821 
  822         /* If clocks are already disabled, we can place the core directly
  823          * into RESET|REJ while setting the caller's IOCTL flags. */
  824         cflags = SIBA_REG_GET(ts_low, TML_SICF);
  825         if (!(cflags & BHND_IOCTL_CLK_EN)) {
  826                 ts_low = SIBA_TML_RESET | SIBA_TML_REJ |
  827                          (ioctl << SIBA_TML_SICF_SHIFT);
  828                 ts_mask = SIBA_TML_RESET | SIBA_TML_REJ | SIBA_TML_SICF_MASK;
  829 
  830                 siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
  831                     ts_low, ts_mask);
  832                 return (0);
  833         }
  834 
  835         /* Reject further transactions reaching this core */
  836         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
  837             SIBA_TML_REJ, SIBA_TML_REJ);
  838 
  839         /* Wait for transaction busy flag to clear for all transactions
  840          * initiated by this core */
  841         error = siba_wait_target_state(child, dinfo, SIBA_CFG0_TMSTATEHIGH,
  842             0x0, SIBA_TMH_BUSY, 100000);
  843         if (error)
  844                 return (error);
  845 
  846         /* If this is an initiator core, we need to reject initiator
  847          * transactions too. */
  848         idl = bhnd_bus_read_4(r, SIBA_CFG0_IDLOW);
  849         if (idl & SIBA_IDL_INIT) {
  850                 /* Reject further initiator transactions */
  851                 siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
  852                     SIBA_IM_RJ, SIBA_IM_RJ);
  853 
  854                 /* Wait for initiator busy flag to clear */
  855                 error = siba_wait_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
  856                     0x0, SIBA_IM_BY, 100000);
  857                 if (error)
  858                         return (error);
  859         }
  860 
  861         /* Put the core into RESET, set the caller's IOCTL flags, and
  862          * force clocks to ensure the RESET signal propagates throughout the
  863          * core. */
  864         ts_low = SIBA_TML_RESET |
  865                  (ioctl << SIBA_TML_SICF_SHIFT) |
  866                  (BHND_IOCTL_CLK_EN << SIBA_TML_SICF_SHIFT) |
  867                  (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT);
  868         ts_mask = SIBA_TML_RESET |
  869                   SIBA_TML_SICF_MASK;
  870 
  871         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, ts_low,
  872             ts_mask);
  873 
  874         /* Give RESET ample time */
  875         DELAY(10);
  876 
  877         /* Clear previously asserted initiator reject */
  878         if (idl & SIBA_IDL_INIT) {
  879                 siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE, 0x0,
  880                     SIBA_IM_RJ);
  881         }
  882 
  883         /* Disable all clocks, leaving RESET and REJ asserted */
  884         siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
  885             (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) << SIBA_TML_SICF_SHIFT);
  886 
  887         /*
  888          * Core is now in RESET.
  889          *
  890          * If the core holds any PWRCTL clock reservations, we need to release
  891          * those now. This emulates the standard bhnd(4) PMU behavior of RESET
  892          * automatically clearing clkctl
  893          */
  894         SIBA_LOCK(sc);
  895         if (dinfo->pmu_state == SIBA_PMU_PWRCTL) {
  896                 error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
  897                     BHND_CLOCK_DYN);
  898                 SIBA_UNLOCK(sc);
  899 
  900                 if (error) {
  901                         device_printf(child, "failed to release clock request: "
  902                             "%d", error);
  903                         return (error);
  904                 }
  905 
  906                 return (0);
  907         } else {
  908                 SIBA_UNLOCK(sc);
  909                 return (0);
  910         }
  911 }
  912 
  913 static int
  914 siba_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
  915     u_int width)
  916 {
  917         struct siba_devinfo     *dinfo;
  918         rman_res_t               r_size;
  919 
  920         /* Must be directly attached */
  921         if (device_get_parent(child) != dev)
  922                 return (EINVAL);
  923 
  924         /* CFG0 registers must be available */
  925         dinfo = device_get_ivars(child);
  926         if (dinfo->cfg_res[0] == NULL)
  927                 return (ENODEV);
  928 
  929         /* Offset must fall within CFG0 */
  930         r_size = rman_get_size(dinfo->cfg_res[0]->res);
  931         if (r_size < offset || r_size - offset < width)
  932                 return (EFAULT);
  933 
  934         switch (width) {
  935         case 1:
  936                 *((uint8_t *)value) = bhnd_bus_read_1(dinfo->cfg_res[0],
  937                     offset);
  938                 return (0);
  939         case 2:
  940                 *((uint16_t *)value) = bhnd_bus_read_2(dinfo->cfg_res[0],
  941                     offset);
  942                 return (0);
  943         case 4:
  944                 *((uint32_t *)value) = bhnd_bus_read_4(dinfo->cfg_res[0],
  945                     offset);
  946                 return (0);
  947         default:
  948                 return (EINVAL);
  949         }
  950 }
  951 
  952 static int
  953 siba_write_config(device_t dev, device_t child, bus_size_t offset,
  954     const void *value, u_int width)
  955 {
  956         struct siba_devinfo     *dinfo;
  957         struct bhnd_resource    *r;
  958         rman_res_t               r_size;
  959 
  960         /* Must be directly attached */
  961         if (device_get_parent(child) != dev)
  962                 return (EINVAL);
  963 
  964         /* CFG0 registers must be available */
  965         dinfo = device_get_ivars(child);
  966         if ((r = dinfo->cfg_res[0]) == NULL)
  967                 return (ENODEV);
  968 
  969         /* Offset must fall within CFG0 */
  970         r_size = rman_get_size(r->res);
  971         if (r_size < offset || r_size - offset < width)
  972                 return (EFAULT);
  973 
  974         switch (width) {
  975         case 1:
  976                 bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
  977                 return (0);
  978         case 2:
  979                 bhnd_bus_write_2(r, offset, *(const uint8_t *)value);
  980                 return (0);
  981         case 4:
  982                 bhnd_bus_write_4(r, offset, *(const uint8_t *)value);
  983                 return (0);
  984         default:
  985                 return (EINVAL);
  986         }
  987 }
  988 
  989 static u_int
  990 siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
  991 {
  992         struct siba_devinfo *dinfo;
  993 
  994         /* delegate non-bus-attached devices to our parent */
  995         if (device_get_parent(child) != dev)
  996                 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
  997                     type));
  998 
  999         dinfo = device_get_ivars(child);
 1000         return (siba_port_count(&dinfo->core_id, type));
 1001 }
 1002 
 1003 static u_int
 1004 siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
 1005     u_int port)
 1006 {
 1007         struct siba_devinfo     *dinfo;
 1008 
 1009         /* delegate non-bus-attached devices to our parent */
 1010         if (device_get_parent(child) != dev)
 1011                 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
 1012                     type, port));
 1013 
 1014         dinfo = device_get_ivars(child);
 1015         return (siba_port_region_count(&dinfo->core_id, type, port));
 1016 }
 1017 
 1018 static int
 1019 siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
 1020     u_int port_num, u_int region_num)
 1021 {
 1022         struct siba_devinfo     *dinfo;
 1023         struct siba_addrspace   *addrspace;
 1024         struct siba_cfg_block   *cfg;
 1025 
 1026         /* delegate non-bus-attached devices to our parent */
 1027         if (device_get_parent(child) != dev)
 1028                 return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
 1029                     port_type, port_num, region_num));
 1030 
 1031         dinfo = device_get_ivars(child);
 1032 
 1033         /* Look for a matching addrspace entry */
 1034         addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
 1035         if (addrspace != NULL)
 1036                 return (addrspace->sa_rid);
 1037 
 1038         /* Try the config blocks */
 1039         cfg = siba_find_cfg_block(dinfo, port_type, port_num, region_num);
 1040         if (cfg != NULL)
 1041                 return (cfg->cb_rid);
 1042 
 1043         /* Not found */
 1044         return (-1);
 1045 }
 1046 
 1047 static int
 1048 siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
 1049     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
 1050 {
 1051         struct siba_devinfo     *dinfo;
 1052 
 1053         /* delegate non-bus-attached devices to our parent */
 1054         if (device_get_parent(child) != dev)
 1055                 return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
 1056                     type, rid, port_type, port_num, region_num));
 1057 
 1058         dinfo = device_get_ivars(child);
 1059 
 1060         /* Ports are always memory mapped */
 1061         if (type != SYS_RES_MEMORY)
 1062                 return (EINVAL);
 1063 
 1064         /* Look for a matching addrspace entry */
 1065         for (u_int i = 0; i < dinfo->core_id.num_admatch; i++) {
 1066                 if (dinfo->addrspace[i].sa_rid != rid)
 1067                         continue;
 1068 
 1069                 *port_type = BHND_PORT_DEVICE;
 1070                 *port_num = siba_addrspace_device_port(i);
 1071                 *region_num = siba_addrspace_device_region(i);
 1072                 return (0);
 1073         }
 1074 
 1075         /* Try the config blocks */
 1076         for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) {
 1077                 if (dinfo->cfg[i].cb_rid != rid)
 1078                         continue;
 1079 
 1080                 *port_type = BHND_PORT_AGENT;
 1081                 *port_num = siba_cfg_agent_port(i);
 1082                 *region_num = siba_cfg_agent_region(i);
 1083                 return (0);
 1084         }
 1085 
 1086         /* Not found */
 1087         return (ENOENT);
 1088 }
 1089 
 1090 static int
 1091 siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
 1092     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
 1093 {
 1094         struct siba_devinfo     *dinfo;
 1095         struct siba_addrspace   *addrspace;
 1096         struct siba_cfg_block   *cfg;
 1097 
 1098         /* delegate non-bus-attached devices to our parent */
 1099         if (device_get_parent(child) != dev) {
 1100                 return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
 1101                     port_type, port_num, region_num, addr, size));
 1102         }
 1103 
 1104         dinfo = device_get_ivars(child);
 1105 
 1106         /* Look for a matching addrspace */
 1107         addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
 1108         if (addrspace != NULL) {
 1109                 *addr = addrspace->sa_base;
 1110                 *size = addrspace->sa_size - addrspace->sa_bus_reserved;
 1111                 return (0);
 1112         }
 1113 
 1114         /* Look for a matching cfg block */
 1115         cfg = siba_find_cfg_block(dinfo, port_type, port_num, region_num);
 1116         if (cfg != NULL) {
 1117                 *addr = cfg->cb_base;
 1118                 *size = cfg->cb_size;
 1119                 return (0);
 1120         }
 1121 
 1122         /* Not found */
 1123         return (ENOENT);
 1124 }
 1125 
 1126 /**
 1127  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
 1128  */
 1129 u_int
 1130 siba_get_intr_count(device_t dev, device_t child)
 1131 {
 1132         struct siba_devinfo     *dinfo;
 1133 
 1134         /* delegate non-bus-attached devices to our parent */
 1135         if (device_get_parent(child) != dev)
 1136                 return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
 1137 
 1138         dinfo = device_get_ivars(child);
 1139         if (!dinfo->core_id.intr_en) {
 1140                 /* No interrupts */
 1141                 return (0);
 1142         } else {
 1143                 /* One assigned interrupt */
 1144                 return (1);
 1145         }
 1146 }
 1147 
 1148 /**
 1149  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
 1150  */
 1151 int
 1152 siba_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
 1153 {
 1154         struct siba_devinfo     *dinfo;
 1155 
 1156         /* delegate non-bus-attached devices to our parent */
 1157         if (device_get_parent(child) != dev)
 1158                 return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
 1159                     intr, ivec));
 1160 
 1161         /* Must be a valid interrupt ID */
 1162         if (intr >= siba_get_intr_count(dev, child))
 1163                 return (ENXIO);
 1164 
 1165         KASSERT(intr == 0, ("invalid ivec %u", intr));
 1166 
 1167         dinfo = device_get_ivars(child);
 1168 
 1169         KASSERT(dinfo->core_id.intr_en,
 1170             ("core does not have an interrupt assigned"));
 1171 
 1172         *ivec = dinfo->core_id.intr_flag;
 1173         return (0);
 1174 }
 1175 
 1176 /**
 1177  * Map per-core configuration blocks for @p dinfo.
 1178  *
 1179  * @param dev The siba bus device.
 1180  * @param dinfo The device info instance on which to map all per-core
 1181  * configuration blocks.
 1182  */
 1183 static int
 1184 siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
 1185 {
 1186         struct siba_addrspace   *addrspace;
 1187         rman_res_t               r_start, r_count, r_end;
 1188         uint8_t                  num_cfg;
 1189         int                      rid;
 1190 
 1191         num_cfg = dinfo->core_id.num_cfg_blocks;
 1192         if (num_cfg > SIBA_MAX_CFG) {
 1193                 device_printf(dev, "config block count %hhu out of range\n",
 1194                     num_cfg);
 1195                 return (ENXIO);
 1196         }
 1197 
 1198         /* Fetch the core register address space */
 1199         addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
 1200         if (addrspace == NULL) {
 1201                 device_printf(dev, "missing device registers\n");
 1202                 return (ENXIO);
 1203         }
 1204 
 1205         /*
 1206          * Map the per-core configuration blocks
 1207          */
 1208         for (uint8_t i = 0; i < num_cfg; i++) {
 1209                 /* Add to child's resource list */
 1210                 r_start = addrspace->sa_base + SIBA_CFG_OFFSET(i);
 1211                 r_count = SIBA_CFG_SIZE;
 1212                 r_end = r_start + r_count - 1;
 1213 
 1214                 rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
 1215                     r_start, r_end, r_count);
 1216 
 1217                 /* Initialize config block descriptor */
 1218                 dinfo->cfg[i] = ((struct siba_cfg_block) {
 1219                         .cb_base = r_start,
 1220                         .cb_size = SIBA_CFG_SIZE,
 1221                         .cb_rid = rid
 1222                 });
 1223 
 1224                 /* Map the config resource for bus-level access */
 1225                 dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
 1226                 dinfo->cfg_res[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
 1227                     SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
 1228                     r_count, RF_ACTIVE|RF_SHAREABLE);
 1229 
 1230                 if (dinfo->cfg_res[i] == NULL) {
 1231                         device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
 1232                             i);
 1233                         return (ENXIO);
 1234                 }
 1235         }
 1236 
 1237         return (0);
 1238 }
 1239 
 1240 static device_t
 1241 siba_add_child(device_t dev, u_int order, const char *name, int unit)
 1242 {
 1243         struct siba_devinfo     *dinfo;
 1244         device_t                 child;
 1245 
 1246         child = device_add_child_ordered(dev, order, name, unit);
 1247         if (child == NULL)
 1248                 return (NULL);
 1249 
 1250         if ((dinfo = siba_alloc_dinfo(dev)) == NULL) {
 1251                 device_delete_child(dev, child);
 1252                 return (NULL);
 1253         }
 1254 
 1255         device_set_ivars(child, dinfo);
 1256 
 1257         return (child);
 1258 }
 1259 
 1260 static void
 1261 siba_child_deleted(device_t dev, device_t child)
 1262 {
 1263         struct siba_devinfo     *dinfo;
 1264 
 1265         /* Call required bhnd(4) implementation */
 1266         bhnd_generic_child_deleted(dev, child);
 1267 
 1268         /* Free siba device info */
 1269         if ((dinfo = device_get_ivars(child)) != NULL)
 1270                 siba_free_dinfo(dev, child, dinfo);
 1271 
 1272         device_set_ivars(child, NULL);
 1273 }
 1274 
 1275 /**
 1276  * Scan the core table and add all valid discovered cores to
 1277  * the bus.
 1278  * 
 1279  * @param dev The siba bus device.
 1280  */
 1281 int
 1282 siba_add_children(device_t dev)
 1283 {
 1284         bhnd_erom_t                     *erom;
 1285         struct siba_erom                *siba_erom;
 1286         struct bhnd_erom_io             *eio;
 1287         const struct bhnd_chipid        *cid;
 1288         struct siba_core_id             *cores;
 1289         device_t                        *children;
 1290         int                              error;
 1291 
 1292         cid = BHND_BUS_GET_CHIPID(dev, dev);
 1293 
 1294         /* Allocate our EROM parser */
 1295         eio = bhnd_erom_iores_new(dev, SIBA_EROM_RID);
 1296         erom = bhnd_erom_alloc(&siba_erom_parser, cid, eio);
 1297         if (erom == NULL) {
 1298                 bhnd_erom_io_fini(eio);
 1299                 return (ENODEV);
 1300         }
 1301 
 1302         /* Allocate our temporary core and device table */
 1303         cores = malloc(sizeof(*cores) * cid->ncores, M_BHND, M_WAITOK);
 1304         children = malloc(sizeof(*children) * cid->ncores, M_BHND,
 1305             M_WAITOK | M_ZERO);
 1306 
 1307         /*
 1308          * Add child devices for all discovered cores.
 1309          * 
 1310          * On bridged devices, we'll exhaust our available register windows if
 1311          * we map config blocks on unpopulated/disabled cores. To avoid this, we
 1312          * defer mapping of the per-core siba(4) config blocks until all cores
 1313          * have been enumerated and otherwise configured.
 1314          */
 1315         siba_erom = (struct siba_erom *)erom;
 1316         for (u_int i = 0; i < cid->ncores; i++) {
 1317                 struct siba_devinfo     *dinfo;
 1318                 device_t                 child;
 1319 
 1320                 if ((error = siba_erom_get_core_id(siba_erom, i, &cores[i])))
 1321                         goto failed;
 1322 
 1323                 /* Add the child device */
 1324                 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
 1325                 if (child == NULL) {
 1326                         error = ENXIO;
 1327                         goto failed;
 1328                 }
 1329 
 1330                 children[i] = child;
 1331 
 1332                 /* Initialize per-device bus info */
 1333                 if ((dinfo = device_get_ivars(child)) == NULL) {
 1334                         error = ENXIO;
 1335                         goto failed;
 1336                 }
 1337 
 1338                 if ((error = siba_init_dinfo(dev, child, dinfo, &cores[i])))
 1339                         goto failed;
 1340 
 1341                 /* If pins are floating or the hardware is otherwise
 1342                  * unpopulated, the device shouldn't be used. */
 1343                 if (bhnd_is_hw_disabled(child))
 1344                         device_disable(child);
 1345         }
 1346 
 1347         /* Free EROM (and any bridge register windows it might hold) */
 1348         bhnd_erom_free(erom);
 1349         erom = NULL;
 1350 
 1351         /* Map all valid core's config register blocks and perform interrupt
 1352          * assignment */
 1353         for (u_int i = 0; i < cid->ncores; i++) {
 1354                 struct siba_devinfo     *dinfo;
 1355                 device_t                 child;
 1356 
 1357                 child = children[i];
 1358 
 1359                 /* Skip if core is disabled */
 1360                 if (bhnd_is_hw_disabled(child))
 1361                         continue;
 1362 
 1363                 dinfo = device_get_ivars(child);
 1364 
 1365                 /* Map the core's config blocks */
 1366                 if ((error = siba_map_cfg_resources(dev, dinfo)))
 1367                         goto failed;
 1368 
 1369                 /* Issue bus callback for fully initialized child. */
 1370                 BHND_BUS_CHILD_ADDED(dev, child);
 1371         }
 1372 
 1373         free(cores, M_BHND);
 1374         free(children, M_BHND);
 1375 
 1376         return (0);
 1377 
 1378 failed:
 1379         for (u_int i = 0; i < cid->ncores; i++) {
 1380                 if (children[i] == NULL)
 1381                         continue;
 1382 
 1383                 device_delete_child(dev, children[i]);
 1384         }
 1385 
 1386         free(cores, M_BHND);
 1387         free(children, M_BHND);
 1388         if (erom != NULL)
 1389                 bhnd_erom_free(erom);
 1390 
 1391         return (error);
 1392 }
 1393 
 1394 static device_method_t siba_methods[] = {
 1395         /* Device interface */
 1396         DEVMETHOD(device_probe,                 siba_probe),
 1397         DEVMETHOD(device_attach,                siba_attach),
 1398         DEVMETHOD(device_detach,                siba_detach),
 1399         DEVMETHOD(device_resume,                siba_resume),
 1400         DEVMETHOD(device_suspend,               siba_suspend),
 1401 
 1402         /* Bus interface */
 1403         DEVMETHOD(bus_add_child,                siba_add_child),
 1404         DEVMETHOD(bus_child_deleted,            siba_child_deleted),
 1405         DEVMETHOD(bus_read_ivar,                siba_read_ivar),
 1406         DEVMETHOD(bus_write_ivar,               siba_write_ivar),
 1407         DEVMETHOD(bus_get_resource_list,        siba_get_resource_list),
 1408 
 1409         /* BHND interface */
 1410         DEVMETHOD(bhnd_bus_get_erom_class,      siba_get_erom_class),
 1411         DEVMETHOD(bhnd_bus_alloc_pmu,           siba_alloc_pmu),
 1412         DEVMETHOD(bhnd_bus_release_pmu,         siba_release_pmu),
 1413         DEVMETHOD(bhnd_bus_request_clock,       siba_request_clock),
 1414         DEVMETHOD(bhnd_bus_enable_clocks,       siba_enable_clocks),
 1415         DEVMETHOD(bhnd_bus_request_ext_rsrc,    siba_request_ext_rsrc),
 1416         DEVMETHOD(bhnd_bus_release_ext_rsrc,    siba_release_ext_rsrc),
 1417         DEVMETHOD(bhnd_bus_get_clock_freq,      siba_get_clock_freq),
 1418         DEVMETHOD(bhnd_bus_get_clock_latency,   siba_get_clock_latency),
 1419         DEVMETHOD(bhnd_bus_read_ioctl,          siba_read_ioctl),
 1420         DEVMETHOD(bhnd_bus_write_ioctl,         siba_write_ioctl),
 1421         DEVMETHOD(bhnd_bus_read_iost,           siba_read_iost),
 1422         DEVMETHOD(bhnd_bus_is_hw_suspended,     siba_is_hw_suspended),
 1423         DEVMETHOD(bhnd_bus_reset_hw,            siba_reset_hw),
 1424         DEVMETHOD(bhnd_bus_suspend_hw,          siba_suspend_hw),
 1425         DEVMETHOD(bhnd_bus_read_config,         siba_read_config),
 1426         DEVMETHOD(bhnd_bus_write_config,        siba_write_config),
 1427         DEVMETHOD(bhnd_bus_get_port_count,      siba_get_port_count),
 1428         DEVMETHOD(bhnd_bus_get_region_count,    siba_get_region_count),
 1429         DEVMETHOD(bhnd_bus_get_port_rid,        siba_get_port_rid),
 1430         DEVMETHOD(bhnd_bus_decode_port_rid,     siba_decode_port_rid),
 1431         DEVMETHOD(bhnd_bus_get_region_addr,     siba_get_region_addr),
 1432         DEVMETHOD(bhnd_bus_get_intr_count,      siba_get_intr_count),
 1433         DEVMETHOD(bhnd_bus_get_intr_ivec,       siba_get_intr_ivec),
 1434 
 1435         DEVMETHOD_END
 1436 };
 1437 
 1438 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
 1439 
 1440 MODULE_VERSION(siba, 1);
 1441 MODULE_DEPEND(siba, bhnd, 1, 1, 1);

Cache object: aa2c5fd2e2aaea765859c12f1840de91


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