Author: landonf
Date: Sat Sep  3 23:57:17 2016
New Revision: 305366
URL: https://svnweb.freebsd.org/changeset/base/305366

Log:
  Implement a generic bhnd(4) device enumeration table API.
  
  This defines a new bhnd_erom_if API, providing a common interface to device
  enumeration on siba(4) and bcma(4) devices, for use both in the bhndb bridge
  and SoC early boot contexts, and migrates mips/broadcom over to the new API.
  
  This also replaces the previous adhoc device enumeration support implemented
  for mips/broadcom.
  
  Migration of bhndb to the new API will be implemented in a follow-up commit.
  
  
  - Defined new bhnd_erom_if interface for bhnd(4) device enumeration, along
    with bcma(4) and siba(4)-specific implementations.
  - Fixed a minor bug in bhndb that logged an error when we attempted to map the
    full siba(4) bus space (18000000-17FFFFFF) in the siba EROM parser.
  - Reverted use of the resource's start address as the ChipCommon enum_addr in
    bhnd_read_chipid(). When called from bhndb, this address is found within the
    host address space, resulting in an invalid bridged enum_addr.
  - Added support for falling back on standard bus_activate_resource() in
    bhnd_bus_generic_activate_resource(), enabling allocation of the bhnd_erom's
    bhnd_resource directly from a nexus-attached bhnd(4) device.
  - Removed BHND_BUS_GET_CORE_TABLE(); it has been replaced by the erom API.
  - Added support for statically initializing bhnd_erom instances, for use prior
    to malloc availability. The statically allocated buffer size is verified 
both
    at runtime, and via a compile-time assertion (see BHND_EROM_STATIC_BYTES).
  - bhnd_erom classes are registered within a module via a linker set, allowing
    mips/broadcom to probe available EROM parser instances without creating a
    strong reference to bcma/siba-specific symbols.
  - Migrated mips/broadcom to bhnd_erom_if, replacing the previous MIPS-specific
    device enumeration implementation.
  
  Approved by:  adrian (mentor)
  Differential Revision:        https://reviews.freebsd.org/D7748

Added:
  head/sys/dev/bhnd/bhnd_erom.c   (contents, props changed)
  head/sys/dev/bhnd/bhnd_erom.h   (contents, props changed)
  head/sys/dev/bhnd/bhnd_erom_if.m   (contents, props changed)
  head/sys/dev/bhnd/bhnd_erom_types.h   (contents, props changed)
  head/sys/dev/bhnd/siba/siba_erom.c   (contents, props changed)
Deleted:
  head/sys/mips/broadcom/bcm_bcma.c
  head/sys/mips/broadcom/bcm_siba.c
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/bcma/bcma.c
  head/sys/dev/bhnd/bcma/bcma.h
  head/sys/dev/bhnd/bcma/bcma_bhndb.c
  head/sys/dev/bhnd/bcma/bcma_erom.c
  head/sys/dev/bhnd/bcma/bcma_eromvar.h
  head/sys/dev/bhnd/bcma/bcma_nexus.c
  head/sys/dev/bhnd/bcma/bcmavar.h
  head/sys/dev/bhnd/bhnd.h
  head/sys/dev/bhnd/bhnd_bus_if.m
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/bhndb/bhndb.c
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba.h
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibareg.h
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/mips/broadcom/bcm_machdep.c
  head/sys/mips/broadcom/bcm_machdep.h
  head/sys/mips/broadcom/bcm_pmu.c
  head/sys/mips/broadcom/files.broadcom
  head/sys/modules/bhnd/Makefile
  head/sys/modules/bhnd/bcma/Makefile
  head/sys/modules/bhnd/bcma_bhndb/Makefile
  head/sys/modules/bhnd/siba/Makefile
  head/sys/modules/bhnd/siba_bhndb/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Sat Sep  3 23:04:56 2016        (r305365)
+++ head/sys/conf/files Sat Sep  3 23:57:17 2016        (r305366)
@@ -1140,6 +1140,8 @@ dev/bce/if_bce.c                  optional bce
 dev/bfe/if_bfe.c                       optional bfe
 dev/bge/if_bge.c                       optional bge
 dev/bhnd/bhnd.c                                optional bhnd
+dev/bhnd/bhnd_erom.c                   optional bhnd
+dev/bhnd/bhnd_erom_if.m                        optional bhnd
 dev/bhnd/bhnd_nexus.c                  optional bhnd siba_nexus | \
                                                 bhnd bcma_nexus
 dev/bhnd/bhnd_subr.c                   optional bhnd
@@ -1188,6 +1190,7 @@ dev/bhnd/nvram/bhnd_sprom.c               optional bh
 dev/bhnd/nvram/bhnd_sprom_parser.c     optional bhnd
 dev/bhnd/siba/siba.c                   optional siba bhnd
 dev/bhnd/siba/siba_bhndb.c             optional siba bhnd bhndb
+dev/bhnd/siba/siba_erom.c              optional siba bhnd
 dev/bhnd/siba/siba_nexus.c             optional siba_nexus siba bhnd
 dev/bhnd/siba/siba_subr.c              optional siba bhnd
 #

Modified: head/sys/dev/bhnd/bcma/bcma.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.c       Sat Sep  3 23:04:56 2016        
(r305365)
+++ head/sys/dev/bhnd/bcma/bcma.c       Sat Sep  3 23:57:17 2016        
(r305366)
@@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
 #include "bcma_eromvar.h"
 #include <dev/bhnd/bhnd_core.h>
 
+/* RID used when allocating EROM table */
+#define        BCMA_EROM_RID   0
+
 int
 bcma_probe(device_t dev)
 {
@@ -492,76 +495,35 @@ bcma_free_bhnd_dinfo(device_t dev, struc
        bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo);
 }
 
-
-static int
-bcma_get_core_table(device_t dev, device_t child, struct bhnd_core_info 
**cores,
-    u_int *num_cores)
-{
-       struct bcma_softc               *sc;
-       struct bcma_erom                 erom;
-       const struct bhnd_chipid        *cid;
-       struct resource                 *r;
-       int                              error;
-       int                              rid;
-
-       sc = device_get_softc(dev);
-
-       /* Map the EROM table. */
-       cid = BHND_BUS_GET_CHIPID(dev, dev);
-       rid = 0;
-       r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
-           cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
-           RF_ACTIVE);
-       if (r == NULL) {
-               device_printf(dev, "failed to allocate EROM resource\n");
-               return (ENXIO);
-       }
-
-       /* Enumerate all declared cores */
-       if ((error = bcma_erom_open(&erom, r, BCMA_EROM_TABLE_START)))
-               goto cleanup;
-
-       error = bcma_erom_get_core_info(&erom, cores, num_cores);
-
-cleanup:
-       bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
-       return (error);
-}
-
 /**
- * Scan a device enumeration ROM table, adding all valid discovered cores to
+ * Scan the device enumeration ROM table, adding all valid discovered cores to
  * the bus.
  * 
  * @param bus The bcma bus.
- * @param erom_res An active resource mapping the EROM core.
- * @param erom_offset Base offset of the EROM core's register mapping.
  */
 int
-bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t 
erom_offset)
+bcma_add_children(device_t bus)
 {
-       struct bcma_erom         erom;
-       struct bcma_corecfg     *corecfg;
-       struct bcma_devinfo     *dinfo;
-       device_t                 child;
-       int                      error;
+       bhnd_erom_t                     *erom;
+       struct bcma_erom                *bcma_erom;
+       const struct bhnd_chipid        *cid;
+       struct bcma_corecfg             *corecfg;
+       struct bcma_devinfo             *dinfo;
+       device_t                         child;
+       int                              error;
 
+       cid = BHND_BUS_GET_CHIPID(bus, bus);
        corecfg = NULL;
 
-       /* Initialize our reader */
-       error = bcma_erom_open(&erom, erom_res, erom_offset);
-       if (error)
-               return (error);
+       /* Allocate our EROM parser */
+       erom = bhnd_erom_alloc(&bcma_erom_parser, bus, BCMA_EROM_RID,
+           cid->enum_addr);
+       if (erom == NULL)
+               return (ENODEV);
 
        /* Add all cores. */
-       while (!error) {
-               /* Parse next core */
-               error = bcma_erom_parse_corecfg(&erom, &corecfg);
-               if (error && error == ENOENT) {
-                       return (0);
-               } else if (error) {
-                       goto failed;
-               }
-
+       bcma_erom = (struct bcma_erom *)erom;
+       while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
                /* Add the child device */
                child = BUS_ADD_CHILD(bus, 0, NULL, -1);
                if (child == NULL) {
@@ -588,9 +550,11 @@ bcma_add_children(device_t bus, struct r
 
        /* Hit EOF parsing cores? */
        if (error == ENOENT)
-               return (0);
+               error = 0;
        
 failed:
+       bhnd_erom_free(erom);
+
        if (corecfg != NULL)
                bcma_free_corecfg(corecfg);
 
@@ -613,7 +577,6 @@ static device_method_t bcma_methods[] = 
        DEVMETHOD(bhnd_bus_find_hostb_device,   bcma_find_hostb_device),
        DEVMETHOD(bhnd_bus_alloc_devinfo,       bcma_alloc_bhnd_dinfo),
        DEVMETHOD(bhnd_bus_free_devinfo,        bcma_free_bhnd_dinfo),
-       DEVMETHOD(bhnd_bus_get_core_table,      bcma_get_core_table),
        DEVMETHOD(bhnd_bus_reset_core,          bcma_reset_core),
        DEVMETHOD(bhnd_bus_suspend_core,        bcma_suspend_core),
        DEVMETHOD(bhnd_bus_read_config,         bcma_read_config),

Modified: head/sys/dev/bhnd/bcma/bcma.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.h       Sat Sep  3 23:04:56 2016        
(r305365)
+++ head/sys/dev/bhnd/bcma/bcma.h       Sat Sep  3 23:57:17 2016        
(r305366)
@@ -45,5 +45,6 @@
  */
 
 DECLARE_CLASS(bcma_driver);
+DECLARE_CLASS(bcma_erom_parser);
 
-#endif /* _BCMA_BCMA_H_ */
\ No newline at end of file
+#endif /* _BCMA_BCMA_H_ */

Modified: head/sys/dev/bhnd/bcma/bcma_bhndb.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_bhndb.c Sat Sep  3 23:04:56 2016        
(r305365)
+++ head/sys/dev/bhnd/bcma/bcma_bhndb.c Sat Sep  3 23:57:17 2016        
(r305366)
@@ -73,29 +73,12 @@ static int
 bcma_bhndb_attach(device_t dev)
 {
        struct bcma_softc               *sc;
-       const struct bhnd_chipid        *cid;
-       struct resource                 *erom_res;
        int                              error;
-       int                              rid;
 
        sc = device_get_softc(dev);
 
-       /* Map the EROM resource and enumerate our children. */
-       cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
-       rid = 0;
-       erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
-               cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
-               RF_ACTIVE);
-       if (erom_res == NULL) {
-               device_printf(dev, "failed to allocate EROM resource\n");
-               return (ENXIO);
-       }
-
-       error = bcma_add_children(dev, erom_res, BCMA_EROM_TABLE_START);
-
-       /* Clean up */
-       bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res);
-       if (error)
+       /* Enumerate our children. */
+       if ((error = bcma_add_children(dev)))
                return (error);
 
        /* Initialize full bridge configuration */

Modified: head/sys/dev/bhnd/bcma/bcma_erom.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_erom.c  Sat Sep  3 23:04:56 2016        
(r305365)
+++ head/sys/dev/bhnd/bcma/bcma_erom.c  Sat Sep  3 23:57:17 2016        
(r305366)
@@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/resource.h>
 
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+
 #include "bcma_eromreg.h"
 #include "bcma_eromvar.h"
 
@@ -56,17 +58,43 @@ __FBSDID("$FreeBSD$");
  * marker.
  */
 
-static const char      *erom_entry_type_name (uint8_t entry);
-static int              erom_read32(struct bcma_erom *erom, uint32_t *entry);
-static int              erom_skip32(struct bcma_erom *erom);
-
-static int              erom_skip_core(struct bcma_erom *erom);
-static int              erom_skip_mport(struct bcma_erom *erom);
-static int              erom_skip_sport_region(struct bcma_erom *erom);
-
-static int              erom_seek_next(struct bcma_erom *erom, uint8_t etype);
-static int              erom_region_to_port_type(struct bcma_erom *erom,
-                           uint8_t region_type, bhnd_port_type *port_type);
+static const char      *bcma_erom_entry_type_name (uint8_t entry);
+static int              bcma_erom_read32(struct bcma_erom *erom,
+                            uint32_t *entry);
+static int              bcma_erom_skip32(struct bcma_erom *erom);
+
+static int              bcma_erom_skip_core(struct bcma_erom *erom);
+static int              bcma_erom_skip_mport(struct bcma_erom *erom);
+static int              bcma_erom_skip_sport_region(struct bcma_erom *erom);
+
+static int              bcma_erom_seek_next(struct bcma_erom *erom,
+                            uint8_t etype);
+static int              bcma_erom_region_to_port_type(struct bcma_erom *erom,
+                            uint8_t region_type, bhnd_port_type *port_type);
+
+static int              bcma_erom_peek32(struct bcma_erom *erom,
+                            uint32_t *entry);
+static bus_size_t       bcma_erom_tell(struct bcma_erom *erom);
+static void             bcma_erom_seek(struct bcma_erom *erom,
+                            bus_size_t offset);
+static void             bcma_erom_reset(struct bcma_erom *erom);
+
+static int              bcma_erom_seek_matching_core(struct bcma_erom *sc,
+                            const struct bhnd_core_match *desc,
+                            struct bhnd_core_info *core);
+
+static int              bcma_erom_parse_core(struct bcma_erom *erom,
+                            struct bcma_erom_core *core);
+
+static int              bcma_erom_parse_mport(struct bcma_erom *erom,
+                            struct bcma_erom_mport *mport);
+
+static int              bcma_erom_parse_sport_region(struct bcma_erom *erom,
+                            struct bcma_erom_sport_region *region);
+
+static void             bcma_erom_to_core_info(const struct bcma_erom_core 
*core,
+                            u_int core_idx, int core_unit,
+                            struct bhnd_core_info *info);
 
 #define        EROM_LOG(erom, fmt, ...)        do {                            
\
        if (erom->dev != NULL) {                                        \
@@ -78,58 +106,10 @@ static int          erom_region_to_port_type(st
        }                                                               \
 } while(0)
 
-/**
- * Open an EROM table for reading.
- * 
- * @param[out] erom On success, will be populated with a valid EROM
- * read state.
- * @param r An active resource mapping the EROM core.
- * @param offset Offset of the EROM core within @p resource.
- *
- * @retval 0 success
- * @retval non-zero if the erom table could not be opened.
- */
-int
-bcma_erom_open(struct bcma_erom *erom, struct resource *r,
-    bus_size_t offset)
-{
-       return (bhnd_erom_bus_space_open(erom, rman_get_device(r),
-           rman_get_bustag(r), rman_get_bushandle(r), offset));
-
-       return (0);
-}
-
-/**
- * Open an EROM table for reading using the provided bus space tag and
- * handle.
- * 
- * @param[out] erom On success, will be populated with a valid EROM
- * read state.
- * @param dev The owning device, or NULL if none.
- * @param bst EROM table bus space tag.
- * @param bsh EROM table bus space handle.
- * @param offset Offset of the EROM core from @p resource.
- *
- * @retval 0 success
- * @retval non-zero if the erom table could not be opened.
- */
-int
-bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t dev,
-    bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset)
-{
-       /* Initialize the EROM reader */
-       erom->dev = dev;
-       erom->bst = bst;
-       erom->bsh = bsh;
-       erom->start = offset + BCMA_EROM_TABLE_START;
-       erom->offset = 0;
-
-       return (0);
-}
 
 /** Return the type name for an EROM entry */
 static const char *
-erom_entry_type_name (uint8_t entry)
+bcma_erom_entry_type_name (uint8_t entry)
 {
        switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
        case BCMA_EROM_ENTRY_TYPE_CORE:
@@ -143,10 +123,340 @@ erom_entry_type_name (uint8_t entry)
        }
 }
 
+static int
+bcma_erom_init(bhnd_erom_t *erom, device_t parent, int rid, bus_addr_t 
enum_addr)
+{
+       struct bcma_erom *sc = (struct bcma_erom *)erom;
+
+       sc->dev = parent;
+
+       sc->rid = rid;
+       sc->res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &sc->rid,
+           enum_addr, enum_addr + BCMA_EROM_TABLE_SIZE - 1,
+           BCMA_EROM_TABLE_SIZE, RF_ACTIVE|RF_SHAREABLE);
+       if (sc->res == NULL)
+               return (ENOMEM);
+       
+       sc->start = BCMA_EROM_TABLE_START;
+       sc->offset = 0;
+
+       return (0);
+}
+
+static int
+bcma_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst,
+     bus_space_handle_t bsh, bus_addr_t paddr, struct bhnd_chipid *cid)
+{
+       uint32_t        idreg, eaddr;
+       uint8_t         chip_type;
+
+       idreg = bus_space_read_4(bst, bsh, CHIPC_ID);
+       chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
+
+       /* Fetch EROM physical address */
+       if (!BHND_CHIPTYPE_HAS_EROM(chip_type))
+               return (ENXIO);
+
+       eaddr = bus_space_read_4(bst, bsh, CHIPC_EROMPTR);
+
+       /* Parse chip identifier */
+       *cid = bhnd_parse_chipid(idreg, eaddr);
+
+       /* Verify chip type */
+       switch (chip_type) {
+               case BHND_CHIPTYPE_BCMA:
+                       return (BUS_PROBE_DEFAULT);
+
+               case BHND_CHIPTYPE_BCMA_ALT:
+               case BHND_CHIPTYPE_UBUS:
+                       return (BUS_PROBE_GENERIC);
+
+               default:
+                       return (ENXIO);
+       }
+}
+
+static int
+bcma_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
+     bus_space_handle_t bsh)
+{
+       struct bcma_erom *sc = (struct bcma_erom *)erom;
+
+       sc->dev = NULL;
+       sc->rid = -1;
+       sc->res = NULL;
+       sc->bst = bst;
+       sc->bsh = bsh;
+       sc->start = BCMA_EROM_TABLE_START;
+       sc->offset = 0;
+
+       return (0);
+}
+
+static void
+bcma_erom_fini(bhnd_erom_t *erom)
+{
+       struct bcma_erom *sc = (struct bcma_erom *)erom;
+
+       if (sc->res != NULL) {
+               bhnd_release_resource(sc->dev, SYS_RES_MEMORY, sc->rid,
+                   sc->res);
+
+               sc->res = NULL;
+               sc->rid = -1;
+       }
+}
+
+static int
+bcma_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
+    struct bhnd_core_info *core)
+{
+       struct bcma_erom *sc = (struct bcma_erom *)erom;
+
+       /* Search for the first matching core */
+       return (bcma_erom_seek_matching_core(sc, desc, core));
+}
+
+static int
+bcma_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match 
*desc,
+    bhnd_port_type port_type, u_int port_num, u_int region_num,
+    struct bhnd_core_info *core, bhnd_addr_t *addr, bhnd_size_t *size)
+{
+       struct bcma_erom        *sc;
+       struct bcma_erom_core    ec;
+       uint32_t                 entry;
+       uint8_t                  region_port, region_type;
+       bool                     found;
+       int                      error;
+
+       sc = (struct bcma_erom *)erom;
+
+       /* Seek to the first matching core and provide the core info
+        * to the caller */
+       if ((error = bcma_erom_seek_matching_core(sc, desc, core)))
+               return (error);
+
+       if ((error = bcma_erom_parse_core(sc, &ec)))
+               return (error);
+
+       /* Skip master ports */
+       for (u_long i = 0; i < ec.num_mport; i++) {
+               if ((error = bcma_erom_skip_mport(sc)))
+                       return (error);
+       }
+
+       /* Seek to the region block for the given port type */
+       found = false;
+       while (1) {
+               bhnd_port_type  p_type;
+               uint8_t         r_type;
+
+               if ((error = bcma_erom_peek32(sc, &entry)))
+                       return (error);
+
+               if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+                       return (ENOENT);
+
+               /* Expected region type? */
+               r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+               error = bcma_erom_region_to_port_type(sc, r_type, &p_type);
+               if (error)
+                       return (error);
+
+               if (p_type == port_type) {
+                       found = true;
+                       break;
+               }
+
+               /* Skip to next entry */
+               if ((error = bcma_erom_skip_sport_region(sc)))
+                       return (error);
+       }
+
+       if (!found)
+               return (ENOENT);
+
+       /* Found the appropriate port type block; now find the region records
+        * for the given port number */
+       found = false;
+       for (u_int i = 0; i <= port_num; i++) {
+               bhnd_port_type  p_type;
+
+               if ((error = bcma_erom_peek32(sc, &entry)))
+                       return (error);
+               
+               if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+                       return (ENOENT);
+
+               /* Fetch the type/port of the first region entry */
+               region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+               region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+               /* Have we found the region entries for the desired port? */
+               if (i == port_num) {
+                       error = bcma_erom_region_to_port_type(sc, region_type,
+                           &p_type);
+                       if (error)
+                               return (error);
+
+                       if (p_type == port_type)
+                               found = true;
+
+                       break;
+               }
+
+               /* Otherwise, seek to next block of region records */
+               while (1) {
+                       uint8_t next_type, next_port;
+       
+                       if ((error = bcma_erom_skip_sport_region(sc)))
+                               return (error);
+
+                       if ((error = bcma_erom_peek32(sc, &entry)))
+                               return (error);
+
+                       if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+                               return (ENOENT);
+
+                       next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+                       next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+                       if (next_type != region_type ||
+                           next_port != region_port)
+                               break;
+               }
+       }
+
+       if (!found)
+               return (ENOENT);
+
+       /* Finally, search for the requested region number */
+       for (u_int i = 0; i <= region_num; i++) {
+               struct bcma_erom_sport_region   region;
+               uint8_t                         next_port, next_type;
+
+               if ((error = bcma_erom_peek32(sc, &entry)))
+                       return (error);
+               
+               if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+                       return (ENOENT);
+
+               /* Check for the end of the region block */
+               next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+               next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+               if (next_type != region_type ||
+                   next_port != region_port)
+                       break;
+
+               /* Parse the region */
+               if ((error = bcma_erom_parse_sport_region(sc, &region)))
+                       return (error);
+
+               /* Is this our target region_num? */
+               if (i == region_num) {
+                       /* Found */
+                       *addr = region.base_addr;
+                       *size = region.size;
+                       return (0);
+               }
+       }
+
+       /* Not found */
+       return (ENOENT);
+};
+
+static int
+bcma_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
+    u_int *num_cores)
+{
+       struct bcma_erom        *sc;
+       struct bhnd_core_info   *buffer;
+       bus_size_t               initial_offset;
+       u_int                    count;
+       int                      error;
+
+       sc = (struct bcma_erom *)erom;
+
+       buffer = NULL;
+       initial_offset = bcma_erom_tell(sc);
+
+       /* Determine the core count */
+       bcma_erom_reset(sc);
+       for (count = 0, error = 0; !error; count++) {
+               struct bcma_erom_core core;
+
+               /* Seek to the first readable core entry */
+               error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
+               if (error == ENOENT)
+                       break;
+               else if (error)
+                       goto cleanup;
+               
+               /* Read past the core descriptor */
+               if ((error = bcma_erom_parse_core(sc, &core)))
+                       goto cleanup;
+       }
+
+       /* Allocate our output buffer */
+       buffer = malloc(sizeof(struct bhnd_core_info) * count, M_BHND,
+           M_NOWAIT);
+       if (buffer == NULL) {
+               error = ENOMEM;
+               goto cleanup;
+       }
+
+       /* Parse all core descriptors */
+       bcma_erom_reset(sc);
+       for (u_int i = 0; i < count; i++) {
+               struct bcma_erom_core   core;
+               int                     unit;
+
+               /* Parse the core */
+               error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
+               if (error)
+                       goto cleanup;
+
+               error = bcma_erom_parse_core(sc, &core);
+               if (error)
+                       goto cleanup;
+
+               /* Determine the unit number */
+               unit = 0;
+               for (u_int j = 0; j < i; j++) {
+                       if (buffer[i].vendor == buffer[j].vendor &&
+                           buffer[i].device == buffer[j].device)
+                               unit++;
+               }
+
+               /* Convert to a bhnd info record */
+               bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
+       }
+
+cleanup:
+       if (!error) {
+               *cores = buffer;
+               *num_cores = count;
+       } else {
+               if (buffer != NULL)
+                       free(buffer, M_BHND);
+       }
+
+       /* Restore the initial position */
+       bcma_erom_seek(sc, initial_offset);
+       return (error);
+}
+
+static void
+bcma_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
+{
+       free(cores, M_BHND);
+}
+
 /**
  * Return the current read position.
  */
-bus_size_t
+static bus_size_t
 bcma_erom_tell(struct bcma_erom *erom)
 {
        return (erom->offset);
@@ -155,7 +465,7 @@ bcma_erom_tell(struct bcma_erom *erom)
 /**
  * Seek to an absolute read position.
  */
-void
+static void
 bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset)
 {
        erom->offset = offset;
@@ -171,16 +481,22 @@ bcma_erom_seek(struct bcma_erom *erom, b
  * @retval ENOENT The end of the EROM table was reached.
  * @retval non-zero The read could not be completed.
  */
-int
+static int
 bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
 {
+       bus_size_t off;
+
        if (erom->offset >= BCMA_EROM_TABLE_SIZE) {
                EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n");
                return (EINVAL);
        }
 
-       *entry = bus_space_read_4(erom->bst, erom->bsh,
-           erom->start + erom->offset);
+       off = erom->start + erom->offset;
+       if (erom->res != NULL)
+               *entry = bhnd_bus_read_4(erom->res, off);
+       else
+               *entry = bus_space_read_4(erom->bst, erom->bsh, off);
+
        return (0);
 }
 
@@ -194,7 +510,7 @@ bcma_erom_peek32(struct bcma_erom *erom,
  * @retval non-zero The read could not be completed.
  */
 static int
-erom_read32(struct bcma_erom *erom, uint32_t *entry)
+bcma_erom_read32(struct bcma_erom *erom, uint32_t *entry)
 {
        int error;
 
@@ -213,11 +529,11 @@ erom_read32(struct bcma_erom *erom, uint
  * @retval non-zero The read could not be completed.
  */
 static int
-erom_skip32(struct bcma_erom *erom)
+bcma_erom_skip32(struct bcma_erom *erom)
 {
        uint32_t        entry;
 
-       return erom_read32(erom, &entry);
+       return bcma_erom_read32(erom, &entry);
 }
 
 /**
@@ -229,7 +545,7 @@ erom_skip32(struct bcma_erom *erom)
  * @retval non-zero The read could not be completed.
  */
 static int
-erom_skip_core(struct bcma_erom *erom)
+bcma_erom_skip_core(struct bcma_erom *erom)
 {
        struct bcma_erom_core core;
        return (bcma_erom_parse_core(erom, &core));
@@ -244,7 +560,7 @@ erom_skip_core(struct bcma_erom *erom)
  * @retval non-zero The read could not be completed.
  */
 static int
-erom_skip_mport(struct bcma_erom *erom)
+bcma_erom_skip_mport(struct bcma_erom *erom)
 {
        struct bcma_erom_mport mp;
        return (bcma_erom_parse_mport(erom, &mp));
@@ -259,7 +575,7 @@ erom_skip_mport(struct bcma_erom *erom)
  * @retval non-zero The read could not be completed.
  */
 static int
-erom_skip_sport_region(struct bcma_erom *erom)
+bcma_erom_skip_sport_region(struct bcma_erom *erom)
 {
        struct bcma_erom_sport_region r;
        return (bcma_erom_parse_sport_region(erom, &r));
@@ -276,7 +592,7 @@ erom_skip_sport_region(struct bcma_erom 
  * @retval non-zero Reading or parsing the descriptor failed.
  */
 static int
-erom_seek_next(struct bcma_erom *erom, uint8_t etype)
+bcma_erom_seek_next(struct bcma_erom *erom, uint8_t etype)
 {
        uint32_t                        entry;
        int                             error;
@@ -298,19 +614,19 @@ erom_seek_next(struct bcma_erom *erom, u
                /* Skip non-matching entry types. */
                switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
                case BCMA_EROM_ENTRY_TYPE_CORE:
-                       if ((error = erom_skip_core(erom)))
+                       if ((error = bcma_erom_skip_core(erom)))
                                return (error);
 
                        break;
 
                case BCMA_EROM_ENTRY_TYPE_MPORT:
-                       if ((error = erom_skip_mport(erom)))
+                       if ((error = bcma_erom_skip_mport(erom)))
                                return (error);
 
                        break;
                
                case BCMA_EROM_ENTRY_TYPE_REGION:
-                       if ((error = erom_skip_sport_region(erom)))
+                       if ((error = bcma_erom_skip_sport_region(erom)))
                                return (error);
                        break;
 
@@ -328,62 +644,100 @@ erom_seek_next(struct bcma_erom *erom, u
  * 
  * @param erom EROM read state.
  */
-void
+static void
 bcma_erom_reset(struct bcma_erom *erom)
 {
        erom->offset = 0;
 }
 
 /**
- * Seek to the next core entry.
- * 
- * @param erom EROM read state.
- * @retval 0 success
- * @retval ENOENT The end of the EROM table was reached.
- * @retval non-zero Reading or parsing failed.
- */
-int
-bcma_erom_seek_next_core(struct bcma_erom *erom)
-{
-       return (erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE));
-}
-
-/**
- * Seek to the requested core entry.
+ * Seek to the first core entry matching @p desc.
  * 
  * @param erom EROM read state.
- * @param core_index Index of the core to seek to.
+ * @param desc The core match descriptor.
+ * @param[out] core On success, the matching core info. If the core info
+ * is not desired, a NULL pointer may be provided.
  * @retval 0 success
  * @retval ENOENT The end of the EROM table was reached before @p index was
  * found.
  * @retval non-zero Reading or parsing failed.
  */
-int
-bcma_erom_seek_core_index(struct bcma_erom *erom, u_int core_index)
+static int
+bcma_erom_seek_matching_core(struct bcma_erom *sc,
+    const struct bhnd_core_match *desc, struct bhnd_core_info *core)
 {
-       int error;
+       struct bhnd_core_match   imatch;
+       bus_size_t               core_offset, next_offset;
+       int                      error;
 
-       /* Start search at top of EROM */
-       bcma_erom_reset(erom);
+       /* Seek to table start. */
+       bcma_erom_reset(sc);
 
-       /* Skip core descriptors till we hit the requested entry */
-       for (u_int i = 0; i < core_index; i++) {
-               struct bcma_erom_core core;
+       /* We can't determine a core's unit number during the initial scan. */
+       imatch = *desc;
+       imatch.m.match.core_unit = 0;
+
+       /* Locate the first matching core */
+       for (u_int i = 0; i < UINT_MAX; i++) {
+               struct bcma_erom_core   ec;
+               struct bhnd_core_info   ci;
 
-               /* Read past the core descriptor */
-               if ((error = bcma_erom_parse_core(erom, &core)))
+               /* Seek to the next core */
+               error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
+               if (error)
                        return (error);
 
-               /* Seek to the next readable core entry */
-               error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
-               if (error)
+               /* Save the core offset */
+               core_offset = bcma_erom_tell(sc);
+       
+               /* Parse the core */
+               if ((error = bcma_erom_parse_core(sc, &ec)))
                        return (error);
+
+               bcma_erom_to_core_info(&ec, i, 0, &ci);
+
+               /* Check for initial match */
+               if (!bhnd_core_matches(&ci, &imatch))
+                       continue;
+
+               /* Re-scan preceding cores to determine the unit number. */
+               next_offset = bcma_erom_tell(sc);
+               bcma_erom_reset(sc);
+               for (u_int j = 0; j < i; j++) {
+                       /* Parse the core */
+                       error = bcma_erom_seek_next(sc,
+                           BCMA_EROM_ENTRY_TYPE_CORE);
+                       if (error)
+                               return (error);
+                       
+                       if ((error = bcma_erom_parse_core(sc, &ec)))
+                               return (error);
+
+                       /* Bump the unit number? */
+                       if (ec.vendor == ci.vendor && ec.device == ci.device)
+                               ci.unit++;
+               }
+
+               /* Check for full match against now-valid unit number */
+               if (!bhnd_core_matches(&ci, desc)) {
+                       /* Reposition to allow reading the next core */
+                       bcma_erom_seek(sc, next_offset);
+                       continue;
+               }
+
+               /* Found; seek to the core's initial offset and provide
+                * the core info to the caller */
+               bcma_erom_seek(sc, core_offset);
+               if (core != NULL)
+                       *core = ci;
+
+               return (0);
        }
 
-       return (0);
+       /* Not found, or a parse error occured */
+       return (error);
 }
 
-
 /**
  * Read the next core descriptor from the EROM table.
  * 
@@ -394,14 +748,14 @@ bcma_erom_seek_core_index(struct bcma_er
  * @retval ENOENT The end of the EROM table was reached.
  * @retval non-zero Reading or parsing the core descriptor failed.
  */
-int
+static int
 bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
 {
        uint32_t        entry;
        int             error;
 
        /* Parse CoreDescA */
-       if ((error = erom_read32(erom, &entry)))
+       if ((error = bcma_erom_read32(erom, &entry)))
                return (error);
        
        /* Handle EOF */
@@ -410,7 +764,7 @@ bcma_erom_parse_core(struct bcma_erom *e
        
        if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
                EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n",
-                   entry, erom_entry_type_name(entry));
+                   entry, bcma_erom_entry_type_name(entry));
                
                return (EINVAL);
        }
@@ -419,7 +773,7 @@ bcma_erom_parse_core(struct bcma_erom *e
        core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID);
        
        /* Parse CoreDescB */
-       if ((error = erom_read32(erom, &entry)))
+       if ((error = bcma_erom_read32(erom, &entry)))
                return (error);
 
        if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
@@ -436,153 +790,6 @@ bcma_erom_parse_core(struct bcma_erom *e
 }
 
 /**
- * Seek to a region record associated with @p core_index.
- * 
- * @param erom EROM read state.
- * @param core_index The index of the core record to be searched.
- * @param port_type The port type to search for.
- * @param port_num The port number to search for.
- * @param region_num The region number to search for.
- * @retval 0 success
- * @retval ENOENT The requested region was not found.
- * @retval non-zero Reading or parsing failed.
- */
-int
-bcma_erom_seek_core_sport_region(struct bcma_erom *erom, u_int core_index,
-    bhnd_port_type port_type, u_int port_num, u_int region_num)
-{
-       struct bcma_erom_core   core;
-       uint32_t                entry;
-       uint8_t                 region_port, region_type;
-       bool                    found;
-       int                     error;
-
-       if ((error = bcma_erom_seek_core_index(erom, core_index)))
-               return (error);
-
-       if ((error = bcma_erom_parse_core(erom, &core)))
-               return (error);
-
-       /* Skip master ports */
-       for (u_long i = 0; i < core.num_mport; i++) {
-               if ((error = erom_skip_mport(erom)))
-                       return (error);
-       }
-
-       /* Seek to the region block for the given port type */
-       found = false;
-       while (1) {
-               bhnd_port_type  p_type;
-               uint8_t         r_type;
-
-               if ((error = bcma_erom_peek32(erom, &entry)))
-                       return (error);
-
-               if (!BCMA_EROM_ENTRY_IS(entry, REGION))
-                       return (ENOENT);
-
-               /* Expected region type? */
-               r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
-               if ((error = erom_region_to_port_type(erom, r_type, &p_type)))
-                       return (error);
-
-               if (p_type == port_type) {
-                       found = true;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to