Author: landonf
Date: Mon Feb 12 19:36:26 2018
New Revision: 329180
URL: https://svnweb.freebsd.org/changeset/base/329180

Log:
  siba(4): Ignore disabled per-core address match entries.
  
  Previously, the address regions described by disabled admatch entries would
  be treated as being mapped to the given core; while incorrect, this was
  essentially harmless given that the entries describe unused address space
  on the few affected devices.
  
  We now perform parsing of per-core admatch registers and interrupt flags in
  siba_erom, correctly skip any disabled admatch entries, and use the
  siba_erom API in siba_add_children() to perform enumeration of attached
  cores.

Added:
  head/sys/dev/bhnd/siba/siba_eromvar.h   (contents, props changed)
Modified:
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_erom.c
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibavar.h

Modified: head/sys/dev/bhnd/siba/siba.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba.c       Mon Feb 12 19:08:17 2018        
(r329179)
+++ head/sys/dev/bhnd/siba/siba.c       Mon Feb 12 19:36:26 2018        
(r329180)
@@ -47,9 +47,14 @@ __FBSDID("$FreeBSD$");
 #include <dev/bhnd/cores/chipc/chipc.h>
 #include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h>
 
+#include "siba_eromvar.h"
+
 #include "sibareg.h"
 #include "sibavar.h"
 
+/* RID used when allocating EROM resources */
+#define        SIBA_EROM_RID   0
+
 static bhnd_erom_class_t *
 siba_get_erom_class(driver_t *driver)
 {
@@ -1057,7 +1062,7 @@ siba_decode_port_rid(device_t dev, device_t child, int
                return (EINVAL);
 
        /* Look for a matching addrspace entry */
-       for (u_int i = 0; i < dinfo->core_id.num_addrspace; i++) {
+       for (u_int i = 0; i < dinfo->core_id.num_admatch; i++) {
                if (dinfo->addrspace[i].sa_rid != rid)
                        continue;
 
@@ -1131,7 +1136,7 @@ siba_get_intr_count(device_t dev, device_t child)
                return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
 
        dinfo = device_get_ivars(child);
-       if (!dinfo->intr_en) {
+       if (!dinfo->core_id.intr_en) {
                /* No interrupts */
                return (0);
        } else {
@@ -1161,121 +1166,14 @@ siba_get_intr_ivec(device_t dev, device_t child, u_int
 
        dinfo = device_get_ivars(child);
 
-       KASSERT(dinfo->intr_en, ("core does not have an interrupt assigned"));
-       *ivec = dinfo->intr.flag;
-       return (0);
-}
+       KASSERT(dinfo->core_id.intr_en,
+           ("core does not have an interrupt assigned"));
 
-/**
- * Register all address space mappings for @p di.
- *
- * @param dev The siba bus device.
- * @param di The device info instance on which to register all address
- * space entries.
- * @param r A resource mapping the enumeration table block for @p di.
- */
-static int
-siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
-    struct bhnd_resource *r)
-{
-       struct siba_core_id     *cid;
-       uint32_t                 addr;
-       uint32_t                 size;
-       int                      error;
-
-       cid = &di->core_id;
-
-
-       /* Register the device address space entries */
-       for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
-               uint32_t        adm;
-               u_int           adm_offset;
-               uint32_t        bus_reserved;
-
-               /* Determine the register offset */
-               adm_offset = siba_admatch_offset(i);
-               if (adm_offset == 0) {
-                   device_printf(dev, "addrspace %hhu is unsupported", i);
-                   return (ENODEV);
-               }
-
-               /* Fetch the address match register value */
-               adm = bhnd_bus_read_4(r, adm_offset);
-
-               /* Parse the value */
-               if ((error = siba_parse_admatch(adm, &addr, &size))) {
-                       device_printf(dev, "failed to decode address "
-                           " match register value 0x%x\n", adm);
-                       return (error);
-               }
-
-               /* If this is the device's core/enumeration addrespace,
-                * reserve the Sonics configuration register blocks for the
-                * use of our bus. */
-               bus_reserved = 0;
-               if (i == SIBA_CORE_ADDRSPACE)
-                       bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
-
-               /* Append the region info */
-               error = siba_append_dinfo_region(di, i, addr, size,
-                   bus_reserved);
-               if (error)
-                       return (error);
-       }
-
+       *ivec = dinfo->core_id.intr_flag;
        return (0);
 }
 
-
 /**
- * Register all interrupt descriptors for @p dinfo. Must be called after
- * configuration blocks have been mapped.
- *
- * @param dev The siba bus device.
- * @param child The siba child device.
- * @param dinfo The device info instance on which to register all interrupt
- * descriptor entries.
- * @param r A resource mapping the enumeration table block for @p di.
- */
-static int
-siba_register_interrupts(device_t dev, device_t child,
-    struct siba_devinfo *dinfo, struct bhnd_resource *r)
-{
-       uint32_t        tpsflag;
-       int             error;
-
-       /* Is backplane interrupt distribution enabled for this core? */
-       tpsflag = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
-       if ((tpsflag & SIBA_TPS_F0EN0) == 0) {
-               dinfo->intr_en = false;
-               return (0);
-       }
-
-       /* Have one interrupt */
-       dinfo->intr_en = true;
-       dinfo->intr.flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
-       dinfo->intr.mapped = false;
-       dinfo->intr.irq = 0;
-       dinfo->intr.rid = -1;
-
-       /* Map the interrupt */
-       error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
-           &dinfo->intr.irq);
-       if (error) {
-               device_printf(dev, "failed mapping interrupt line for core %u: "
-                   "%d\n", dinfo->core_id.core_info.core_idx, error);
-               return (error);
-       }
-       dinfo->intr.mapped = true;
-
-       /* Update the resource list */
-       dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
-           dinfo->intr.irq, dinfo->intr.irq, 1);
-
-       return (0);
-}
-
-/**
  * Map per-core configuration blocks for @p dinfo.
  *
  * @param dev The siba bus device.
@@ -1386,21 +1284,27 @@ siba_child_deleted(device_t dev, device_t child)
 int
 siba_add_children(device_t dev)
 {
-       const struct bhnd_chipid        *chipid;
+       bhnd_erom_t                     *erom;
+       struct siba_erom                *siba_erom;
+       struct bhnd_erom_io             *eio;
+       const struct bhnd_chipid        *cid;
        struct siba_core_id             *cores;
-       struct bhnd_resource            *r;
        device_t                        *children;
-       int                              rid;
        int                              error;
 
-       cores = NULL;
-       r = NULL;
+       cid = BHND_BUS_GET_CHIPID(dev, dev);
 
-       chipid = BHND_BUS_GET_CHIPID(dev, dev);
+       /* Allocate our EROM parser */
+       eio = bhnd_erom_iores_new(dev, SIBA_EROM_RID);
+       erom = bhnd_erom_alloc(&siba_erom_parser, cid, eio);
+       if (erom == NULL) {
+               bhnd_erom_io_fini(eio);
+               return (ENODEV);
+       }
 
        /* Allocate our temporary core and device table */
-       cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_WAITOK);
-       children = malloc(sizeof(*children) * chipid->ncores, M_BHND,
+       cores = malloc(sizeof(*cores) * cid->ncores, M_BHND, M_WAITOK);
+       children = malloc(sizeof(*children) * cid->ncores, M_BHND,
            M_WAITOK | M_ZERO);
 
        /*
@@ -1411,40 +1315,14 @@ siba_add_children(device_t dev)
         * defer mapping of the per-core siba(4) config blocks until all cores
         * have been enumerated and otherwise configured.
         */
-       for (u_int i = 0; i < chipid->ncores; i++) {
+       siba_erom = (struct siba_erom *)erom;
+       for (u_int i = 0; i < cid->ncores; i++) {
                struct siba_devinfo     *dinfo;
                device_t                 child;
-               uint32_t                 idhigh, idlow;
-               rman_res_t               r_count, r_end, r_start;
 
-               /* Map the core's register block */
-               rid = 0;
-               r_start = SIBA_CORE_ADDR(i);
-               r_count = SIBA_CORE_SIZE;
-               r_end = r_start + SIBA_CORE_SIZE - 1;
-               r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
-                   r_end, r_count, RF_ACTIVE);
-               if (r == NULL) {
-                       error = ENXIO;
+               if ((error = siba_erom_get_core_id(siba_erom, i, &cores[i])))
                        goto failed;
-               }
 
-               /* Read the core info */
-               idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
-               idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
-
-               cores[i] = siba_parse_core_id(idhigh, idlow, i, 0);
-
-               /* Determine and set unit number */
-               for (u_int j = 0; j < i; j++) {
-                       struct bhnd_core_info *cur = &cores[i].core_info;
-                       struct bhnd_core_info *prev = &cores[j].core_info;
-
-                       if (prev->vendor == cur->vendor &&
-                           prev->device == cur->device)
-                               cur->unit++;
-               }
-
                /* Add the child device */
                child = BUS_ADD_CHILD(dev, 0, NULL, -1);
                if (child == NULL) {
@@ -1460,30 +1338,22 @@ siba_add_children(device_t dev)
                        goto failed;
                }
 
-               if ((error = siba_init_dinfo(dev, dinfo, &cores[i])))
+               if ((error = siba_init_dinfo(dev, child, dinfo, &cores[i])))
                        goto failed;
 
-               /* Register the core's address space(s). */
-               if ((error = siba_register_addrspaces(dev, dinfo, r)))
-                       goto failed;
-
-               /* Register the core's interrupts */
-               if ((error = siba_register_interrupts(dev, child, dinfo, r)))
-                       goto failed;
-
-               /* Unmap the core's register block */
-               bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
-               r = NULL;
-
                /* If pins are floating or the hardware is otherwise
                 * unpopulated, the device shouldn't be used. */
                if (bhnd_is_hw_disabled(child))
                        device_disable(child);
        }
 
+       /* Free EROM (and any bridge register windows it might hold) */
+       bhnd_erom_free(erom);
+       erom = NULL;
+
        /* Map all valid core's config register blocks and perform interrupt
         * assignment */
-       for (u_int i = 0; i < chipid->ncores; i++) {
+       for (u_int i = 0; i < cid->ncores; i++) {
                struct siba_devinfo     *dinfo;
                device_t                 child;
 
@@ -1509,7 +1379,7 @@ siba_add_children(device_t dev)
        return (0);
 
 failed:
-       for (u_int i = 0; i < chipid->ncores; i++) {
+       for (u_int i = 0; i < cid->ncores; i++) {
                if (children[i] == NULL)
                        continue;
 
@@ -1518,9 +1388,8 @@ failed:
 
        free(cores, M_BHND);
        free(children, M_BHND);
-
-       if (r != NULL)
-               bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
+       if (erom != NULL)
+               bhnd_erom_free(erom);
 
        return (error);
 }

Modified: head/sys/dev/bhnd/siba/siba_erom.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba_erom.c  Mon Feb 12 19:08:17 2018        
(r329179)
+++ head/sys/dev/bhnd/siba/siba_erom.c  Mon Feb 12 19:36:26 2018        
(r329180)
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
 #include "sibareg.h"
 #include "sibavar.h"
 
+#include "siba_eromvar.h"
+
 struct siba_erom;
 struct siba_erom_io;
 
@@ -59,8 +61,9 @@ static int                    siba_eio_init(struct 
siba_erom_io *io,
 static uint32_t                        siba_eio_read_4(struct siba_erom_io *io,
                                    u_int core_idx, bus_size_t offset);
 
-static struct siba_core_id     siba_eio_read_core_id(struct siba_erom_io *io,
-                                   u_int core_idx, int unit);
+static int                     siba_eio_read_core_id(struct siba_erom_io *io,
+                                   u_int core_idx, int unit,
+                                   struct siba_core_id *sid);
 
 static int                     siba_eio_read_chipid(struct siba_erom_io *io,
                                    bus_addr_t enum_addr,
@@ -118,7 +121,8 @@ siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_er
                 * BCM4710, it's a SDRAM core (0x803).
                 */
 
-               sid = siba_eio_read_core_id(&io, 0, 0);
+               if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
+                       return (error);
 
                if (sid.core_info.vendor != BHND_MFGID_BCM)
                        return (ENXIO);
@@ -227,19 +231,154 @@ siba_eio_read_4(struct siba_erom_io *io, u_int core_id
  * @param core_idx The core index.
  * @param unit The caller-specified unit number to be included in the return
  * value.
+ * @param[out] sid On success, the parsed siba core id.
+ * 
+ * @retval 0           success
+ * @retval non-zero     if reading or parsing the identification registers
+ *                     otherwise fails, a regular unix error code will be
+ *                     returned.
  */
-static struct siba_core_id
-siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
+static int
+siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
+    struct siba_core_id *sid)
 {
-       uint32_t idhigh, idlow;
+       struct siba_admatch     admatch[SIBA_MAX_ADDRSPACE];
+       uint32_t                idhigh, idlow;
+       uint32_t                tpsflag;
+       uint16_t                ocp_vendor;
+       uint8_t                 sonics_rev;
+       uint8_t                 num_admatch;
+       uint8_t                 num_admatch_en;
+       uint8_t                 num_cfg;
+       bool                    intr_en;
+       u_int                   intr_flag;
+       int                     error;
 
        idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
        idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
+       tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
 
-       return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
+       ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
+       sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
+       num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
+       if (num_admatch > nitems(admatch)) {
+               printf("core%u: invalid admatch count %hhu\n", core_idx,
+                   num_admatch);
+               return (EINVAL);
+       }
+
+       /* Determine backplane interrupt distribution configuration */
+       intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
+       intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
+
+       /* Determine the number of sonics config register blocks */
+       num_cfg = SIBA_CFG_NUM_2_2;
+       if (sonics_rev >= SIBA_IDL_SBREV_2_3)
+               num_cfg = SIBA_CFG_NUM_2_3;
+
+       /* Parse all admatch descriptors */
+       num_admatch_en = 0;
+       for (uint8_t i = 0; i < num_admatch; i++) {
+               uint32_t        am_value;
+               u_int           am_offset;
+
+               KASSERT(i < nitems(admatch), ("invalid admatch index"));
+
+               /* Determine the register offset */
+               am_offset = siba_admatch_offset(i);
+               if (am_offset == 0) {
+                       printf("core%u: addrspace %hhu is unsupported",
+                           core_idx, i);
+                       return (ENODEV);
+               }
+
+               /* Read and parse the address match register */
+               am_value = siba_eio_read_4(io, core_idx, am_offset);
+               error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
+               if (error) {
+                       printf("core%u: failed to decode admatch[%hhu] "
+                           "register value 0x%x\n", core_idx, i, am_value);
+                       return (error);
+               }
+
+               /* Skip disabled entries */
+               if (!admatch[num_admatch_en].am_enabled)
+                       continue;
+
+               /* Reject unsupported negative matches. These are not used on
+                * any known devices */
+               if (admatch[num_admatch_en].am_negative) {
+                       printf("core%u: unsupported negative admatch[%hhu] "
+                           "value 0x%x\n", core_idx, i, am_value);
+                       return (ENXIO);
+               }
+
+               num_admatch_en++;
+       }
+
+       /* Populate the result */
+       *sid = (struct siba_core_id) {
+               .core_info      = {
+                       .vendor = siba_get_bhnd_mfgid(ocp_vendor),
+                       .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
+                       .hwrev  = SIBA_IDH_CORE_REV(idhigh),
+                       .core_idx = core_idx,
+                       .unit   = unit
+               },
+               .sonics_vendor  = ocp_vendor,
+               .sonics_rev     = sonics_rev,
+               .intr_en        = intr_en,
+               .intr_flag      = intr_flag,
+               .num_admatch    = num_admatch_en,
+               .num_cfg_blocks = num_cfg
+       };
+       memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
+
+       return (0);
 }
 
 /**
+ * Read and parse the SSB identification registers for the given @p core_index,
+ * returning the siba(4) core identification in @p sid.
+ * 
+ * @param sc A siba EROM instance.
+ * @param core_idx The index of the core to be identified.
+ * @param[out] result On success, the parsed siba core id.
+ * 
+ * @retval 0           success
+ * @retval non-zero     if reading or parsing the identification registers
+ *                     otherwise fails, a regular unix error code will be
+ *                     returned.
+ */
+int
+siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
+    struct siba_core_id *result)
+{
+       struct siba_core_id     sid;
+       int                     error;
+
+       /* Fetch the core info, assuming a unit number of 0 */
+       if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
+               return (error);
+
+       /* Scan preceding cores to determine the real unit number. */
+       for (u_int i = 0; i < core_idx; i++) {
+               struct siba_core_id prev;
+
+               if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
+                       return (error);
+
+               /* Bump the unit number? */
+               if (sid.core_info.vendor == prev.core_info.vendor &&
+                   sid.core_info.device == prev.core_info.device)
+                       sid.core_info.unit++;
+       }
+
+       *result = sid;
+       return (0);
+}
+
+/**
  * Read and parse the chip identification register from the ChipCommon core.
  * 
  * @param io EROM I/O context.
@@ -252,9 +391,12 @@ siba_eio_read_chipid(struct siba_erom_io *io, bus_addr
 {
        struct siba_core_id     ccid;
        uint32_t                idreg;
+       int                     error;
 
        /* Identify the chipcommon core */
-       ccid = siba_eio_read_core_id(io, 0, 0);
+       if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
+               return (error);
+
        if (ccid.core_info.vendor != BHND_MFGID_BCM ||
            ccid.core_info.device != BHND_COREID_CC)
        {
@@ -281,6 +423,7 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
 {
        struct siba_erom        *sc;
        struct bhnd_core_match   imatch;
+       int                      error;
 
        sc = (struct siba_erom *)erom;
 
@@ -294,7 +437,9 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
                struct bhnd_core_info   ci;
 
                /* Read the core info */
-               sid = siba_eio_read_core_id(&sc->io, i, 0);
+               if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
+                       return (error);
+
                ci = sid.core_info;
 
                /* Check for initial match */
@@ -303,7 +448,9 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
 
                /* Re-scan preceding cores to determine the unit number. */
                for (u_int j = 0; j < i; j++) {
-                       sid = siba_eio_read_core_id(&sc->io, j, 0);
+                       error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
+                       if (error)
+                               return (error);
 
                        /* Bump the unit number? */
                        if (sid.core_info.vendor == ci.vendor &&
@@ -332,7 +479,8 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
        struct siba_erom        *sc;
        struct bhnd_core_info    core;
        struct siba_core_id      sid;
-       uint32_t                 am, am_addr, am_size;
+       struct siba_admatch      admatch;
+       uint32_t                 am;
        u_int                    am_offset;
        u_int                    addrspace, cfg;
        
@@ -345,7 +493,9 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
                return (error);
 
        /* Fetch full siba core ident */
-       sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
+       error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
+       if (error)
+               return (error);
 
        /* Is port valid? */
        if (!siba_is_port_valid(&sid, type, port))
@@ -419,7 +569,7 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
        /* Read and parse the address match register */
        am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
 
-       if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
+       if ((error = siba_parse_admatch(am, &admatch))) {
                printf("failed to decode address match register value 0x%x\n",
                    am);
                return (error);
@@ -428,8 +578,8 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
        if (info != NULL)
                *info = core;
 
-       *addr = am_addr;
-       *size = am_size;
+       *addr = admatch.am_base;
+       *size = admatch.am_size;
 
        return (0);
 }
@@ -441,6 +591,7 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhn
 {
        struct siba_erom        *sc;
        struct bhnd_core_info   *out;
+       int                      error;
 
        sc = (struct siba_erom *)erom;
 
@@ -457,7 +608,9 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhn
                struct siba_core_id sid;
 
                /* Read the core info */
-               sid = siba_eio_read_core_id(&sc->io, i, 0);
+               if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
+                       return (error);
+
                out[i] = sid.core_info;
 
                /* Determine unit number */
@@ -508,8 +661,9 @@ siba_erom_dump(bhnd_erom_t *erom)
                printf("\tnraddr\t0x%04x\n", nraddr);
 
                for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
-                       uint32_t        am, am_addr, am_size;
-                       u_int           am_offset;
+                       struct siba_admatch     admatch;
+                       uint32_t                am;
+                       u_int                   am_offset;
 
                        /* Determine the register offset */
                        am_offset = siba_admatch_offset(addrspace);
@@ -521,16 +675,15 @@ siba_erom_dump(bhnd_erom_t *erom)
                        
                        /* Read and parse the address match register */
                        am = siba_eio_read_4(&sc->io, i, am_offset);
-                       error = siba_parse_admatch(am, &am_addr, &am_size);
-                       if (error) {
+                       if ((error = siba_parse_admatch(am, &admatch))) {
                                printf("failed to decode address match "
                                    "register value 0x%x\n", am);
                                continue;
                        }
 
                        printf("\taddrspace %zu\n", addrspace);
-                       printf("\t\taddr: 0x%08x\n", am_addr);
-                       printf("\t\tsize: 0x%08x\n", am_size);
+                       printf("\t\taddr: 0x%08x\n", admatch.am_base);
+                       printf("\t\tsize: 0x%08x\n", admatch.am_size);
                }
        }
 

Added: head/sys/dev/bhnd/siba/siba_eromvar.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/bhnd/siba/siba_eromvar.h       Mon Feb 12 19:36:26 2018        
(r329180)
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Landon Fuller <land...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef        _SIBA_SIBA_EROMVAR_H_
+#define        _SIBA_SIBA_EROMVAR_H_
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhnd_erom.h>
+
+#include "sibavar.h"
+
+struct siba_erom;
+
+#define        SIBA_EROM_
+
+int    siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
+           struct siba_core_id *result);
+
+#endif /* _SIBA_SIBA_EROMVAR_H_ */

Modified: head/sys/dev/bhnd/siba/siba_subr.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba_subr.c  Mon Feb 12 19:08:17 2018        
(r329179)
+++ head/sys/dev/bhnd/siba/siba_subr.c  Mon Feb 12 19:36:26 2018        
(r329180)
@@ -48,6 +48,12 @@ __FBSDID("$FreeBSD$");
 #include "sibareg.h"
 #include "sibavar.h"
 
+static int     siba_register_interrupts(device_t dev, device_t child,
+                   struct siba_devinfo *dinfo);
+static int     siba_append_dinfo_region(struct siba_devinfo *dinfo,
+                    uint8_t addridx, uint32_t base, uint32_t size,
+                    uint32_t bus_reserved);
+
 /**
  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
  * code.
@@ -68,48 +74,6 @@ siba_get_bhnd_mfgid(uint16_t ocp_vendor)
 }
 
 /**
- * Parse the SIBA_IDH_* fields from the per-core identification
- * registers, returning a siba_core_id representation.
- * 
- * @param idhigh The SIBA_R0_IDHIGH register.
- * @param idlow The SIBA_R0_IDLOW register. 
- * @param core_id The core id (index) to include in the result.
- * @param unit The unit number to include in the result.
- */
-struct siba_core_id     
-siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
-{
-
-       uint16_t        ocp_vendor;
-       uint8_t         sonics_rev;
-       uint8_t         num_addrspace;
-       uint8_t         num_cfg;
-
-       ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
-       sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
-       num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
-
-       /* Determine the number of sonics config register blocks */
-       num_cfg = SIBA_CFG_NUM_2_2;
-       if (sonics_rev >= SIBA_IDL_SBREV_2_3)
-               num_cfg = SIBA_CFG_NUM_2_3;
-
-       return (struct siba_core_id) {
-               .core_info      = {
-                       .vendor = siba_get_bhnd_mfgid(ocp_vendor),
-                       .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
-                       .hwrev  = SIBA_IDH_CORE_REV(idhigh),
-                       .core_idx = core_idx,
-                       .unit   = unit
-               },
-               .sonics_vendor  = ocp_vendor,
-               .sonics_rev     = sonics_rev,
-               .num_addrspace  = num_addrspace,
-               .num_cfg_blocks = num_cfg
-       };      
-}
-
-/**
  * Allocate and return a new empty device info structure.
  * 
  * @param bus The requesting bus device.
@@ -138,8 +102,12 @@ siba_alloc_dinfo(device_t bus)
        resource_list_init(&dinfo->resources);
 
        dinfo->pmu_state = SIBA_PMU_NONE;
-       dinfo->intr_en = false;
 
+       dinfo->intr = (struct siba_intr) {
+               .mapped = false,
+               .rid = -1
+       };
+
        return dinfo;
 }
 
@@ -148,6 +116,7 @@ siba_alloc_dinfo(device_t bus)
  * siba_alloc_dinfo, copying the provided core id.
  * 
  * @param dev The requesting bus device.
+ * @param child The siba child device.
  * @param dinfo The device info instance.
  * @param core Device core info.
  * 
@@ -155,14 +124,81 @@ siba_alloc_dinfo(device_t bus)
  * @retval non-zero initialization failed.
  */
 int
-siba_init_dinfo(device_t dev, struct siba_devinfo *dinfo,
+siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo,
     const struct siba_core_id *core_id)
 {
+       int error;
+
        dinfo->core_id = *core_id;
+
+       /* Register all address space mappings */
+       for (uint8_t i = 0; i < core_id->num_admatch; i++) {
+               uint32_t bus_reserved;
+
+               /* If this is the device's core/enumeration addrespace,
+                * reserve the Sonics configuration register blocks for the
+                * use of our bus. */
+               bus_reserved = 0;
+               if (i == SIBA_CORE_ADDRSPACE)
+                       bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE;
+
+               /* Append the region info */
+               error = siba_append_dinfo_region(dinfo, i,
+                   core_id->admatch[i].am_base, core_id->admatch[i].am_size,
+                   bus_reserved);
+               if (error)
+                       return (error);
+       }
+
+       /* Register all interrupt(s) */
+       if ((error = siba_register_interrupts(dev, child, dinfo)))
+               return (error);
+
        return (0);
 }
 
+
 /**
+ * Register and map all interrupts for @p dinfo.
+ *
+ * @param dev The siba bus device.
+ * @param child The siba child device.
+ * @param dinfo The device info instance on which to register all interrupt
+ * entries.
+ */
+static int
+siba_register_interrupts(device_t dev, device_t child,
+     struct siba_devinfo *dinfo)
+{
+       int error;
+
+       /* Is backplane interrupt distribution enabled for this core? */
+       if (!dinfo->core_id.intr_en)
+               return (0);
+
+       /* Have one interrupt */
+       dinfo->intr.mapped = false;
+       dinfo->intr.irq = 0;
+       dinfo->intr.rid = -1;
+
+       /* Map the interrupt */
+       error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
+           &dinfo->intr.irq);
+       if (error) {
+               device_printf(dev, "failed mapping interrupt line for core %u: "
+                   "%d\n", dinfo->core_id.core_info.core_idx, error);
+               return (error);
+       }
+       dinfo->intr.mapped = true;
+
+       /* Update the resource list */
+       dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
+           dinfo->intr.irq, dinfo->intr.irq, 1);
+
+       return (0);
+}
+
+/**
  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
  * number.
  * 
@@ -238,7 +274,7 @@ siba_port_count(struct siba_core_id *core_id, bhnd_por
        switch (port_type) {
        case BHND_PORT_DEVICE:
                /* 0, 1, or 2 ports */
-               return (min(core_id->num_addrspace, 2));
+               return (min(core_id->num_admatch, 2));
 
        case BHND_PORT_AGENT:
                /* One agent port maps all configuration blocks */
@@ -292,11 +328,11 @@ siba_port_region_count(struct siba_core_id *core_id, b
        case BHND_PORT_DEVICE:
                /* The first address space, if any, is mapped to device0.0 */
                if (port == 0)
-                       return (min(core_id->num_addrspace, 1));
+                       return (min(core_id->num_admatch, 1));
 
                /* All remaining address spaces are mapped to device0.(n - 1) */
-               if (port == 1 && core_id->num_addrspace >= 2)
-                       return (core_id->num_addrspace - 1);
+               if (port == 1 && core_id->num_admatch >= 2)
+                       return (core_id->num_admatch - 1);
 
                break;
 
@@ -327,7 +363,6 @@ siba_port_region_count(struct siba_core_id *core_id, b
  *     agent0.0        0
  *     agent0.1        1
  * 
- * @param num_addrspace The number of available siba address spaces.
  * @param port_type The bhnd(4) port type.
  * @param port The bhnd(4) port number.
  * @param region The bhnd(4) port region.
@@ -394,7 +429,7 @@ siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_p
  * For compatibility with bcma(4), we map address spaces to port/region
  * identifiers as follows:
  * 
- *     [port]          [addrspace]
+ *     [port.region]   [admatch index]
  *     device0.0       0
  *     device1.0       1
  *     device1.1       2
@@ -431,7 +466,7 @@ siba_addrspace_index(struct siba_core_id *core_id, bhn
        else
                return (ENOENT);
 
-       if (idx >= core_id->num_addrspace)
+       if (idx >= core_id->num_admatch)
                return (ENOENT);
 
        /* Found */
@@ -484,7 +519,7 @@ siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_p
  * @retval 0 success
  * @retval non-zero An error occurred appending the entry.
  */
-int
+static int
 siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
     uint32_t base, uint32_t size, uint32_t bus_reserved)
 {
@@ -546,7 +581,7 @@ siba_free_dinfo(device_t dev, device_t child, struct s
        }
 
        /* Unmap the core's interrupt */
-       if (dinfo->intr_en && dinfo->intr.mapped) {
+       if (dinfo->core_id.intr_en && dinfo->intr.mapped) {
                BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
                dinfo->intr.mapped = false;
        }
@@ -585,36 +620,38 @@ siba_admatch_offset(uint8_t addrspace)
  * 
  * @param addrspace The address space index.
  * @param am The address match register value to be parsed.
- * @param[out] addr The parsed address.
- * @param[out] size The parsed size.
+ * @param[out] admatch The parsed address match descriptor
  * 
  * @retval 0 success
  * @retval non-zero a parse error occurred.
  */
 int
-siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
+siba_parse_admatch(uint32_t am, struct siba_admatch *admatch)
 {
-       u_int           am_type;
+       u_int am_type;
        
-       /* Negative encoding is not supported. This is not used on any
-        * currently known devices*/
-       if (am & SIBA_AM_ADNEG)
-               return (EINVAL);
-       
        /* Extract the base address and size */
        am_type = SIBA_REG_GET(am, AM_TYPE);
        switch (am_type) {
        case 0:
-               *addr = am & SIBA_AM_BASE0_MASK;
-               *size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
+               /* Type 0 entries are always enabled, and do not support
+                * negative matching */
+               admatch->am_base = am & SIBA_AM_BASE0_MASK;
+               admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
+               admatch->am_enabled = true;
+               admatch->am_negative = false;
                break;
        case 1:
-               *addr = am & SIBA_AM_BASE1_MASK;
-               *size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
+               admatch->am_base = am & SIBA_AM_BASE1_MASK;
+               admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
+               admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
+               admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
                break;
        case 2:
-               *addr = am & SIBA_AM_BASE2_MASK;
-               *size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
+               admatch->am_base = am & SIBA_AM_BASE2_MASK;
+               admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
+               admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
+               admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
                break;
        default:
                return (EINVAL);

Modified: head/sys/dev/bhnd/siba/sibavar.h
==============================================================================
--- head/sys/dev/bhnd/siba/sibavar.h    Mon Feb 12 19:08:17 2018        
(r329179)
+++ head/sys/dev/bhnd/siba/sibavar.h    Mon Feb 12 19:36:26 2018        
(r329180)
@@ -37,6 +37,7 @@
 #define _SIBA_SIBAVAR_H_
 
 #include <sys/param.h>
+#include <sys/bitstring.h>
 #include <sys/bus.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
@@ -52,6 +53,7 @@
  */
 
 struct siba_addrspace;
+struct siba_admatch;
 struct siba_cfg_block;
 struct siba_devinfo;
 struct siba_core_id;
@@ -68,13 +70,10 @@ int                  siba_get_intr_ivec(device_t dev, 
device_t child
 
 uint16_t                siba_get_bhnd_mfgid(uint16_t ocp_vendor);
 
-struct siba_core_id     siba_parse_core_id(uint32_t idhigh, uint32_t idlow,
-                            u_int core_idx, int unit);
-
 int                     siba_add_children(device_t bus);
 
 struct siba_devinfo    *siba_alloc_dinfo(device_t dev);
-int                     siba_init_dinfo(device_t dev,
+int                     siba_init_dinfo(device_t dev, device_t child,
                             struct siba_devinfo *dinfo,
                             const struct siba_core_id *core_id);
 void                    siba_free_dinfo(device_t dev, device_t child,
@@ -109,13 +108,9 @@ struct siba_addrspace      *siba_find_addrspace(struct siba

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

Reply via email to