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_erom.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 <landonf@FreeBSD.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 
   43 #include <machine/bus.h>
   44 
   45 #include <dev/bhnd/bhnd_eromvar.h>
   46 
   47 #include <dev/bhnd/cores/chipc/chipcreg.h>
   48 
   49 #include "sibareg.h"
   50 #include "sibavar.h"
   51 
   52 #include "siba_eromvar.h"
   53 
   54 struct siba_erom;
   55 struct siba_erom_io;
   56 
   57 static int                      siba_eio_init(struct siba_erom_io *io,
   58                                     struct bhnd_erom_io *eio, u_int ncores);
   59 
   60 static uint32_t                 siba_eio_read_4(struct siba_erom_io *io,
   61                                     u_int core_idx, bus_size_t offset);
   62 
   63 static int                      siba_eio_read_core_id(struct siba_erom_io *io,
   64                                     u_int core_idx, int unit,
   65                                     struct siba_core_id *sid);
   66 
   67 static int                      siba_eio_read_chipid(struct siba_erom_io *io,
   68                                     bus_addr_t enum_addr,
   69                                     struct bhnd_chipid *cid);
   70 
   71 /**
   72  * SIBA EROM generic I/O context
   73  */
   74 struct siba_erom_io {
   75         struct bhnd_erom_io     *eio;           /**< erom I/O callbacks */
   76         bhnd_addr_t              base_addr;     /**< address of first core */
   77         u_int                    ncores;        /**< core count */
   78 };
   79 
   80 /**
   81  * SIBA EROM per-instance state.
   82  */
   83 struct siba_erom {
   84         struct bhnd_erom        obj;
   85         struct siba_erom_io     io;     /**< i/o context */
   86 };
   87 
   88 #define EROM_LOG(io, fmt, ...)  do {                            \
   89         printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__);        \
   90 } while(0)
   91 
   92 /* SIBA implementation of BHND_EROM_PROBE() */
   93 static int
   94 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
   95     const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
   96 {
   97         struct siba_erom_io     io;
   98         uint32_t                idreg;
   99         int                     error;
  100 
  101         /* Initialize I/O context, assuming at least the first core is mapped */
  102         if ((error = siba_eio_init(&io, eio, 1)))
  103                 return (error);
  104 
  105         /* Try using the provided hint. */
  106         if (hint != NULL) {
  107                 struct siba_core_id sid;
  108 
  109                 /* Validate bus type */
  110                 if (hint->chip_type != BHND_CHIPTYPE_SIBA)
  111                         return (ENXIO);
  112 
  113                 /*
  114                  * Verify the first core's IDHIGH/IDLOW identification.
  115                  * 
  116                  * The core must be a Broadcom core, but must *not* be
  117                  * a chipcommon core; those shouldn't be hinted.
  118                  *
  119                  * The first core on EXTIF-equipped devices varies, but on the
  120                  * BCM4710, it's a SDRAM core (0x803).
  121                  */
  122 
  123                 if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
  124                         return (error);
  125 
  126                 if (sid.core_info.vendor != BHND_MFGID_BCM)
  127                         return (ENXIO);
  128 
  129                 if (sid.core_info.device == BHND_COREID_CC)
  130                         return (EINVAL);
  131 
  132                 *cid = *hint;
  133         } else {
  134                 /* Validate bus type */
  135                 idreg = siba_eio_read_4(&io, 0, CHIPC_ID);
  136                 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
  137                         return (ENXIO); 
  138 
  139                 /* Identify the chipset */
  140                 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
  141                         return (error);
  142 
  143                 /* Verify the chip type */
  144                 if (cid->chip_type != BHND_CHIPTYPE_SIBA)
  145                         return (ENXIO);
  146         }
  147 
  148         /*
  149          * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
  150          * without triggering build failure due to -Wtype-limits
  151          *
  152          * if (cid.ncores > SIBA_MAX_CORES)
  153          *      return (EINVAL)
  154          */
  155         _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
  156             "ncores could result in over-read of backing resource");
  157 
  158         return (0);
  159 }
  160 
  161 /* SIBA implementation of BHND_EROM_INIT() */
  162 static int
  163 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
  164     struct bhnd_erom_io *eio)
  165 {
  166         struct siba_erom        *sc;
  167         int                      error;
  168 
  169         sc = (struct siba_erom *)erom;
  170 
  171         /* Attempt to map the full core enumeration space */
  172         error = bhnd_erom_io_map(eio, cid->enum_addr,
  173             cid->ncores * SIBA_CORE_SIZE);
  174         if (error) {
  175                 printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
  176                     cid->ncores, error);
  177                 return (error);
  178         }
  179 
  180         /* Initialize I/O context */
  181         return (siba_eio_init(&sc->io, eio, cid->ncores));
  182 }
  183 
  184 /* SIBA implementation of BHND_EROM_FINI() */
  185 static void
  186 siba_erom_fini(bhnd_erom_t *erom)
  187 {
  188         struct siba_erom *sc = (struct siba_erom *)erom;
  189 
  190         bhnd_erom_io_fini(sc->io.eio);
  191 }
  192 
  193 /* Initialize siba_erom resource I/O context */
  194 static int
  195 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
  196 {
  197         io->eio = eio;
  198         io->ncores = ncores;
  199         return (0);
  200 }
  201 
  202 /**
  203  * Read a 32-bit value from @p offset relative to the base address of
  204  * the given @p core_idx.
  205  * 
  206  * @param io EROM I/O context.
  207  * @param core_idx Core index.
  208  * @param offset Core register offset.
  209  */
  210 static uint32_t
  211 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
  212 {
  213         /* Sanity check core index and offset */
  214         if (core_idx >= io->ncores)
  215                 panic("core index %u out of range (ncores=%u)", core_idx,
  216                     io->ncores);
  217 
  218         if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
  219                 panic("invalid core offset %#jx", (uintmax_t)offset);
  220 
  221         /* Perform read */
  222         return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
  223             4));
  224 }
  225 
  226 /**
  227  * Read and parse identification registers for the given @p core_index.
  228  * 
  229  * @param io EROM I/O context.
  230  * @param core_idx The core index.
  231  * @param unit The caller-specified unit number to be included in the return
  232  * value.
  233  * @param[out] sid On success, the parsed siba core id.
  234  * 
  235  * @retval 0            success
  236  * @retval non-zero     if reading or parsing the identification registers
  237  *                      otherwise fails, a regular unix error code will be
  238  *                      returned.
  239  */
  240 static int
  241 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
  242     struct siba_core_id *sid)
  243 {
  244         struct siba_admatch     admatch[SIBA_MAX_ADDRSPACE];
  245         uint32_t                idhigh, idlow;
  246         uint32_t                tpsflag;
  247         uint16_t                ocp_vendor;
  248         uint8_t                 sonics_rev;
  249         uint8_t                 num_admatch;
  250         uint8_t                 num_admatch_en;
  251         uint8_t                 num_cfg;
  252         bool                    intr_en;
  253         u_int                   intr_flag;
  254         int                     error;
  255 
  256         idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
  257         idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
  258         tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
  259 
  260         ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
  261         sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
  262         num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
  263         if (num_admatch > nitems(admatch)) {
  264                 printf("core%u: invalid admatch count %hhu\n", core_idx,
  265                     num_admatch);
  266                 return (EINVAL);
  267         }
  268 
  269         /* Determine backplane interrupt distribution configuration */
  270         intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
  271         intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
  272 
  273         /* Determine the number of sonics config register blocks */
  274         num_cfg = SIBA_CFG_NUM_2_2;
  275         if (sonics_rev >= SIBA_IDL_SBREV_2_3)
  276                 num_cfg = SIBA_CFG_NUM_2_3;
  277 
  278         /* Parse all admatch descriptors */
  279         num_admatch_en = 0;
  280         for (uint8_t i = 0; i < num_admatch; i++) {
  281                 uint32_t        am_value;
  282                 u_int           am_offset;
  283 
  284                 KASSERT(i < nitems(admatch), ("invalid admatch index"));
  285 
  286                 /* Determine the register offset */
  287                 am_offset = siba_admatch_offset(i);
  288                 if (am_offset == 0) {
  289                         printf("core%u: addrspace %hhu is unsupported",
  290                             core_idx, i);
  291                         return (ENODEV);
  292                 }
  293 
  294                 /* Read and parse the address match register */
  295                 am_value = siba_eio_read_4(io, core_idx, am_offset);
  296                 error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
  297                 if (error) {
  298                         printf("core%u: failed to decode admatch[%hhu] "
  299                             "register value 0x%x\n", core_idx, i, am_value);
  300                         return (error);
  301                 }
  302 
  303                 /* Skip disabled entries */
  304                 if (!admatch[num_admatch_en].am_enabled)
  305                         continue;
  306 
  307                 /* Reject unsupported negative matches. These are not used on
  308                  * any known devices */
  309                 if (admatch[num_admatch_en].am_negative) {
  310                         printf("core%u: unsupported negative admatch[%hhu] "
  311                             "value 0x%x\n", core_idx, i, am_value);
  312                         return (ENXIO);
  313                 }
  314 
  315                 num_admatch_en++;
  316         }
  317 
  318         /* Populate the result */
  319         *sid = (struct siba_core_id) {
  320                 .core_info      = {
  321                         .vendor = siba_get_bhnd_mfgid(ocp_vendor),
  322                         .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
  323                         .hwrev  = SIBA_IDH_CORE_REV(idhigh),
  324                         .core_idx = core_idx,
  325                         .unit   = unit
  326                 },
  327                 .sonics_vendor  = ocp_vendor,
  328                 .sonics_rev     = sonics_rev,
  329                 .intr_en        = intr_en,
  330                 .intr_flag      = intr_flag,
  331                 .num_admatch    = num_admatch_en,
  332                 .num_cfg_blocks = num_cfg
  333         };
  334         memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
  335 
  336         return (0);
  337 }
  338 
  339 /**
  340  * Read and parse the SSB identification registers for the given @p core_index,
  341  * returning the siba(4) core identification in @p sid.
  342  * 
  343  * @param sc A siba EROM instance.
  344  * @param core_idx The index of the core to be identified.
  345  * @param[out] result On success, the parsed siba core id.
  346  * 
  347  * @retval 0            success
  348  * @retval non-zero     if reading or parsing the identification registers
  349  *                      otherwise fails, a regular unix error code will be
  350  *                      returned.
  351  */
  352 int
  353 siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
  354     struct siba_core_id *result)
  355 {
  356         struct siba_core_id     sid;
  357         int                     error;
  358 
  359         /* Fetch the core info, assuming a unit number of 0 */
  360         if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
  361                 return (error);
  362 
  363         /* Scan preceding cores to determine the real unit number. */
  364         for (u_int i = 0; i < core_idx; i++) {
  365                 struct siba_core_id prev;
  366 
  367                 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
  368                         return (error);
  369 
  370                 /* Bump the unit number? */
  371                 if (sid.core_info.vendor == prev.core_info.vendor &&
  372                     sid.core_info.device == prev.core_info.device)
  373                         sid.core_info.unit++;
  374         }
  375 
  376         *result = sid;
  377         return (0);
  378 }
  379 
  380 /**
  381  * Read and parse the chip identification register from the ChipCommon core.
  382  * 
  383  * @param io EROM I/O context.
  384  * @param enum_addr The physical address mapped by @p io.
  385  * @param cid On success, the parsed chip identifier.
  386  */
  387 static int
  388 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
  389     struct bhnd_chipid *cid)
  390 {
  391         struct siba_core_id     ccid;
  392         int                     error;
  393 
  394         /* Identify the chipcommon core */
  395         if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
  396                 return (error);
  397 
  398         if (ccid.core_info.vendor != BHND_MFGID_BCM ||
  399             ccid.core_info.device != BHND_COREID_CC)
  400         {
  401                 if (bootverbose) {
  402                         EROM_LOG(io, "first core not chipcommon "
  403                             "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
  404                             ccid.core_info.device);
  405                 }
  406                 return (ENXIO);
  407         }
  408 
  409         /* Identify the chipset */
  410         if ((error = bhnd_erom_read_chipid(io->eio, cid)))
  411                 return (error);
  412 
  413         /* Do we need to fix up the core count? */
  414         if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev))
  415                 return (0);
  416 
  417         switch (cid->chip_id) {
  418         case BHND_CHIPID_BCM4306:
  419                 cid->ncores = 6;
  420                 break;
  421         case BHND_CHIPID_BCM4704:
  422                 cid->ncores = 9;
  423                 break;
  424         case BHND_CHIPID_BCM5365:
  425                 /*
  426                 * BCM5365 does support ID_NUMCORE in at least
  427                 * some of its revisions, but for unknown
  428                 * reasons, Broadcom's drivers always exclude
  429                 * the ChipCommon revision (0x5) used by BCM5365
  430                 * from the set of revisions supporting
  431                 * ID_NUMCORE, and instead supply a fixed value.
  432                 * 
  433                 * Presumably, at least some of these devices
  434                 * shipped with a broken ID_NUMCORE value.
  435                 */
  436                 cid->ncores = 7;
  437                 break;
  438         default:
  439                 return (EINVAL);
  440         }
  441 
  442         return (0);
  443 }
  444 
  445 static int
  446 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
  447     struct bhnd_core_info *core)
  448 {
  449         struct siba_erom        *sc;
  450         struct bhnd_core_match   imatch;
  451         int                      error;
  452 
  453         sc = (struct siba_erom *)erom;
  454 
  455         /* We can't determine a core's unit number during the initial scan. */
  456         imatch = *desc;
  457         imatch.m.match.core_unit = 0;
  458 
  459         /* Locate the first matching core */
  460         for (u_int i = 0; i < sc->io.ncores; i++) {
  461                 struct siba_core_id     sid;
  462                 struct bhnd_core_info   ci;
  463 
  464                 /* Read the core info */
  465                 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
  466                         return (error);
  467 
  468                 ci = sid.core_info;
  469 
  470                 /* Check for initial match */
  471                 if (!bhnd_core_matches(&ci, &imatch))
  472                         continue;
  473 
  474                 /* Re-scan preceding cores to determine the unit number. */
  475                 for (u_int j = 0; j < i; j++) {
  476                         error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
  477                         if (error)
  478                                 return (error);
  479 
  480                         /* Bump the unit number? */
  481                         if (sid.core_info.vendor == ci.vendor &&
  482                             sid.core_info.device == ci.device)
  483                                 ci.unit++;
  484                 }
  485 
  486                 /* Check for full match against now-valid unit number */
  487                 if (!bhnd_core_matches(&ci, desc))
  488                         continue;
  489 
  490                 /* Matching core found */
  491                 *core = ci;
  492                 return (0);
  493         }
  494 
  495         /* Not found */
  496         return (ENOENT);
  497 }
  498 
  499 static int
  500 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
  501     bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
  502     bhnd_addr_t *addr, bhnd_size_t *size)
  503 {
  504         struct siba_erom        *sc;
  505         struct bhnd_core_info    core;
  506         struct siba_core_id      sid;
  507         struct siba_admatch      admatch;
  508         uint32_t                 am;
  509         u_int                    am_offset;
  510         u_int                    addrspace, cfg;
  511 
  512         int                      error;
  513 
  514         sc = (struct siba_erom *)erom;
  515 
  516         /* Locate the requested core */
  517         if ((error = siba_erom_lookup_core(erom, desc, &core)))
  518                 return (error);
  519 
  520         /* Fetch full siba core ident */
  521         error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
  522         if (error)
  523                 return (error);
  524 
  525         /* Is port valid? */
  526         if (!siba_is_port_valid(&sid, type, port))
  527                 return (ENOENT);
  528 
  529         /* Is region valid? */
  530         if (region >= siba_port_region_count(&sid, type, port))
  531                 return (ENOENT);
  532 
  533         /* Is this a siba configuration region? If so, this is mapped to an
  534          * offset within the device0.0 port */
  535         error = siba_cfg_index(&sid, type, port, region, &cfg);
  536         if (!error) {
  537                 bhnd_addr_t     region_addr;
  538                 bhnd_addr_t     region_size;
  539                 bhnd_size_t     cfg_offset, cfg_size;
  540 
  541                 cfg_offset = SIBA_CFG_OFFSET(cfg);
  542                 cfg_size = SIBA_CFG_SIZE;
  543 
  544                 /* Fetch the device0.0 addr/size */
  545                 error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
  546                     0, 0, NULL, &region_addr, &region_size);
  547                 if (error)
  548                         return (error);
  549 
  550                 /* Verify that our offset fits within the region */
  551                 if (region_size < cfg_size) {
  552                         printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
  553                             bhnd_port_type_name(type), port, region, cfg_offset,
  554                             bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
  555 
  556                         return (ENXIO);
  557                 }
  558 
  559                 if (BHND_ADDR_MAX - region_addr < cfg_offset) {
  560                         printf("%s%u.%u offset %ju would overflow %s0.0 addr "
  561                             "%ju\n", bhnd_port_type_name(type), port, region,
  562                             cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
  563                             region_addr);
  564 
  565                         return (ENXIO);
  566                 }
  567 
  568                 if (info != NULL)
  569                         *info = core;
  570 
  571                 *addr = region_addr + cfg_offset;
  572                 *size = cfg_size;
  573                 return (0);
  574         }
  575 
  576         /* 
  577          * Otherwise, must be a device port.
  578          * 
  579          * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
  580          * bus drivers, we do not exclude the siba(4) configuration blocks from
  581          * the first device port.
  582          */
  583         error = siba_addrspace_index(&sid, type, port, region, &addrspace);
  584         if (error)
  585                 return (error);
  586 
  587         /* Determine the register offset */
  588         am_offset = siba_admatch_offset(addrspace);
  589         if (am_offset == 0) {
  590                 printf("addrspace %u is unsupported", addrspace);
  591                 return (ENODEV);
  592         }
  593 
  594         /* Read and parse the address match register */
  595         am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
  596 
  597         if ((error = siba_parse_admatch(am, &admatch))) {
  598                 printf("failed to decode address match register value 0x%x\n",
  599                     am);
  600                 return (error);
  601         }
  602 
  603         if (info != NULL)
  604                 *info = core;
  605 
  606         *addr = admatch.am_base;
  607         *size = admatch.am_size;
  608 
  609         return (0);
  610 }
  611 
  612 /* BHND_EROM_GET_CORE_TABLE() */
  613 static int
  614 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
  615     u_int *num_cores)
  616 {
  617         struct siba_erom        *sc;
  618         struct bhnd_core_info   *out;
  619         int                      error;
  620 
  621         sc = (struct siba_erom *)erom;
  622 
  623         /* Allocate our core array */
  624         out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT);
  625         if (out == NULL)
  626                 return (ENOMEM);
  627 
  628         *cores = out;
  629         *num_cores = sc->io.ncores;
  630 
  631         /* Enumerate all cores. */
  632         for (u_int i = 0; i < sc->io.ncores; i++) {
  633                 struct siba_core_id sid;
  634 
  635                 /* Read the core info */
  636                 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
  637                         return (error);
  638 
  639                 out[i] = sid.core_info;
  640 
  641                 /* Determine unit number */
  642                 for (u_int j = 0; j < i; j++) {
  643                         if (out[j].vendor == out[i].vendor &&
  644                             out[j].device == out[i].device)
  645                                 out[i].unit++;
  646                 }
  647         }
  648 
  649         return (0);
  650 }
  651 
  652 /* BHND_EROM_FREE_CORE_TABLE() */
  653 static void
  654 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
  655 {
  656         free(cores, M_BHND);
  657 }
  658 
  659 /* BHND_EROM_DUMP() */
  660 static int
  661 siba_erom_dump(bhnd_erom_t *erom)
  662 {
  663         struct siba_erom        *sc;
  664         int                      error;
  665 
  666         sc = (struct siba_erom *)erom;
  667 
  668         /* Enumerate all cores. */
  669         for (u_int i = 0; i < sc->io.ncores; i++) {
  670                 uint32_t idhigh, idlow;
  671                 uint32_t nraddr;
  672 
  673                 idhigh = siba_eio_read_4(&sc->io, i,
  674                     SB0_REG_ABS(SIBA_CFG0_IDHIGH));
  675                 idlow = siba_eio_read_4(&sc->io, i,
  676                     SB0_REG_ABS(SIBA_CFG0_IDLOW));
  677 
  678                 printf("siba core %u:\n", i);
  679                 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
  680                 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
  681                 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
  682                 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
  683 
  684                 /* Enumerate the address match registers */
  685                 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
  686                 printf("\tnraddr\t0x%04x\n", nraddr);
  687 
  688                 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
  689                         struct siba_admatch     admatch;
  690                         uint32_t                am;
  691                         u_int                   am_offset;
  692 
  693                         /* Determine the register offset */
  694                         am_offset = siba_admatch_offset(addrspace);
  695                         if (am_offset == 0) {
  696                                 printf("addrspace %zu unsupported",
  697                                     addrspace);
  698                                 break;
  699                         }
  700                         
  701                         /* Read and parse the address match register */
  702                         am = siba_eio_read_4(&sc->io, i, am_offset);
  703                         if ((error = siba_parse_admatch(am, &admatch))) {
  704                                 printf("failed to decode address match "
  705                                     "register value 0x%x\n", am);
  706                                 continue;
  707                         }
  708 
  709                         printf("\taddrspace %zu\n", addrspace);
  710                         printf("\t\taddr: 0x%08x\n", admatch.am_base);
  711                         printf("\t\tsize: 0x%08x\n", admatch.am_size);
  712                 }
  713         }
  714 
  715         return (0);
  716 }
  717 
  718 static kobj_method_t siba_erom_methods[] = {
  719         KOBJMETHOD(bhnd_erom_probe,             siba_erom_probe),
  720         KOBJMETHOD(bhnd_erom_init,              siba_erom_init),
  721         KOBJMETHOD(bhnd_erom_fini,              siba_erom_fini),
  722         KOBJMETHOD(bhnd_erom_get_core_table,    siba_erom_get_core_table),
  723         KOBJMETHOD(bhnd_erom_free_core_table,   siba_erom_free_core_table),
  724         KOBJMETHOD(bhnd_erom_lookup_core,       siba_erom_lookup_core),
  725         KOBJMETHOD(bhnd_erom_lookup_core_addr,  siba_erom_lookup_core_addr),
  726         KOBJMETHOD(bhnd_erom_dump,              siba_erom_dump),
  727 
  728         KOBJMETHOD_END
  729 };
  730 
  731 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));

Cache object: 1880d495bc750249890d789c73764642


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