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_subr.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/limits.h>
   41 #include <sys/systm.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/resource.h>
   45 
   46 #include <dev/bhnd/bhndvar.h>
   47 
   48 #include "sibareg.h"
   49 #include "sibavar.h"
   50 
   51 static int      siba_register_interrupts(device_t dev, device_t child,
   52                     struct siba_devinfo *dinfo);
   53 static int      siba_append_dinfo_region(struct siba_devinfo *dinfo,
   54                      uint8_t addridx, uint32_t base, uint32_t size,
   55                      uint32_t bus_reserved);
   56 
   57 /**
   58  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
   59  * code.
   60  * 
   61  * @param ocp_vendor An OCP vendor code.
   62  * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
   63  * BHND_MFGID_INVALID if the OCP vendor is unknown.
   64  */
   65 uint16_t
   66 siba_get_bhnd_mfgid(uint16_t ocp_vendor)
   67 {
   68         switch (ocp_vendor) {
   69         case OCP_VENDOR_BCM:
   70                 return (BHND_MFGID_BCM);
   71         default:
   72                 return (BHND_MFGID_INVALID);
   73         }
   74 }
   75 
   76 /**
   77  * Allocate and return a new empty device info structure.
   78  * 
   79  * @param bus The requesting bus device.
   80  * 
   81  * @retval NULL if allocation failed.
   82  */
   83 struct siba_devinfo *
   84 siba_alloc_dinfo(device_t bus)
   85 {
   86         struct siba_devinfo *dinfo;
   87 
   88         dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO);
   89         if (dinfo == NULL)
   90                 return NULL;
   91 
   92         for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
   93                 dinfo->cfg[i] = ((struct siba_cfg_block){
   94                         .cb_base = 0,
   95                         .cb_size = 0,
   96                         .cb_rid = -1,
   97                 });
   98                 dinfo->cfg_res[i] = NULL;
   99                 dinfo->cfg_rid[i] = -1;
  100         }
  101 
  102         resource_list_init(&dinfo->resources);
  103 
  104         dinfo->pmu_state = SIBA_PMU_NONE;
  105 
  106         dinfo->intr = (struct siba_intr) {
  107                 .mapped = false,
  108                 .rid = -1
  109         };
  110 
  111         return dinfo;
  112 }
  113 
  114 /**
  115  * Initialize a device info structure previously allocated via
  116  * siba_alloc_dinfo, copying the provided core id.
  117  * 
  118  * @param dev The requesting bus device.
  119  * @param child The siba child device.
  120  * @param dinfo The device info instance.
  121  * @param core Device core info.
  122  * 
  123  * @retval 0 success
  124  * @retval non-zero initialization failed.
  125  */
  126 int
  127 siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo,
  128     const struct siba_core_id *core_id)
  129 {
  130         int error;
  131 
  132         dinfo->core_id = *core_id;
  133 
  134         /* Register all address space mappings */
  135         for (uint8_t i = 0; i < core_id->num_admatch; i++) {
  136                 uint32_t bus_reserved;
  137 
  138                 /* If this is the device's core/enumeration addrespace,
  139                  * reserve the Sonics configuration register blocks for the
  140                  * use of our bus. */
  141                 bus_reserved = 0;
  142                 if (i == SIBA_CORE_ADDRSPACE)
  143                         bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE;
  144 
  145                 /* Append the region info */
  146                 error = siba_append_dinfo_region(dinfo, i,
  147                     core_id->admatch[i].am_base, core_id->admatch[i].am_size,
  148                     bus_reserved);
  149                 if (error)
  150                         return (error);
  151         }
  152 
  153         /* Register all interrupt(s) */
  154         if ((error = siba_register_interrupts(dev, child, dinfo)))
  155                 return (error);
  156 
  157         return (0);
  158 }
  159 
  160 /**
  161  * Register and map all interrupts for @p dinfo.
  162  *
  163  * @param dev The siba bus device.
  164  * @param child The siba child device.
  165  * @param dinfo The device info instance on which to register all interrupt
  166  * entries.
  167  */
  168 static int
  169 siba_register_interrupts(device_t dev, device_t child,
  170      struct siba_devinfo *dinfo)
  171 {
  172         int error;
  173 
  174         /* Is backplane interrupt distribution enabled for this core? */
  175         if (!dinfo->core_id.intr_en)
  176                 return (0);
  177 
  178         /* Have one interrupt */
  179         dinfo->intr.mapped = false;
  180         dinfo->intr.irq = 0;
  181         dinfo->intr.rid = -1;
  182 
  183         /* Map the interrupt */
  184         error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
  185             &dinfo->intr.irq);
  186         if (error) {
  187                 device_printf(dev, "failed mapping interrupt line for core %u: "
  188                     "%d\n", dinfo->core_id.core_info.core_idx, error);
  189                 return (error);
  190         }
  191         dinfo->intr.mapped = true;
  192 
  193         /* Update the resource list */
  194         dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
  195             dinfo->intr.irq, dinfo->intr.irq, 1);
  196 
  197         return (0);
  198 }
  199 
  200 /**
  201  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
  202  * number.
  203  * 
  204  * @param addrspace Address space index.
  205  */
  206 u_int
  207 siba_addrspace_device_port(u_int addrspace)
  208 {
  209         /* The first addrspace is always mapped to device0; the remainder
  210          * are mapped to device1 */
  211         if (addrspace == 0)
  212                 return (0);
  213         else
  214                 return (1);
  215 }
  216 
  217 /**
  218  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
  219  * region number.
  220  * 
  221  * @param addrspace Address space index.
  222  */
  223 u_int
  224 siba_addrspace_device_region(u_int addrspace)
  225 {
  226         /* The first addrspace is always mapped to device0.0; the remainder
  227          * are mapped to device1.0 + (n - 1) */
  228         if (addrspace == 0)
  229                 return (0);
  230         else
  231                 return (addrspace - 1);
  232 }
  233 
  234 /**
  235  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
  236  * number.
  237  * 
  238  * @param cfg Config block index.
  239  */
  240 u_int
  241 siba_cfg_agent_port(u_int cfg)
  242 {
  243         /* Always agent0 */
  244         return (0);
  245 }
  246 
  247 /**
  248  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
  249  * region number.
  250  * 
  251  * @param cfg Config block index.
  252  */
  253 u_int
  254 siba_cfg_agent_region(u_int cfg)
  255 {
  256         /* Always agent0.<idx> */
  257         return (cfg);
  258 }
  259 
  260 /**
  261  * Return the number of bhnd(4) ports to advertise for the given
  262  * @p core_id and @p port_type.
  263  * 
  264  * Refer to the siba_addrspace_index() and siba_cfg_index() functions for
  265  * information on siba's mapping of bhnd(4) port and region identifiers.
  266  * 
  267  * @param core_id The siba core info.
  268  * @param port_type The bhnd(4) port type.
  269  */
  270 u_int
  271 siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type)
  272 {
  273         switch (port_type) {
  274         case BHND_PORT_DEVICE:
  275                 /* 0, 1, or 2 ports */
  276                 return (min(core_id->num_admatch, 2));
  277 
  278         case BHND_PORT_AGENT:
  279                 /* One agent port maps all configuration blocks */
  280                 if (core_id->num_cfg_blocks > 0)
  281                         return (1);
  282 
  283                 /* Do not advertise an agent port if there are no configuration
  284                  * register blocks */
  285                 return (0);
  286 
  287         default:
  288                 return (0);
  289         }
  290 }
  291 
  292 /**
  293  * Return true if @p port of @p port_type is defined by @p core_id, false
  294  * otherwise.
  295  * 
  296  * @param core_id The siba core info.
  297  * @param port_type The bhnd(4) port type.
  298  * @param port The bhnd(4) port number.
  299  */
  300 bool
  301 siba_is_port_valid(struct siba_core_id *core_id, bhnd_port_type port_type,
  302     u_int port)
  303 {
  304         /* Verify the index against the port count */
  305         if (siba_port_count(core_id, port_type) <= port)
  306                 return (false);
  307 
  308         return (true);
  309 }
  310 
  311 /**
  312  * Return the number of bhnd(4) regions to advertise for @p core_id on the
  313  * @p port of @p port_type.
  314  * 
  315  * @param core_id The siba core info.
  316  * @param port_type The bhnd(4) port type.
  317  */
  318 u_int
  319 siba_port_region_count(struct siba_core_id *core_id, bhnd_port_type port_type,
  320     u_int port)
  321 {
  322         /* The port must exist */
  323         if (!siba_is_port_valid(core_id, port_type, port))
  324                 return (0);
  325 
  326         switch (port_type) {
  327         case BHND_PORT_DEVICE:
  328                 /* The first address space, if any, is mapped to device0.0 */
  329                 if (port == 0)
  330                         return (min(core_id->num_admatch, 1));
  331 
  332                 /* All remaining address spaces are mapped to device0.(n - 1) */
  333                 if (port == 1 && core_id->num_admatch >= 2)
  334                         return (core_id->num_admatch - 1);
  335 
  336                 break;
  337 
  338         case BHND_PORT_AGENT:
  339                 /* All config blocks are mapped to a single port */
  340                 if (port == 0)
  341                         return (core_id->num_cfg_blocks);
  342 
  343                 break;
  344 
  345         default:
  346                 break;
  347         }
  348 
  349         /* Validated above */
  350         panic("siba_is_port_valid() returned true for unknown %s.%u port",
  351             bhnd_port_type_name(port_type), port);
  352 
  353 }
  354 
  355 /**
  356  * Map a bhnd(4) type/port/region triplet to its associated config block index,
  357  * if any.
  358  * 
  359  * We map config registers to port/region identifiers as follows:
  360  * 
  361  *      [port].[region] [cfg register block]
  362  *      agent0.0        0
  363  *      agent0.1        1
  364  * 
  365  * @param port_type The bhnd(4) port type.
  366  * @param port The bhnd(4) port number.
  367  * @param region The bhnd(4) port region.
  368  * @param addridx On success, the corresponding addrspace index.
  369  * 
  370  * @retval 0 success
  371  * @retval ENOENT if the given type/port/region cannot be mapped to a
  372  * siba config register block.
  373  */
  374 int
  375 siba_cfg_index(struct siba_core_id *core_id, bhnd_port_type port_type,
  376     u_int port, u_int region, u_int *cfgidx)
  377 {
  378         /* Config blocks are mapped to agent ports */
  379         if (port_type != BHND_PORT_AGENT)
  380                 return (ENOENT);
  381 
  382         /* Port must be valid */
  383         if (!siba_is_port_valid(core_id, port_type, port))
  384                 return (ENOENT);
  385 
  386         if (region >= core_id->num_cfg_blocks)
  387                 return (ENOENT);
  388 
  389         if (region >= SIBA_MAX_CFG)
  390                 return (ENOENT);
  391 
  392         /* Found */
  393         *cfgidx = region;
  394         return (0);
  395 }
  396 
  397 /**
  398  * Map an bhnd(4) type/port/region triplet to its associated config block
  399  * entry, if any.
  400  *
  401  * The only supported port type is BHND_PORT_DEVICE.
  402  * 
  403  * @param dinfo The device info to search for a matching address space.
  404  * @param type The bhnd(4) port type.
  405  * @param port The bhnd(4) port number.
  406  * @param region The bhnd(4) port region.
  407  */
  408 struct siba_cfg_block *
  409 siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
  410     u_int region)
  411 {
  412         u_int   cfgidx;
  413         int     error;
  414 
  415         /* Map to addrspace index */
  416         error = siba_cfg_index(&dinfo->core_id, type, port, region, &cfgidx);
  417         if (error)
  418                 return (NULL);
  419 
  420         /* Found */
  421         return (&dinfo->cfg[cfgidx]);
  422 }
  423 
  424 /**
  425  * Map a bhnd(4) type/port/region triplet to its associated address space
  426  * index, if any.
  427  * 
  428  * For compatibility with bcma(4), we map address spaces to port/region
  429  * identifiers as follows:
  430  * 
  431  *      [port.region]   [admatch index]
  432  *      device0.0       0
  433  *      device1.0       1
  434  *      device1.1       2
  435  *      device1.2       3
  436  * 
  437  * @param core_id The siba core info.
  438  * @param port_type The bhnd(4) port type.
  439  * @param port The bhnd(4) port number.
  440  * @param region The bhnd(4) port region.
  441  * @param addridx On success, the corresponding addrspace index.
  442  * 
  443  * @retval 0 success
  444  * @retval ENOENT if the given type/port/region cannot be mapped to a
  445  * siba address space.
  446  */
  447 int
  448 siba_addrspace_index(struct siba_core_id *core_id, bhnd_port_type port_type,
  449     u_int port, u_int region, u_int *addridx)
  450 {
  451         u_int idx;
  452 
  453         /* Address spaces are always device ports */
  454         if (port_type != BHND_PORT_DEVICE)
  455                 return (ENOENT);
  456 
  457         /* Port must be valid */
  458         if (!siba_is_port_valid(core_id, port_type, port))
  459                 return (ENOENT);
  460 
  461         if (port == 0)
  462                 idx = region;
  463         else if (port == 1)
  464                 idx = region + 1;
  465         else
  466                 return (ENOENT);
  467 
  468         if (idx >= core_id->num_admatch)
  469                 return (ENOENT);
  470 
  471         /* Found */
  472         *addridx = idx;
  473         return (0);
  474 }
  475 
  476 /**
  477  * Map an bhnd(4) type/port/region triplet to its associated address space
  478  * entry, if any.
  479  *
  480  * The only supported port type is BHND_PORT_DEVICE.
  481  * 
  482  * @param dinfo The device info to search for a matching address space.
  483  * @param type The bhnd(4) port type.
  484  * @param port The bhnd(4) port number.
  485  * @param region The bhnd(4) port region.
  486  */
  487 struct siba_addrspace *
  488 siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
  489     u_int region)
  490 {
  491         u_int   addridx;
  492         int     error;
  493 
  494         /* Map to addrspace index */
  495         error = siba_addrspace_index(&dinfo->core_id, type, port, region,
  496             &addridx);
  497         if (error)
  498                 return (NULL);
  499 
  500         /* Found */
  501         if (addridx >= SIBA_MAX_ADDRSPACE)
  502                 return (NULL);
  503 
  504         return (&dinfo->addrspace[addridx]);
  505 }
  506 
  507 /**
  508  * Append an address space entry to @p dinfo.
  509  * 
  510  * @param dinfo The device info entry to update.
  511  * @param addridx The address space index.
  512  * @param base The mapping's base address.
  513  * @param size The mapping size.
  514  * @param bus_reserved Number of bytes to reserve in @p size for bus use
  515  * when registering the resource list entry. This is used to reserve bus
  516  * access to the core's SIBA_CFG* register blocks.
  517  * 
  518  * @retval 0 success
  519  * @retval non-zero An error occurred appending the entry.
  520  */
  521 static int
  522 siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
  523     uint32_t base, uint32_t size, uint32_t bus_reserved)
  524 {
  525         struct siba_addrspace   *sa;
  526         rman_res_t               r_size;
  527 
  528         /* Verify that base + size will not overflow */
  529         if (size > 0 && UINT32_MAX - (size - 1) < base)
  530                 return (ERANGE);
  531 
  532         /* Verify that size - bus_reserved will not underflow */
  533         if (size < bus_reserved)
  534                 return (ERANGE);
  535 
  536         /* Must not be 0-length */
  537         if (size == 0)
  538                 return (EINVAL);
  539 
  540         /* Must not exceed addrspace array size */
  541         if (addridx >= nitems(dinfo->addrspace))
  542                 return (EINVAL);
  543 
  544         /* Initialize new addrspace entry */
  545         sa = &dinfo->addrspace[addridx];
  546         sa->sa_base = base;
  547         sa->sa_size = size;
  548         sa->sa_bus_reserved = bus_reserved;
  549 
  550         /* Populate the resource list */
  551         r_size = size - bus_reserved;
  552         sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
  553             base, base + (r_size - 1), r_size);
  554 
  555         return (0);
  556 }
  557 
  558 /**
  559  * Deallocate the given device info structure and any associated resources.
  560  * 
  561  * @param dev The requesting bus device.
  562  * @param child The siba child device.
  563  * @param dinfo Device info associated with @p child to be deallocated.
  564  */
  565 void
  566 siba_free_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo)
  567 {
  568         resource_list_free(&dinfo->resources);
  569 
  570         /* Free all mapped configuration blocks */
  571         for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
  572                 if (dinfo->cfg_res[i] == NULL)
  573                         continue;
  574 
  575                 bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
  576                     dinfo->cfg_res[i]);
  577 
  578                 dinfo->cfg_res[i] = NULL;
  579                 dinfo->cfg_rid[i] = -1;
  580         }
  581 
  582         /* Unmap the core's interrupt */
  583         if (dinfo->core_id.intr_en && dinfo->intr.mapped) {
  584                 BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
  585                 dinfo->intr.mapped = false;
  586         }
  587 
  588         free(dinfo, M_BHND);
  589 }
  590 
  591 /**
  592  * Return the core-enumeration-relative offset for the @p addrspace
  593  * SIBA_R0_ADMATCH* register.
  594  * 
  595  * @param addrspace The address space index.
  596  * 
  597  * @retval non-zero success
  598  * @retval 0 the given @p addrspace index is not supported.
  599  */
  600 u_int
  601 siba_admatch_offset(uint8_t addrspace)
  602 {
  603         switch (addrspace) {
  604         case 0:
  605                 return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
  606         case 1:
  607                 return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
  608         case 2:
  609                 return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
  610         case 3:
  611                 return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
  612         default:
  613                 return (0);
  614         }
  615 }
  616 
  617 /**
  618  * Parse a SIBA_R0_ADMATCH* register.
  619  * 
  620  * @param addrspace The address space index.
  621  * @param am The address match register value to be parsed.
  622  * @param[out] admatch The parsed address match descriptor
  623  * 
  624  * @retval 0 success
  625  * @retval non-zero a parse error occurred.
  626  */
  627 int
  628 siba_parse_admatch(uint32_t am, struct siba_admatch *admatch)
  629 {
  630         u_int am_type;
  631 
  632         /* Extract the base address and size */
  633         am_type = SIBA_REG_GET(am, AM_TYPE);
  634         switch (am_type) {
  635         case 0:
  636                 /* Type 0 entries are always enabled, and do not support
  637                  * negative matching */
  638                 admatch->am_base = am & SIBA_AM_BASE0_MASK;
  639                 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
  640                 admatch->am_enabled = true;
  641                 admatch->am_negative = false;
  642                 break;
  643         case 1:
  644                 admatch->am_base = am & SIBA_AM_BASE1_MASK;
  645                 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
  646                 admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
  647                 admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
  648                 break;
  649         case 2:
  650                 admatch->am_base = am & SIBA_AM_BASE2_MASK;
  651                 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
  652                 admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
  653                 admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
  654                 break;
  655         default:
  656                 return (EINVAL);
  657         }
  658 
  659         return (0);
  660 }
  661 
  662 /**
  663  * Write @p value to @p dev's CFG0 target/initiator state register, performing
  664  * required read-back and waiting for completion.
  665  * 
  666  * @param dev The siba(4) child device.
  667  * @param reg The CFG0 state register to write (e.g. SIBA_CFG0_TMSTATELOW,
  668  * SIBA_CFG0_IMSTATE)
  669  * @param value The value to write to @p reg.
  670  * @param mask The mask of bits to be included from @p value.
  671  */
  672 void
  673 siba_write_target_state(device_t dev, struct siba_devinfo *dinfo,
  674     bus_size_t reg, uint32_t value, uint32_t mask)
  675 {
  676         struct bhnd_resource    *r;
  677         uint32_t                 rval;
  678 
  679         r = dinfo->cfg_res[0];
  680 
  681         KASSERT(r != NULL, ("%s missing CFG0 mapping",
  682             device_get_nameunit(dev)));
  683         KASSERT(reg <= SIBA_CFG_SIZE-4, ("%s invalid CFG0 register offset %#jx",
  684             device_get_nameunit(dev), (uintmax_t)reg));
  685 
  686         rval = bhnd_bus_read_4(r, reg);
  687         rval &= ~mask;
  688         rval |= (value & mask);
  689 
  690         bhnd_bus_write_4(r, reg, rval);
  691         bhnd_bus_read_4(r, reg); /* read-back */
  692         DELAY(1);
  693 }
  694 
  695 /**
  696  * Spin for up to @p usec waiting for @p dev's CFG0 target/initiator state
  697  * register value to be equal to @p value after applying @p mask bits to both
  698  * values.
  699  * 
  700  * @param dev The siba(4) child device to wait on.
  701  * @param dinfo The @p dev's device info
  702  * @param reg The state register to read (e.g. SIBA_CFG0_TMSTATEHIGH,
  703  * SIBA_CFG0_IMSTATE)
  704  * @param value The value against which @p reg will be compared.
  705  * @param mask The mask to be applied when comparing @p value with @p reg.
  706  * @param usec The maximum number of microseconds to wait for completion.
  707  * 
  708  * @retval 0 if SIBA_TMH_BUSY is cleared prior to the @p usec timeout.
  709  * @retval ENODEV if SIBA_CFG0 is not mapped by @p dinfo.
  710  * @retval ETIMEDOUT if a timeout occurs.
  711  */
  712 int
  713 siba_wait_target_state(device_t dev, struct siba_devinfo *dinfo, bus_size_t reg,
  714     uint32_t value, uint32_t mask, u_int usec)
  715 {
  716         struct bhnd_resource    *r;
  717         uint32_t                 rval;
  718 
  719         if ((r = dinfo->cfg_res[0]) == NULL)
  720                 return (ENODEV);
  721 
  722         value &= mask;
  723         for (int i = 0; i < usec; i += 10) {
  724                 rval = bhnd_bus_read_4(r, reg);
  725                 if ((rval & mask) == value)
  726                         return (0);
  727 
  728                 DELAY(10);
  729         }
  730 
  731         return (ETIMEDOUT);
  732 }

Cache object: 6f1c1bccc342c712b5ab6994c397f91f


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