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/bcma/bcma.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
    5  * Copyright (c) 2017 The FreeBSD Foundation
    6  * All rights reserved.
    7  *
    8  * Portions of this software were developed by Landon Fuller
    9  * under sponsorship from the FreeBSD Foundation.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer,
   16  *    without modification.
   17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   18  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   19  *    redistribution must be conditioned upon including a substantially
   20  *    similar Disclaimer requirement for further binary redistribution.
   21  *
   22  * NO WARRANTY
   23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   26  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   27  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   28  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   31  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   33  * THE POSSIBILITY OF SUCH DAMAGES.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/module.h>
   44 #include <sys/systm.h>
   45 
   46 #include <machine/bus.h>
   47 
   48 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
   49 
   50 #include "bcma_dmp.h"
   51 
   52 #include "bcma_eromreg.h"
   53 #include "bcma_eromvar.h"
   54 
   55 #include "bcmavar.h"
   56 
   57 /* RID used when allocating EROM table */
   58 #define BCMA_EROM_RID   0
   59 
   60 static bhnd_erom_class_t *
   61 bcma_get_erom_class(driver_t *driver)
   62 {
   63         return (&bcma_erom_parser);
   64 }
   65 
   66 int
   67 bcma_probe(device_t dev)
   68 {
   69         device_set_desc(dev, "BCMA BHND bus");
   70         return (BUS_PROBE_DEFAULT);
   71 }
   72 
   73 /**
   74  * Default bcma(4) bus driver implementation of DEVICE_ATTACH().
   75  * 
   76  * This implementation initializes internal bcma(4) state and performs
   77  * bus enumeration, and must be called by subclassing drivers in
   78  * DEVICE_ATTACH() before any other bus methods.
   79  */
   80 int
   81 bcma_attach(device_t dev)
   82 {
   83         int error;
   84 
   85         /* Enumerate children */
   86         if ((error = bcma_add_children(dev))) {
   87                 device_delete_children(dev);
   88                 return (error);
   89         }
   90 
   91         return (0);
   92 }
   93 
   94 int
   95 bcma_detach(device_t dev)
   96 {
   97         return (bhnd_generic_detach(dev));
   98 }
   99 
  100 static device_t
  101 bcma_add_child(device_t dev, u_int order, const char *name, int unit)
  102 {
  103         struct bcma_devinfo     *dinfo;
  104         device_t                 child;
  105 
  106         child = device_add_child_ordered(dev, order, name, unit);
  107         if (child == NULL)
  108                 return (NULL);
  109 
  110         if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) {
  111                 device_delete_child(dev, child);
  112                 return (NULL);
  113         }
  114 
  115         device_set_ivars(child, dinfo);
  116 
  117         return (child);
  118 }
  119 
  120 static void
  121 bcma_child_deleted(device_t dev, device_t child)
  122 {
  123         struct bcma_devinfo     *dinfo;
  124 
  125         /* Call required bhnd(4) implementation */
  126         bhnd_generic_child_deleted(dev, child);
  127 
  128         /* Free bcma device info */
  129         if ((dinfo = device_get_ivars(child)) != NULL)
  130                 bcma_free_dinfo(dev, child, dinfo);
  131 
  132         device_set_ivars(child, NULL);
  133 }
  134 
  135 static int
  136 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  137 {
  138         const struct bcma_devinfo *dinfo;
  139         const struct bhnd_core_info *ci;
  140 
  141         dinfo = device_get_ivars(child);
  142         ci = &dinfo->corecfg->core_info;
  143 
  144         switch (index) {
  145         case BHND_IVAR_VENDOR:
  146                 *result = ci->vendor;
  147                 return (0);
  148         case BHND_IVAR_DEVICE:
  149                 *result = ci->device;
  150                 return (0);
  151         case BHND_IVAR_HWREV:
  152                 *result = ci->hwrev;
  153                 return (0);
  154         case BHND_IVAR_DEVICE_CLASS:
  155                 *result = bhnd_core_class(ci);
  156                 return (0);
  157         case BHND_IVAR_VENDOR_NAME:
  158                 *result = (uintptr_t) bhnd_vendor_name(ci->vendor);
  159                 return (0);
  160         case BHND_IVAR_DEVICE_NAME:
  161                 *result = (uintptr_t) bhnd_core_name(ci);
  162                 return (0);
  163         case BHND_IVAR_CORE_INDEX:
  164                 *result = ci->core_idx;
  165                 return (0);
  166         case BHND_IVAR_CORE_UNIT:
  167                 *result = ci->unit;
  168                 return (0);
  169         case BHND_IVAR_PMU_INFO:
  170                 *result = (uintptr_t) dinfo->pmu_info;
  171                 return (0);
  172         default:
  173                 return (ENOENT);
  174         }
  175 }
  176 
  177 static int
  178 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
  179 {
  180         struct bcma_devinfo *dinfo;
  181 
  182         dinfo = device_get_ivars(child);
  183 
  184         switch (index) {
  185         case BHND_IVAR_VENDOR:
  186         case BHND_IVAR_DEVICE:
  187         case BHND_IVAR_HWREV:
  188         case BHND_IVAR_DEVICE_CLASS:
  189         case BHND_IVAR_VENDOR_NAME:
  190         case BHND_IVAR_DEVICE_NAME:
  191         case BHND_IVAR_CORE_INDEX:
  192         case BHND_IVAR_CORE_UNIT:
  193                 return (EINVAL);
  194         case BHND_IVAR_PMU_INFO:
  195                 dinfo->pmu_info = (void *)value;
  196                 return (0);
  197         default:
  198                 return (ENOENT);
  199         }
  200 }
  201 
  202 static struct resource_list *
  203 bcma_get_resource_list(device_t dev, device_t child)
  204 {
  205         struct bcma_devinfo *dinfo = device_get_ivars(child);
  206         return (&dinfo->resources);
  207 }
  208 
  209 static int
  210 bcma_read_iost(device_t dev, device_t child, uint16_t *iost)
  211 {
  212         uint32_t        value;
  213         int             error;
  214 
  215         if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4)))
  216                 return (error);
  217 
  218         /* Return only the bottom 16 bits */
  219         *iost = (value & BCMA_DMP_IOST_MASK);
  220         return (0);
  221 }
  222 
  223 static int
  224 bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
  225 {
  226         uint32_t        value;
  227         int             error;
  228 
  229         if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4)))
  230                 return (error);
  231 
  232         /* Return only the bottom 16 bits */
  233         *ioctl = (value & BCMA_DMP_IOCTRL_MASK);
  234         return (0);
  235 }
  236 
  237 static int
  238 bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
  239 {
  240         struct bcma_devinfo     *dinfo;
  241         struct bhnd_resource    *r;
  242         uint32_t                 ioctl;
  243 
  244         if (device_get_parent(child) != dev)
  245                 return (EINVAL);
  246 
  247         dinfo = device_get_ivars(child);
  248         if ((r = dinfo->res_agent) == NULL)
  249                 return (ENODEV);
  250 
  251         /* Write new value */
  252         ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
  253         ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask);
  254         ioctl |= (value & mask);
  255 
  256         bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl);
  257 
  258         /* Perform read-back and wait for completion */
  259         bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
  260         DELAY(10);
  261 
  262         return (0);
  263 }
  264 
  265 static bool
  266 bcma_is_hw_suspended(device_t dev, device_t child)
  267 {
  268         uint32_t        rst;
  269         uint16_t        ioctl;
  270         int             error;
  271 
  272         /* Is core held in RESET? */
  273         error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4);
  274         if (error) {
  275                 device_printf(child, "error reading HW reset state: %d\n",
  276                     error);
  277                 return (true);
  278         }
  279 
  280         if (rst & BCMA_DMP_RC_RESET)
  281                 return (true);
  282 
  283         /* Is core clocked? */
  284         error = bhnd_read_ioctl(child, &ioctl);
  285         if (error) {
  286                 device_printf(child, "error reading HW ioctl register: %d\n",
  287                     error);
  288                 return (true);
  289         }
  290 
  291         if (!(ioctl & BHND_IOCTL_CLK_EN))
  292                 return (true);
  293 
  294         return (false);
  295 }
  296 
  297 static int
  298 bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl,
  299     uint16_t reset_ioctl)
  300 {
  301         struct bcma_devinfo     *dinfo;
  302         struct bhnd_resource    *r;
  303         uint16_t                 clkflags;
  304         int                      error;
  305 
  306         if (device_get_parent(child) != dev)
  307                 return (EINVAL);
  308 
  309         dinfo = device_get_ivars(child);
  310 
  311         /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
  312         clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
  313         if (ioctl & clkflags)
  314                 return (EINVAL);
  315 
  316         /* Can't suspend the core without access to the agent registers */
  317         if ((r = dinfo->res_agent) == NULL)
  318                 return (ENODEV);
  319 
  320         /* Place core into known RESET state */
  321         if ((error = bhnd_suspend_hw(child, reset_ioctl)))
  322                 return (error);
  323 
  324         /*
  325          * Leaving the core in reset:
  326          * - Set the caller's IOCTL flags
  327          * - Enable clocks
  328          * - Force clock distribution to ensure propagation throughout the
  329          *   core.
  330          */
  331         if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX)))
  332                 return (error);
  333 
  334         /* Bring the core out of reset */
  335         if ((error = bcma_dmp_write_reset(child, dinfo, 0x0)))
  336                 return (error);
  337 
  338         /* Disable forced clock gating (leaving clock enabled) */
  339         error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE);
  340         if (error)
  341                 return (error);
  342 
  343         return (0);
  344 }
  345 
  346 static int
  347 bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl)
  348 {
  349         struct bcma_devinfo     *dinfo;
  350         struct bhnd_resource    *r;
  351         uint16_t                 clkflags;
  352         int                      error;
  353 
  354         if (device_get_parent(child) != dev)
  355                 return (EINVAL);
  356 
  357         dinfo = device_get_ivars(child);
  358 
  359         /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
  360         clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
  361         if (ioctl & clkflags)
  362                 return (EINVAL);
  363 
  364         /* Can't suspend the core without access to the agent registers */
  365         if ((r = dinfo->res_agent) == NULL)
  366                 return (ENODEV);
  367 
  368         /* Wait for any pending reset operations to clear */
  369         if ((error = bcma_dmp_wait_reset(child, dinfo)))
  370                 return (error);
  371 
  372         /* Put core into reset (if not already in reset) */
  373         if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET)))
  374                 return (error);
  375 
  376         /* Write core flags (and clear CLK_EN/CLK_FORCE) */
  377         if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags)))
  378                 return (error);
  379 
  380         return (0);
  381 }
  382 
  383 static int
  384 bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
  385     u_int width)
  386 {
  387         struct bcma_devinfo     *dinfo;
  388         struct bhnd_resource    *r;
  389 
  390         /* Must be a directly attached child core */
  391         if (device_get_parent(child) != dev)
  392                 return (EINVAL);
  393 
  394         /* Fetch the agent registers */
  395         dinfo = device_get_ivars(child);
  396         if ((r = dinfo->res_agent) == NULL)
  397                 return (ENODEV);
  398 
  399         /* Verify bounds */
  400         if (offset > rman_get_size(r->res))
  401                 return (EFAULT);
  402 
  403         if (rman_get_size(r->res) - offset < width)
  404                 return (EFAULT);
  405 
  406         switch (width) {
  407         case 1:
  408                 *((uint8_t *)value) = bhnd_bus_read_1(r, offset);
  409                 return (0);
  410         case 2:
  411                 *((uint16_t *)value) = bhnd_bus_read_2(r, offset);
  412                 return (0);
  413         case 4:
  414                 *((uint32_t *)value) = bhnd_bus_read_4(r, offset);
  415                 return (0);
  416         default:
  417                 return (EINVAL);
  418         }
  419 }
  420 
  421 static int
  422 bcma_write_config(device_t dev, device_t child, bus_size_t offset,
  423     const void *value, u_int width)
  424 {
  425         struct bcma_devinfo     *dinfo;
  426         struct bhnd_resource    *r;
  427 
  428         /* Must be a directly attached child core */
  429         if (device_get_parent(child) != dev)
  430                 return (EINVAL);
  431 
  432         /* Fetch the agent registers */
  433         dinfo = device_get_ivars(child);
  434         if ((r = dinfo->res_agent) == NULL)
  435                 return (ENODEV);
  436 
  437         /* Verify bounds */
  438         if (offset > rman_get_size(r->res))
  439                 return (EFAULT);
  440 
  441         if (rman_get_size(r->res) - offset < width)
  442                 return (EFAULT);
  443 
  444         switch (width) {
  445         case 1:
  446                 bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
  447                 return (0);
  448         case 2:
  449                 bhnd_bus_write_2(r, offset, *(const uint16_t *)value);
  450                 return (0);
  451         case 4:
  452                 bhnd_bus_write_4(r, offset, *(const uint32_t *)value);
  453                 return (0);
  454         default:
  455                 return (EINVAL);
  456         }
  457 }
  458 
  459 static u_int
  460 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
  461 {
  462         struct bcma_devinfo *dinfo;
  463 
  464         /* delegate non-bus-attached devices to our parent */
  465         if (device_get_parent(child) != dev)
  466                 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
  467                     type));
  468 
  469         dinfo = device_get_ivars(child);
  470         switch (type) {
  471         case BHND_PORT_DEVICE:
  472                 return (dinfo->corecfg->num_dev_ports);
  473         case BHND_PORT_BRIDGE:
  474                 return (dinfo->corecfg->num_bridge_ports);
  475         case BHND_PORT_AGENT:
  476                 return (dinfo->corecfg->num_wrapper_ports);
  477         default:
  478                 device_printf(dev, "%s: unknown type (%d)\n",
  479                     __func__,
  480                     type);
  481                 return (0);
  482         }
  483 }
  484 
  485 static u_int
  486 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
  487     u_int port_num)
  488 {
  489         struct bcma_devinfo     *dinfo;
  490         struct bcma_sport_list  *ports;
  491         struct bcma_sport       *port;
  492 
  493         /* delegate non-bus-attached devices to our parent */
  494         if (device_get_parent(child) != dev)
  495                 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
  496                     type, port_num));
  497 
  498         dinfo = device_get_ivars(child);
  499         ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
  500 
  501         STAILQ_FOREACH(port, ports, sp_link) {
  502                 if (port->sp_num == port_num)
  503                         return (port->sp_num_maps);
  504         }
  505 
  506         /* not found */
  507         return (0);
  508 }
  509 
  510 static int
  511 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
  512     u_int port_num, u_int region_num)
  513 {
  514         struct bcma_devinfo     *dinfo;
  515         struct bcma_map         *map;
  516         struct bcma_sport_list  *ports;
  517         struct bcma_sport       *port;
  518 
  519         dinfo = device_get_ivars(child);
  520         ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
  521 
  522         STAILQ_FOREACH(port, ports, sp_link) {
  523                 if (port->sp_num != port_num)
  524                         continue;
  525 
  526                 STAILQ_FOREACH(map, &port->sp_maps, m_link)
  527                         if (map->m_region_num == region_num)
  528                                 return map->m_rid;
  529         }
  530 
  531         return -1;
  532 }
  533 
  534 static int
  535 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
  536     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
  537 {
  538         struct bcma_devinfo     *dinfo;
  539         struct bcma_map         *map;
  540         struct bcma_sport_list  *ports;
  541         struct bcma_sport       *port;
  542 
  543         dinfo = device_get_ivars(child);
  544 
  545         /* Ports are always memory mapped */
  546         if (type != SYS_RES_MEMORY)
  547                 return (EINVAL);
  548 
  549         /* Starting with the most likely device list, search all three port
  550          * lists */
  551         bhnd_port_type types[] = {
  552             BHND_PORT_DEVICE, 
  553             BHND_PORT_AGENT,
  554             BHND_PORT_BRIDGE
  555         };
  556 
  557         for (int i = 0; i < nitems(types); i++) {
  558                 ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
  559 
  560                 STAILQ_FOREACH(port, ports, sp_link) {
  561                         STAILQ_FOREACH(map, &port->sp_maps, m_link) {
  562                                 if (map->m_rid != rid)
  563                                         continue;
  564 
  565                                 *port_type = port->sp_type;
  566                                 *port_num = port->sp_num;
  567                                 *region_num = map->m_region_num;
  568                                 return (0);
  569                         }
  570                 }
  571         }
  572 
  573         return (ENOENT);
  574 }
  575 
  576 static int
  577 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
  578     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
  579 {
  580         struct bcma_devinfo     *dinfo;
  581         struct bcma_map         *map;
  582         struct bcma_sport_list  *ports;
  583         struct bcma_sport       *port;
  584 
  585         dinfo = device_get_ivars(child);
  586         ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
  587 
  588         /* Search the port list */
  589         STAILQ_FOREACH(port, ports, sp_link) {
  590                 if (port->sp_num != port_num)
  591                         continue;
  592 
  593                 STAILQ_FOREACH(map, &port->sp_maps, m_link) {
  594                         if (map->m_region_num != region_num)
  595                                 continue;
  596 
  597                         /* Found! */
  598                         *addr = map->m_base;
  599                         *size = map->m_size;
  600                         return (0);
  601                 }
  602         }
  603 
  604         return (ENOENT);
  605 }
  606 
  607 /**
  608  * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
  609  */
  610 u_int
  611 bcma_get_intr_count(device_t dev, device_t child)
  612 {
  613         struct bcma_devinfo *dinfo;
  614 
  615         /* delegate non-bus-attached devices to our parent */
  616         if (device_get_parent(child) != dev)
  617                 return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
  618 
  619         dinfo = device_get_ivars(child);
  620         return (dinfo->num_intrs);
  621 }
  622 
  623 /**
  624  * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
  625  */
  626 int
  627 bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
  628 {
  629         struct bcma_devinfo     *dinfo;
  630         struct bcma_intr        *desc;
  631 
  632         /* delegate non-bus-attached devices to our parent */
  633         if (device_get_parent(child) != dev) {
  634                 return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
  635                     intr, ivec));
  636         }
  637 
  638         dinfo = device_get_ivars(child);
  639 
  640         STAILQ_FOREACH(desc, &dinfo->intrs, i_link) {
  641                 if (desc->i_sel == intr) {
  642                         *ivec = desc->i_busline;
  643                         return (0);
  644                 }
  645         }
  646 
  647         /* Not found */
  648         return (ENXIO);
  649 }
  650 
  651 /**
  652  * Scan the device enumeration ROM table, adding all valid discovered cores to
  653  * the bus.
  654  * 
  655  * @param bus The bcma bus.
  656  */
  657 int
  658 bcma_add_children(device_t bus)
  659 {
  660         bhnd_erom_t                     *erom;
  661         struct bcma_erom                *bcma_erom;
  662         struct bhnd_erom_io             *eio;
  663         const struct bhnd_chipid        *cid;
  664         struct bcma_corecfg             *corecfg;
  665         struct bcma_devinfo             *dinfo;
  666         device_t                         child;
  667         int                              error;
  668 
  669         cid = BHND_BUS_GET_CHIPID(bus, bus);
  670         corecfg = NULL;
  671 
  672         /* Allocate our EROM parser */
  673         eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID);
  674         erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio);
  675         if (erom == NULL) {
  676                 bhnd_erom_io_fini(eio);
  677                 return (ENODEV);
  678         }
  679 
  680         /* Add all cores. */
  681         bcma_erom = (struct bcma_erom *)erom;
  682         while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
  683                 /* Add the child device */
  684                 child = BUS_ADD_CHILD(bus, 0, NULL, -1);
  685                 if (child == NULL) {
  686                         error = ENXIO;
  687                         goto cleanup;
  688                 }
  689 
  690                 /* Initialize device ivars */
  691                 dinfo = device_get_ivars(child);
  692                 if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg)))
  693                         goto cleanup;
  694 
  695                 /* The dinfo instance now owns the corecfg value */
  696                 corecfg = NULL;
  697 
  698                 /* If pins are floating or the hardware is otherwise
  699                  * unpopulated, the device shouldn't be used. */
  700                 if (bhnd_is_hw_disabled(child))
  701                         device_disable(child);
  702 
  703                 /* Issue bus callback for fully initialized child. */
  704                 BHND_BUS_CHILD_ADDED(bus, child);
  705         }
  706 
  707         /* EOF while parsing cores is expected */
  708         if (error == ENOENT)
  709                 error = 0;
  710 
  711 cleanup:
  712         bhnd_erom_free(erom);
  713 
  714         if (corecfg != NULL)
  715                 bcma_free_corecfg(corecfg);
  716 
  717         if (error)
  718                 device_delete_children(bus);
  719 
  720         return (error);
  721 }
  722 
  723 static device_method_t bcma_methods[] = {
  724         /* Device interface */
  725         DEVMETHOD(device_probe,                 bcma_probe),
  726         DEVMETHOD(device_attach,                bcma_attach),
  727         DEVMETHOD(device_detach,                bcma_detach),
  728 
  729         /* Bus interface */
  730         DEVMETHOD(bus_add_child,                bcma_add_child),
  731         DEVMETHOD(bus_child_deleted,            bcma_child_deleted),
  732         DEVMETHOD(bus_read_ivar,                bcma_read_ivar),
  733         DEVMETHOD(bus_write_ivar,               bcma_write_ivar),
  734         DEVMETHOD(bus_get_resource_list,        bcma_get_resource_list),
  735 
  736         /* BHND interface */
  737         DEVMETHOD(bhnd_bus_get_erom_class,      bcma_get_erom_class),
  738         DEVMETHOD(bhnd_bus_read_ioctl,          bcma_read_ioctl),
  739         DEVMETHOD(bhnd_bus_write_ioctl,         bcma_write_ioctl),
  740         DEVMETHOD(bhnd_bus_read_iost,           bcma_read_iost),
  741         DEVMETHOD(bhnd_bus_is_hw_suspended,     bcma_is_hw_suspended),
  742         DEVMETHOD(bhnd_bus_reset_hw,            bcma_reset_hw),
  743         DEVMETHOD(bhnd_bus_suspend_hw,          bcma_suspend_hw),
  744         DEVMETHOD(bhnd_bus_read_config,         bcma_read_config),
  745         DEVMETHOD(bhnd_bus_write_config,        bcma_write_config),
  746         DEVMETHOD(bhnd_bus_get_port_count,      bcma_get_port_count),
  747         DEVMETHOD(bhnd_bus_get_region_count,    bcma_get_region_count),
  748         DEVMETHOD(bhnd_bus_get_port_rid,        bcma_get_port_rid),
  749         DEVMETHOD(bhnd_bus_decode_port_rid,     bcma_decode_port_rid),
  750         DEVMETHOD(bhnd_bus_get_region_addr,     bcma_get_region_addr),
  751         DEVMETHOD(bhnd_bus_get_intr_count,      bcma_get_intr_count),
  752         DEVMETHOD(bhnd_bus_get_intr_ivec,       bcma_get_intr_ivec),
  753 
  754         DEVMETHOD_END
  755 };
  756 
  757 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
  758 MODULE_VERSION(bcma, 1);
  759 MODULE_DEPEND(bcma, bhnd, 1, 1, 1);

Cache object: 9c225a44bb5c47375c165edfa5c4b466


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