Index: head/sys/dev/bhnd/bhnd.h =================================================================== --- head/sys/dev/bhnd/bhnd.h +++ head/sys/dev/bhnd/bhnd.h @@ -167,72 +167,104 @@ /** * Wildcard hardware revision match descriptor. */ -#define BHND_HWREV_MATCH_ANY { BHND_HWREV_INVALID, BHND_HWREV_INVALID } - - -/** A core match descriptor. */ -struct bhnd_core_match { - uint16_t vendor; /**< required JEP106 device vendor or BHND_MFGID_INVALID. */ - uint16_t device; /**< required core ID or BHND_COREID_INVALID */ - struct bhnd_hwrev_match hwrev; /**< matching revisions. */ - bhnd_devclass_t class; /**< required class or BHND_DEVCLASS_INVALID */ - int unit; /**< required core unit, or -1 */ -}; - +#define BHND_HWREV_ANY { BHND_HWREV_INVALID, BHND_HWREV_INVALID } +#define BHND_HWREV_IS_ANY(_m) \ + ((_m)->start == BHND_HWREV_INVALID && (_m)->end == BHND_HWREV_INVALID) /** - * Revision-specific hardware quirk descriptor. - * - * Defines a set of quirk flags applicable to a range of hardware - * revisions. - */ -struct bhnd_device_quirk { - struct bhnd_hwrev_match hwrev; /**< applicable hardware revisions */ - uint32_t quirks; /**< applicable quirk flags */ -}; - -/** - * Define a bhnd_device_quirk over a range of hardware revisions. + * Hardware revision match descriptor for an inclusive range. * * @param _start The first applicable hardware revision. * @param _end The last applicable hardware revision, or BHND_HWREV_INVALID * to match on any revision. - * @param _quirks Quirk flags applicable to this revision range. */ -#define BHND_QUIRK_HWREV_RANGE(_start, _end, _quirks) \ - { .hwrev = { _start, _end }, .quirks = _quirks } +#define BHND_HWREV_RANGE(_start, _end) { _start, _end } /** - * Define a bhnd_device_quirk for a specific hardware revision. + * Hardware revision match descriptor for a single revision. * * @param _hwrev The hardware revision to match on. - * @param _quirks Quirk flags applicable to this revision. */ -#define BHND_QUIRK_HWREV_EQ(_hwrev, _quirks) \ - BHND_QUIRK_HWREV_RANGE(_hwrev, _hwrev, _quirks) +#define BHND_HWREV_EQ(_hwrev) BHND_HWREV_RANGE(_hwrev, _hwrev) /** - * Define a bhnd_device_quirk for any hardware revision equal or greater + * Hardware revision match descriptor for any revision equal to or greater * than @p _start. * * @param _start The first hardware revision to match on. - * @param _quirks Quirk flags applicable to this revision. */ -#define BHND_QUIRK_HWREV_GTE(_start, _quirks) \ - BHND_QUIRK_HWREV_RANGE(_start, BHND_HWREV_INVALID, _quirks) +#define BHND_HWREV_GTE(_start) BHND_HWREV_RANGE(_start, BHND_HWREV_INVALID) /** - * Define a bhnd_device_quirk for any hardware revision equal or less + * Hardware revision match descriptor for any revision equal to or less * than @p _end. * * @param _end The last hardware revision to match on. - * @param _quirks Quirk flags applicable to this revision. */ -#define BHND_QUIRK_HWREV_LTE(_end, _quirks) \ - BHND_QUIRK_HWREV_RANGE(0, _end, _quirks) +#define BHND_HWREV_LTE(_end) BHND_HWREV_RANGE(0, _end) + + +/** A core match descriptor. */ +struct bhnd_core_match { + uint16_t vendor; /**< required JEP106 device vendor or BHND_MFGID_INVALID. */ + uint16_t device; /**< required core ID or BHND_COREID_INVALID */ + struct bhnd_hwrev_match hwrev; /**< matching revisions. */ + bhnd_devclass_t class; /**< required class or BHND_DEVCLASS_INVALID */ + int unit; /**< required core unit, or -1 */ +}; + +/** + * Core match descriptor matching against the given @p _vendor, @p _device, + * and @p _hwrev match descriptors. + */ +#define BHND_CORE_MATCH(_vendor, _device, _hwrev) \ + { _vendor, _device, _hwrev, BHND_DEVCLASS_INVALID, -1 } -/** Mark the end of a bhnd_device_quirk table. */ -#define BHND_QUIRK_HWREV_END { BHND_HWREV_MATCH_ANY, 0 } +/** + * Wildcard core match descriptor. + */ +#define BHND_CORE_MATCH_ANY \ + { \ + .vendor = BHND_MFGID_INVALID, \ + .device = BHND_COREID_INVALID, \ + .hwrev = BHND_HWREV_ANY, \ + .class = BHND_DEVCLASS_INVALID, \ + .unit = -1 \ + } + +/** + * Device quirk table descriptor. + */ +struct bhnd_device_quirk { + struct bhnd_hwrev_match hwrev; /**< applicable hardware revisions */ + uint32_t quirks; /**< quirk flags */ +}; +#define BHND_DEVICE_QUIRK_END { BHND_HWREV_ANY, 0 } +#define BHND_DEVICE_QUIRK_IS_END(_q) \ + (BHND_HWREV_IS_ANY(&(_q)->hwrev) && (_q)->quirks == 0) + +enum { + BHND_DF_ANY = 0, + BHND_DF_HOSTB = (1<<0) /**< core is serving as the bus' + * host bridge */ +}; + +/** Device probe table descriptor */ +struct bhnd_device { + const struct bhnd_core_match core; /**< core match descriptor */ + const char *desc; /**< device description, or NULL. */ + const struct bhnd_device_quirk *quirks_table; /**< quirks table for this device, or NULL */ + uint32_t device_flags; /**< required BHND_DF_* flags */ +}; + +#define _BHND_DEVICE(_device, _desc, _quirks, _flags, ...) \ + { BHND_CORE_MATCH(BHND_MFGID_BCM, BHND_COREID_ ## _device, \ + BHND_HWREV_ANY), _desc, _quirks, _flags } + +#define BHND_DEVICE(_device, _desc, _quirks, ...) \ + _BHND_DEVICE(_device, _desc, _quirks, ## __VA_ARGS__, 0) + +#define BHND_DEVICE_END { BHND_CORE_MATCH_ANY, NULL, NULL, 0 } const char *bhnd_vendor_name(uint16_t vendor); const char *bhnd_port_type_name(bhnd_port_type port_type); @@ -271,6 +303,14 @@ bool bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc); +const struct bhnd_device *bhnd_device_lookup(device_t dev, + const struct bhnd_device *table, + size_t entry_size); + +uint32_t bhnd_device_quirks(device_t dev, + const struct bhnd_device *table, + size_t entry_size); + struct bhnd_core_info bhnd_get_core_info(device_t dev); @@ -290,9 +330,9 @@ bus_size_t chipc_offset, struct bhnd_chipid *result); -void bhnd_set_generic_core_desc(device_t dev); - - +void bhnd_set_custom_core_desc(device_t dev, + const char *name); +void bhnd_set_default_core_desc(device_t dev); bool bhnd_bus_generic_is_hostb_device(device_t dev, Index: head/sys/dev/bhnd/bhnd_subr.c =================================================================== --- head/sys/dev/bhnd/bhnd_subr.c +++ head/sys/dev/bhnd/bhnd_subr.c @@ -470,6 +470,85 @@ } /** + * Search @p table for an entry matching @p dev. + * + * @param dev A bhnd device to match against @p table. + * @param table The device table to search. + * @param entry_size The @p table entry size, in bytes. + * + * @retval bhnd_device the first matching device, if any. + * @retval NULL if no matching device is found in @p table. + */ +const struct bhnd_device * +bhnd_device_lookup(device_t dev, const struct bhnd_device *table, + size_t entry_size) +{ + const struct bhnd_device *entry; + + for (entry = table; entry->desc != NULL; entry = + (const struct bhnd_device *) ((const char *) entry + entry_size)) + { + /* match core info */ + if (!bhnd_device_matches(dev, &entry->core)) + continue; + + /* match device flags */ + if (entry->device_flags & BHND_DF_HOSTB) { + if (!bhnd_is_hostb_device(dev)) + continue; + } + + /* device found */ + return (entry); + } + + /* not found */ + return (NULL); +} + +/** + * Scan @p table for all quirk flags applicable to @p dev. + * + * @param dev A bhnd device to match against @p table. + * @param table The device table to search. + * @param entry_size The @p table entry size, in bytes. + * + * @return returns all matching quirk flags. + */ +uint32_t +bhnd_device_quirks(device_t dev, const struct bhnd_device *table, + size_t entry_size) +{ + const struct bhnd_device *dent; + const struct bhnd_device_quirk *qtable, *qent; + uint32_t quirks; + uint16_t hwrev; + + hwrev = bhnd_get_hwrev(dev); + quirks = 0; + + /* Find the quirk table */ + if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL) { + /* This is almost certainly a (caller) implementation bug */ + device_printf(dev, "quirk lookup did not match any device\n"); + return (0); + } + + /* Quirks aren't a mandatory field */ + if ((qtable = dent->quirks_table) == NULL) + return (0); + + /* Collect matching quirk entries */ + for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) { + if (bhnd_hwrev_matches(hwrev, &qent->hwrev)) + quirks |= qent->quirks; + } + + return (quirks); +} + + +/** * Allocate bhnd(4) resources defined in @p rs from a parent bus. * * @param dev The device requesting ownership of the resources. @@ -619,25 +698,21 @@ } /** - * Using the bhnd(4) bus-level core information, populate @p dev's device - * description. + * Using the bhnd(4) bus-level core information and a custom core name, + * populate @p dev's device description. * * @param dev A bhnd-bus attached device. + * @param dev_name The core's name (e.g. "SDIO Device Core") */ void -bhnd_set_generic_core_desc(device_t dev) +bhnd_set_custom_core_desc(device_t dev, const char *dev_name) { - const char *dev_name; const char *vendor_name; char *desc; vendor_name = bhnd_get_vendor_name(dev); - dev_name = bhnd_get_device_name(dev); - - asprintf(&desc, M_BHND, "%s %s, rev %hhu", - bhnd_get_vendor_name(dev), - bhnd_get_device_name(dev), - bhnd_get_hwrev(dev)); + asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name, + bhnd_get_hwrev(dev)); if (desc != NULL) { device_set_desc_copy(dev, desc); @@ -648,6 +723,18 @@ } /** + * Using the bhnd(4) bus-level core information, populate @p dev's device + * description. + * + * @param dev A bhnd-bus attached device. + */ +void +bhnd_set_default_core_desc(device_t dev) +{ + bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev)); +} + +/** * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE(). * * If a parent device is available, this implementation delegates the Index: head/sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c +++ head/sys/dev/bhnd/bhndb/bhndb_pci.c @@ -111,56 +111,60 @@ */ static const struct bhndb_pci_id bhndb_pci_ids[] = { /* PCI */ - BHNDB_PCI_ID(PCI, - BHND_QUIRK_HWREV_GTE (0, - BHNDB_PCI_QUIRK_EXT_CLOCK_GATING | - BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST), - - BHND_QUIRK_HWREV_RANGE (0, 5, - BHNDB_PCI_QUIRK_SBINTVEC), - - BHND_QUIRK_HWREV_GTE (11, - BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI | - BHNDB_PCI_QUIRK_CLKRUN_DSBL), + { BHND_COREID_PCI, BHND_PCI_REGFMT_PCI, + (struct bhnd_device_quirk[]) { + { BHND_HWREV_GTE (0), + BHNDB_PCI_QUIRK_EXT_CLOCK_GATING | + BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST }, + + { BHND_HWREV_RANGE (0, 5), + BHNDB_PCI_QUIRK_SBINTVEC }, + + { BHND_HWREV_GTE (11), + BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI | + BHNDB_PCI_QUIRK_CLKRUN_DSBL }, - BHND_QUIRK_HWREV_END - ), + BHND_DEVICE_QUIRK_END + } + }, /* PCI Gen 1 */ - BHNDB_PCI_ID(PCIE, - BHND_QUIRK_HWREV_EQ (0, - BHNDB_PCIE_QUIRK_SDR9_L0s_HANG), + { BHND_COREID_PCIE, BHND_PCI_REGFMT_PCIE, + (struct bhnd_device_quirk[]) { + { BHND_HWREV_EQ (0), + BHNDB_PCIE_QUIRK_SDR9_L0s_HANG }, - BHND_QUIRK_HWREV_RANGE (0, 1, - BHNDB_PCIE_QUIRK_UR_STATUS_FIX), + { BHND_HWREV_RANGE (0, 1), + BHNDB_PCIE_QUIRK_UR_STATUS_FIX }, - BHND_QUIRK_HWREV_EQ (1, - BHNDB_PCIE_QUIRK_PCIPM_REQEN), + { BHND_HWREV_EQ (1), + BHNDB_PCIE_QUIRK_PCIPM_REQEN }, - BHND_QUIRK_HWREV_RANGE (3, 5, - BHNDB_PCIE_QUIRK_ASPM_OVR | - BHNDB_PCIE_QUIRK_SDR9_POLARITY | - BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY), + { BHND_HWREV_RANGE (3, 5), + BHNDB_PCIE_QUIRK_ASPM_OVR | + BHNDB_PCIE_QUIRK_SDR9_POLARITY | + BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY }, - BHND_QUIRK_HWREV_LTE (6, - BHNDB_PCIE_QUIRK_L1_IDLE_THRESH), + { BHND_HWREV_LTE (6), + BHNDB_PCIE_QUIRK_L1_IDLE_THRESH }, - BHND_QUIRK_HWREV_GTE (6, - BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET), + { BHND_HWREV_GTE (6), + BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET }, - BHND_QUIRK_HWREV_EQ (7, - BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN), + { BHND_HWREV_EQ (7), + BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN }, - BHND_QUIRK_HWREV_GTE (8, - BHNDB_PCIE_QUIRK_L1_TIMER_PERF), + { BHND_HWREV_GTE (8), + BHNDB_PCIE_QUIRK_L1_TIMER_PERF }, - BHND_QUIRK_HWREV_GTE (10, - BHNDB_PCIE_QUIRK_SD_C22_EXTADDR), + { BHND_HWREV_GTE (10), + BHNDB_PCIE_QUIRK_SD_C22_EXTADDR }, - BHND_QUIRK_HWREV_END - ), + BHND_DEVICE_QUIRK_END + } + }, - { BHND_COREID_INVALID, BHND_PCI_REGFMT_PCI, NULL } + { BHND_COREID_INVALID, BHND_PCI_REGFMT_PCI } }; Index: head/sys/dev/bhnd/bhndb/bhndb_pcivar.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pcivar.h +++ head/sys/dev/bhnd/bhndb/bhndb_pcivar.h @@ -97,15 +97,6 @@ } sdr9_quirk_polarity; }; -/* Declare a bhndb_pci_id entry */ -#define BHNDB_PCI_ID(_device, _desc, ...) { \ - BHND_COREID_ ## _device, \ - BHND_PCI_REGFMT_ ## _device, \ - (struct bhnd_device_quirk[]) { \ - __VA_ARGS__ \ - } \ -} - /* * PCI/PCIe-Gen1 endpoint-mode device quirks */ Index: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c +++ head/sys/dev/bhnd/cores/chipc/chipc.c @@ -62,21 +62,22 @@ { -1, -1, 0 } }; +static struct bhnd_device_quirk chipc_quirks[]; + /* Supported device identifiers */ -static const struct chipc_device { - uint16_t device; -} chipc_devices[] = { - { BHND_COREID_CC }, - { BHND_COREID_INVALID } +static const struct bhnd_device chipc_devices[] = { + BHND_DEVICE(CC, "", chipc_quirks), + BHND_DEVICE_END }; + /* Device quirks table */ static struct bhnd_device_quirk chipc_quirks[] = { - BHND_QUIRK_HWREV_RANGE (0, 21, CHIPC_QUIRK_ALWAYS_HAS_SPROM), - BHND_QUIRK_HWREV_EQ (22, CHIPC_QUIRK_SPROM_CHECK_CST_R22), - BHND_QUIRK_HWREV_RANGE (23, 31, CHIPC_QUIRK_SPROM_CHECK_CST_R23), - BHND_QUIRK_HWREV_GTE (35, CHIPC_QUIRK_SUPPORTS_NFLASH), - BHND_QUIRK_HWREV_END + { BHND_HWREV_RANGE (0, 21), CHIPC_QUIRK_ALWAYS_HAS_SPROM }, + { BHND_HWREV_EQ (22), CHIPC_QUIRK_SPROM_CHECK_CST_R22 }, + { BHND_HWREV_RANGE (23, 31), CHIPC_QUIRK_SPROM_CHECK_CST_R23 }, + { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_NFLASH }, + BHND_DEVICE_QUIRK_END }; /* quirk and capability flag convenience macros */ @@ -95,25 +96,19 @@ static int chipc_probe(device_t dev) { - const struct chipc_device *id; + const struct bhnd_device *id; - for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++) - { - if (bhnd_get_vendor(dev) == BHND_MFGID_BCM && - bhnd_get_device(dev) == id->device) - { - bhnd_set_generic_core_desc(dev); - return (BUS_PROBE_DEFAULT); - } - } + id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0])); + if (id == NULL) + return (ENXIO); - return (ENXIO); + bhnd_set_default_core_desc(dev); + return (BUS_PROBE_DEFAULT); } static int chipc_attach(device_t dev) { - struct bhnd_device_quirk *dq; struct chipc_softc *sc; bhnd_addr_t enum_addr; uint32_t ccid_reg; @@ -122,6 +117,8 @@ sc = device_get_softc(dev); sc->dev = dev; + sc->quirks = bhnd_device_quirks(dev, chipc_devices, + sizeof(chipc_devices[0])); /* Allocate bus resources */ memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); @@ -155,13 +152,6 @@ sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); - /* Populate the set of applicable quirk flags */ - sc->quirks = 0; - for (dq = chipc_quirks; dq->quirks != 0; dq++) { - if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev)) - sc->quirks |= dq->quirks; - } - // TODO switch (bhnd_chipc_nvram_src(dev)) { case BHND_NVRAM_SRC_CIS: Index: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c +++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c @@ -68,7 +68,7 @@ if (!bhnd_is_hostb_device(dev)) return (ENXIO); - bhnd_set_generic_core_desc(dev); + bhnd_set_default_core_desc(dev); return (BUS_PROBE_DEFAULT); }