Index: sys/dev/bhnd/bhnd.h =================================================================== --- sys/dev/bhnd/bhnd.h +++ 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,7 +330,37 @@ 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, + device_t child); +bool bhnd_bus_generic_is_hw_disabled(device_t dev, + device_t child); +bool bhnd_bus_generic_is_region_valid(device_t dev, + device_t child, bhnd_port_type type, + u_int port, u_int region); +int bhnd_bus_generic_read_nvram_var(device_t dev, + device_t child, const char *name, + void *buf, size_t *size); +const struct bhnd_chipid *bhnd_bus_generic_get_chipid(device_t dev, + device_t child); +struct bhnd_resource *bhnd_bus_generic_alloc_resource (device_t dev, + device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, + rman_res_t count, u_int flags); +int bhnd_bus_generic_release_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); +int bhnd_bus_generic_activate_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); +int bhnd_bus_generic_deactivate_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); + /** Index: sys/dev/bhnd/bhnd.c =================================================================== --- sys/dev/bhnd/bhnd.c +++ sys/dev/bhnd/bhnd.c @@ -90,11 +90,10 @@ const void *rhs); /** - * Helper function for implementing DEVICE_ATTACH(). - * - * This function can be used to implement DEVICE_ATTACH() for bhnd(4) - * bus implementations. It calls device_probe_and_attach() for each - * of the device's children, in order. + * Default bhnd(4) bus driver implementation of DEVICE_ATTACH(). + * + * This implementation calls device_probe_and_attach() for each of the device's + * children, in bhnd probe order. */ int bhnd_generic_attach(device_t dev) @@ -120,12 +119,11 @@ } /** - * Helper function for implementing DEVICE_DETACH(). - * - * This function can be used to implement DEVICE_DETACH() for bhnd(4) - * bus implementations. It calls device_detach() for each - * of the device's children, in reverse order, terminating if - * any call to device_detach() fails. + * Default bhnd(4) bus driver implementation of DEVICE_DETACH(). + * + * This implementation calls device_detach() for each of the the device's + * children, in reverse bhnd probe order, terminating if any call to + * device_detach() fails. */ int bhnd_generic_detach(device_t dev) @@ -156,12 +154,11 @@ } /** - * Helper function for implementing DEVICE_SHUTDOWN(). + * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN(). * - * This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4) - * bus implementations. It calls device_shutdown() for each - * of the device's children, in reverse order, terminating if - * any call to device_shutdown() fails. + * This implementation calls device_shutdown() for each of the device's + * children, in reverse bhnd probe order, terminating if any call to + * device_shutdown() fails. */ int bhnd_generic_shutdown(device_t dev) @@ -192,12 +189,11 @@ } /** - * Helper function for implementing DEVICE_RESUME(). - * - * This function can be used to implement DEVICE_RESUME() for bhnd(4) - * bus implementations. It calls BUS_RESUME_CHILD() for each - * of the device's children, in order, terminating if - * any call to BUS_RESUME_CHILD() fails. + * Default bhnd(4) bus driver implementation of DEVICE_RESUME(). + * + * This implementation calls BUS_RESUME_CHILD() for each of the device's + * children in bhnd probe order, terminating if any call to BUS_RESUME_CHILD() + * fails. */ int bhnd_generic_resume(device_t dev) @@ -227,14 +223,13 @@ } /** - * Helper function for implementing DEVICE_SUSPEND(). - * - * This function can be used to implement DEVICE_SUSPEND() for bhnd(4) - * bus implementations. It calls BUS_SUSPEND_CHILD() for each - * of the device's children, in reverse order. If any call to - * BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and - * any devices that were suspended are resumed immediately by calling - * their BUS_RESUME_CHILD() methods. + * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND(). + * + * This implementation calls BUS_SUSPEND_CHILD() for each of the device's + * children in reverse bhnd probe order. If any call to BUS_SUSPEND_CHILD() + * fails, the suspend operation is terminated and any devices that were + * suspended are resumed immediately by calling their BUS_RESUME_CHILD() + * methods. */ int bhnd_generic_suspend(device_t dev) @@ -305,8 +300,8 @@ } /** - * Helper function for implementing BHND_BUS_GET_PROBE_ORDER(). - * + * Default bhnd(4) bus driver implementation of BHND_BUS_GET_PROBE_ORDER(). + * * This implementation determines probe ordering based on the device's class * and other properties, including whether the device is serving as a host * bridge. @@ -360,14 +355,14 @@ } /** - * Helper function for implementing BHND_BUS_IS_REGION_VALID(). + * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID(). * * This implementation assumes that port and region numbers are 0-indexed and * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall * within the defined range. */ -bool +static bool bhnd_generic_is_region_valid(device_t dev, device_t child, bhnd_port_type type, u_int port, u_int region) { @@ -413,14 +408,14 @@ } /** - * Helper function for implementing BHND_BUS_READ_NVRAM_VAR(). + * Default bhnd(4) bus driver implementation of BHND_BUS_READ_NVRAM_VAR(). * * This implementation searches @p dev for a valid NVRAM device. If no NVRAM * child device is found on @p dev, the request is delegated to the * BHND_BUS_READ_NVRAM_VAR() method on the parent * of @p dev. */ -int +static int bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name, void *buf, size_t *size) { @@ -435,7 +430,7 @@ } /** - * Helper function for implementing BUS_PRINT_CHILD(). + * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD(). * * This implementation requests the device's struct resource_list via * BUS_GET_RESOURCE_LIST. @@ -463,7 +458,7 @@ } /** - * Helper function for implementing BUS_PRINT_CHILD(). + * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH(). * * This implementation requests the device's struct resource_list via * BUS_GET_RESOURCE_LIST. @@ -525,7 +520,7 @@ } /** - * Default implementation of implementing BUS_PRINT_CHILD(). + * Default implementation of BUS_CHILD_LOCATION_STR(). */ static int bhnd_child_location_str(device_t dev, device_t child, char *buf, @@ -585,215 +580,6 @@ return bus_generic_resume_child(dev, child); } -/** - * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE(). - * - * If a parent device is available, this implementation delegates the - * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev. - * - * If no parent device is available (i.e. on a the bus root), false - * is returned. - */ -bool -bhnd_generic_is_hostb_device(device_t dev, device_t child) { - if (device_get_parent(dev) != NULL) - return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), - child)); - - return (false); -} - -/** - * Helper function for implementing BHND_BUS_IS_HW_DISABLED(). - * - * If a parent device is available, this implementation delegates the - * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev. - * - * If no parent device is available (i.e. on a the bus root), the hardware - * is assumed to be usable and false is returned. - */ -bool -bhnd_generic_is_hw_disabled(device_t dev, device_t child) -{ - if (device_get_parent(dev) != NULL) - return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); - - return (false); -} - -/** - * Helper function for implementing BHND_BUS_GET_CHIPID(). - * - * This implementation delegates the request to the BHND_BUS_GET_CHIPID() - * method on the parent of @p dev. - */ -const struct bhnd_chipid * -bhnd_generic_get_chipid(device_t dev, device_t child) { - return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); -} - -/** - * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). - * - * This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines - * any default values via BUS_GET_RESOURCE_LIST(), and calls - * BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev. - * - * If no parent device is available, the request is instead delegated to - * BUS_ALLOC_RESOURCE(). - */ -struct bhnd_resource * -bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type, - int *rid, rman_res_t start, rman_res_t end, rman_res_t count, - u_int flags) -{ - struct bhnd_resource *r; - struct resource_list *rl; - struct resource_list_entry *rle; - bool isdefault; - bool passthrough; - - passthrough = (device_get_parent(child) != dev); - isdefault = RMAN_IS_DEFAULT_RANGE(start, end); - - /* the default RID must always be the first device port/region. */ - if (!passthrough && *rid == 0) { - int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0); - KASSERT(*rid == rid0, - ("rid 0 does not map to the first device port (%d)", rid0)); - } - - /* Determine locally-known defaults before delegating the request. */ - if (!passthrough && isdefault) { - /* fetch resource list from child's bus */ - rl = BUS_GET_RESOURCE_LIST(dev, child); - if (rl == NULL) - return (NULL); /* no resource list */ - - /* look for matching type/rid pair */ - rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), - type, *rid); - if (rle == NULL) - return (NULL); - - /* set default values */ - start = rle->start; - end = rle->end; - count = ulmax(count, rle->count); - } - - /* Try to delegate to our parent. */ - if (device_get_parent(dev) != NULL) { - return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child, - type, rid, start, end, count, flags)); - } - - /* If this is the bus root, use a real bus-allocated resource */ - r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); - if (r == NULL) - return NULL; - - /* Allocate the bus resource, marking it as 'direct' (not requiring - * any bus window remapping to perform I/O) */ - r->direct = true; - r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, - count, flags); - - if (r->res == NULL) { - free(r, M_BHND); - return NULL; - } - - return (r); -} - -/** - * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). - * - * This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the - * BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev. - * - * If no parent device is available, the request is delegated to - * BUS_RELEASE_RESOURCE(). - */ -int -bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type, - int rid, struct bhnd_resource *r) -{ - int error; - - /* Try to delegate to the parent. */ - if (device_get_parent(dev) != NULL) - return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child, - type, rid, r)); - - /* Release the resource directly */ - if (!r->direct) { - panic("bhnd indirect resource released without " - "bhnd parent bus"); - } - - error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res); - if (error) - return (error); - - free(r, M_BHND); - return (0); -} - -/** - * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). - * - * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the - * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. - * - * If no parent device is available, the request is delegated to - * BUS_ACTIVATE_RESOURCE(). - */ -int -bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type, - int rid, struct bhnd_resource *r) -{ - /* Try to delegate to the parent */ - if (device_get_parent(dev) != NULL) - return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), - child, type, rid, r)); - - /* Activate the resource directly */ - if (!r->direct) { - panic("bhnd indirect resource released without " - "bhnd parent bus"); - } - - return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res)); -}; - -/** - * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). - * - * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the - * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. - * - * If no parent device is available, the request is delegated to - * BUS_DEACTIVATE_RESOURCE(). - */ -int -bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type, - int rid, struct bhnd_resource *r) -{ - if (device_get_parent(dev) != NULL) - return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), - child, type, rid, r)); - - /* De-activate the resource directly */ - if (!r->direct) { - panic("bhnd indirect resource released without " - "bhnd parent bus"); - } - - return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res)); -}; - /* * Delegate all indirect I/O to the parent device. When inherited by * non-bridged bus implementations, resources will never be marked as @@ -885,12 +671,12 @@ DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), /* BHND interface */ - DEVMETHOD(bhnd_bus_alloc_resource, bhnd_generic_alloc_bhnd_resource), - DEVMETHOD(bhnd_bus_release_resource, bhnd_generic_release_bhnd_resource), - DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_activate_bhnd_resource), - DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_deactivate_bhnd_resource), - DEVMETHOD(bhnd_bus_get_chipid, bhnd_generic_get_chipid), + DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid), DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), + DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), + DEVMETHOD(bhnd_bus_is_hostb_device, bhnd_bus_generic_is_hostb_device), + DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), + DEVMETHOD(bhnd_bus_read_nvram_var, bhnd_generic_read_nvram_var), DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), Index: sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- sys/dev/bhnd/bhnd_bus_if.m +++ sys/dev/bhnd/bhnd_bus_if.m @@ -52,7 +52,25 @@ static struct bhnd_chipid * bhnd_bus_null_get_chipid(device_t dev, device_t child) { - panic("bhnd_get_chipid unimplemented"); + panic("bhnd_bus_get_chipid unimplemented"); + } + + static bool + bhnd_bus_null_is_hostb_device(device_t dev, device_t child) + { + panic("bhnd_bus_is_hostb_device unimplemented"); + } + + static bool + bhnd_bus_null_is_hw_disabled(device_t dev, device_t child) + { + panic("bhnd_bus_is_hw_disabled unimplemented"); + } + + static int + bhnd_bus_null_get_probe_order(device_t dev, device_t child) + { + panic("bhnd_bus_get_probe_order unimplemented"); } static int @@ -68,7 +86,7 @@ { return (ENOENT); } - + static int bhnd_bus_null_get_region_addr(device_t dev, device_t child, bhnd_port_type type, u_int port, u_int region, bhnd_addr_t *addr, @@ -83,6 +101,7 @@ { return (ENOENT); } + } /** @@ -98,7 +117,7 @@ METHOD bool is_hostb_device { device_t dev; device_t child; -} DEFAULT bhnd_generic_is_hostb_device; +} DEFAULT bhnd_bus_null_is_hostb_device; /** * Return true if the hardware components required by @p child are unpopulated @@ -115,7 +134,7 @@ METHOD bool is_hw_disabled { device_t dev; device_t child; -} DEFAULT bhnd_generic_is_hw_disabled; +} DEFAULT bhnd_bus_null_is_hw_disabled; /** * Return the probe (and attach) order for @p child. @@ -147,7 +166,7 @@ METHOD int get_probe_order { device_t dev; device_t child; -} DEFAULT bhnd_generic_get_probe_order; +} DEFAULT bhnd_bus_null_get_probe_order; /** * Return the BHND chip identification for the parent bus. @@ -205,7 +224,7 @@ rman_res_t end; rman_res_t count; u_int flags; -} DEFAULT bhnd_generic_alloc_bhnd_resource; +} DEFAULT bhnd_bus_generic_alloc_resource; /** * Release a bhnd resource. @@ -219,7 +238,7 @@ int type; int rid; struct bhnd_resource *res; -} DEFAULT bhnd_generic_release_bhnd_resource; +} DEFAULT bhnd_bus_generic_release_resource; /** * Activate a bhnd resource. @@ -233,7 +252,7 @@ int type; int rid; struct bhnd_resource *r; -} DEFAULT bhnd_generic_activate_bhnd_resource; +} DEFAULT bhnd_bus_generic_activate_resource; /** * Deactivate a bhnd resource. @@ -247,7 +266,7 @@ int type; int rid; struct bhnd_resource *r; -} DEFAULT bhnd_generic_deactivate_bhnd_resource; +} DEFAULT bhnd_bus_generic_deactivate_resource; /** * Return true if @p region_num is a valid region on @p port_num of @@ -259,13 +278,13 @@ * @param port_num The port number being queried. * @param region_num The region number being queried. */ -METHOD u_int is_region_valid { +METHOD bool is_region_valid { device_t dev; device_t child; bhnd_port_type type; u_int port_num; u_int region_num; -} DEFAULT bhnd_generic_is_region_valid; +}; /** * Return the number of ports of type @p type attached to @p child. @@ -278,7 +297,7 @@ device_t dev; device_t child; bhnd_port_type type; -} +}; /** * Return the number of memory regions mapped to @p child @p port of @@ -294,7 +313,7 @@ device_t child; bhnd_port_type type; u_int port; -} +}; /** * Return the SYS_RES_MEMORY resource-ID for a port/region pair attached to Index: sys/dev/bhnd/bhnd_subr.c =================================================================== --- sys/dev/bhnd/bhnd_subr.c +++ 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); @@ -646,3 +721,172 @@ device_set_desc(dev, dev_name); } } + +/** + * 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 + * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev. + * + * If no parent device is available (i.e. on a the bus root), false + * is returned. + */ +bool +bhnd_bus_generic_is_hostb_device(device_t dev, device_t child) { + if (device_get_parent(dev) != NULL) + return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), + child)); + + return (false); +} + +/** + * Helper function for implementing BHND_BUS_IS_HW_DISABLED(). + * + * If a parent device is available, this implementation delegates the + * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev. + * + * If no parent device is available (i.e. on a the bus root), the hardware + * is assumed to be usable and false is returned. + */ +bool +bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child) +{ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); + + return (false); +} + +/** + * Helper function for implementing BHND_BUS_GET_CHIPID(). + * + * This implementation delegates the request to the BHND_BUS_GET_CHIPID() + * method on the parent of @p dev. If no parent exists, the implementation + * will panic. + */ +const struct bhnd_chipid * +bhnd_bus_generic_get_chipid(device_t dev, device_t child) +{ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); + + panic("missing BHND_BUS_GET_CHIPID()"); +} + +/** + * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). + * + * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation + * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation + * to @p dev's BHND_BUS_ACTIVATE_RESOURCE(). + */ +struct bhnd_resource * +bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type, + int *rid, rman_res_t start, rman_res_t end, rman_res_t count, + u_int flags) +{ + struct bhnd_resource *br; + struct resource *res; + int error; + + br = NULL; + res = NULL; + + /* Allocate the real bus resource (without activating it) */ + res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count, + (flags & ~RF_ACTIVE)); + if (res == NULL) + return (NULL); + + /* Allocate our bhnd resource wrapper. */ + br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); + if (br == NULL) + goto failed; + + br->direct = false; + br->res = res; + + /* Attempt activation */ + if (flags & RF_ACTIVE) { + error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br); + if (error) + goto failed; + } + + return (br); + +failed: + if (res != NULL) + BUS_RELEASE_RESOURCE(dev, child, type, *rid, res); + + free(br, M_BHND); + return (NULL); +} + +/** + * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). + * + * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of + * the backing resource to BUS_RELEASE_RESOURCE(). + */ +int +bhnd_bus_generic_release_resource(device_t dev, device_t child, int type, + int rid, struct bhnd_resource *r) +{ + int error; + + if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res))) + return (error); + + free(r, M_BHND); + return (0); +} + + +/** + * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). + * + * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the + * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. + */ +int +bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type, + int rid, struct bhnd_resource *r) +{ + /* Try to delegate to the parent */ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r)); + + return (EINVAL); +}; + +/** + * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). + * + * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the + * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. + */ +int +bhnd_bus_generic_deactivate_resource(device_t dev, device_t child, + int type, int rid, struct bhnd_resource *r) +{ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r)); + + return (EINVAL); +}; \ No newline at end of file Index: sys/dev/bhnd/bhndb/bhndb.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb.c +++ sys/dev/bhnd/bhndb/bhndb.c @@ -85,8 +85,11 @@ const struct bhndb_hwcfg *cfg, struct bhnd_chipid *result); +bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc, + device_t child); + static struct rman *bhndb_get_rman(struct bhndb_softc *sc, - int type); + device_t child, int type); static int bhndb_init_child_resource(struct resource *r, struct resource *parent, @@ -509,6 +512,7 @@ int bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass) { + struct bhndb_devinfo *dinfo; struct bhndb_softc *sc; const struct bhndb_hwcfg *cfg; int error; @@ -525,45 +529,30 @@ if ((error = bhndb_read_chipid(sc, cfg, &sc->chipid))) return (error); - /* Set up a resource manager for the device's address space. */ - sc->mem_rman.rm_start = 0; - sc->mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT; - sc->mem_rman.rm_type = RMAN_ARRAY; - sc->mem_rman.rm_descr = "BHND I/O memory addresses"; - - if ((error = rman_init(&sc->mem_rman))) { - device_printf(dev, "could not initialize mem_rman\n"); - return (error); - } - - error = rman_manage_region(&sc->mem_rman, 0, BUS_SPACE_MAXADDR_32BIT); - if (error) { - device_printf(dev, "could not configure mem_rman\n"); - goto failed; - } - - /* Initialize basic resource allocation state. */ + /* Populate generic resource allocation state. */ sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg); if (sc->bus_res == NULL) { - error = ENXIO; - goto failed; + return (ENXIO); } /* Attach our bridged bus device */ - sc->bus_dev = device_add_child(dev, devclass_get_name(bhnd_devclass), + sc->bus_dev = BUS_ADD_CHILD(dev, 0, devclass_get_name(bhnd_devclass), -1); if (sc->bus_dev == NULL) { error = ENXIO; goto failed; } + /* Configure address space */ + dinfo = device_get_ivars(sc->bus_dev); + dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED; + + /* Finish attach */ return (bus_generic_attach(dev)); failed: BHNDB_LOCK_DESTROY(sc); - rman_fini(&sc->mem_rman); - if (sc->bus_res != NULL) bhndb_free_resources(sc->bus_res); @@ -680,7 +669,6 @@ return (error); /* Clean up our driver state. */ - rman_fini(&sc->mem_rman); bhndb_free_resources(sc->bus_res); BHNDB_LOCK_DESTROY(sc); @@ -826,24 +814,60 @@ } /** + * Return the address space for the given @p child device. + */ +bhndb_addrspace +bhndb_get_addrspace(struct bhndb_softc *sc, device_t child) +{ + struct bhndb_devinfo *dinfo; + device_t imd_dev; + + /* Find the directly attached parent of the requesting device */ + imd_dev = child; + while (imd_dev != NULL && device_get_parent(imd_dev) != sc->dev) + imd_dev = device_get_parent(imd_dev); + + if (imd_dev == NULL) + panic("bhndb address space request for non-child device %s\n", + device_get_nameunit(child)); + + dinfo = device_get_ivars(imd_dev); + return (dinfo->addrspace); +} + +/** * Return the rman instance for a given resource @p type, if any. * * @param sc The bhndb device state. + * @param child The requesting child. * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...) */ static struct rman * -bhndb_get_rman(struct bhndb_softc *sc, int type) -{ - switch (type) { - case SYS_RES_MEMORY: - return &sc->mem_rman; - case SYS_RES_IRQ: - // TODO - // return &sc->irq_rman; - return (NULL); - default: - return (NULL); - }; +bhndb_get_rman(struct bhndb_softc *sc, device_t child, int type) +{ + switch (bhndb_get_addrspace(sc, child)) { + case BHNDB_ADDRSPACE_NATIVE: + switch (type) { + case SYS_RES_MEMORY: + return (&sc->bus_res->ht_mem_rman); + case SYS_RES_IRQ: + return (NULL); + default: + return (NULL); + }; + + case BHNDB_ADDRSPACE_BRIDGED: + switch (type) { + case SYS_RES_MEMORY: + return (&sc->bus_res->br_mem_rman); + case SYS_RES_IRQ: + // TODO + // return &sc->irq_rman; + return (NULL); + default: + return (NULL); + }; + } } /** @@ -865,6 +889,7 @@ return (NULL); } + dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; resource_list_init(&dinfo->resources); device_set_ivars(child, dinfo); @@ -1023,15 +1048,15 @@ struct resource *rv; struct rman *rm; int error; - bool immed_child, defaults; + bool passthrough, isdefault; sc = device_get_softc(dev); - immed_child = (device_get_parent(child) == dev); - defaults = (start == 0UL && end == ~0UL); + passthrough = (device_get_parent(child) != dev); + isdefault = RMAN_IS_DEFAULT_RANGE(start, end); rle = NULL; /* Populate defaults */ - if (immed_child && defaults) { + if (!passthrough && isdefault) { /* Fetch the resource list entry. */ rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), type, *rid); @@ -1058,11 +1083,11 @@ } /* Validate resource addresses */ - if (start > end || end < start || count > ((end - start) + 1)) + if (start > end || count > ((end - start) + 1)) return (NULL); /* Fetch the resource manager */ - rm = bhndb_get_rman(sc, type); + rm = bhndb_get_rman(sc, child, type); if (rm == NULL) return (NULL); @@ -1080,8 +1105,8 @@ if (error) { device_printf(dev, "failed to activate entry %#x type %d for " - "child %s\n", - *rid, type, device_get_nameunit(child)); + "child %s: %d\n", + *rid, type, device_get_nameunit(child), error); rman_release_resource(rv); @@ -1137,7 +1162,7 @@ error = 0; /* Fetch resource manager */ - rm = bhndb_get_rman(sc, type); + rm = bhndb_get_rman(sc, child, type); if (rm == NULL) return (ENXIO); @@ -1159,7 +1184,8 @@ /** * Initialize child resource @p r with a virtual address, tag, and handle - * copied from @p parent, adjusted to contain only the range defined by @p win. + * copied from @p parent, adjusted to contain only the range defined by + * @p offsize and @p size. * * @param r The register to be initialized. * @param parent The parent bus resource that fully contains the subregion. @@ -1171,7 +1197,6 @@ bhndb_init_child_resource(struct resource *r, struct resource *parent, bhnd_size_t offset, bhnd_size_t size) { - bus_space_handle_t bh, child_bh; bus_space_tag_t bt; uintptr_t vaddr; @@ -1335,13 +1360,39 @@ if (indirect) *indirect = false; + + r_start = rman_get_start(r); + r_size = rman_get_size(r); + + /* Activate native addrspace resources using the host address space */ + if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_NATIVE) { + struct resource *parent; + + /* Find the bridge resource referenced by the child */ + parent = bhndb_find_resource_range(sc->bus_res, r_start, + r_size); + if (parent == NULL) { + device_printf(sc->dev, "host resource not found " + "for 0x%llx-0x%llx\n", + (unsigned long long) r_start, + (unsigned long long) r_start + r_size - 1); + return (ENOENT); + } + + /* Initialize child resource with the real bus values */ + error = bhndb_init_child_resource(r, parent, + r_start - rman_get_start(parent), r_size); + if (error) + return (error); + + /* Try to activate child resource */ + return (rman_activate_resource(r)); + } /* Default to low priority */ dw_priority = BHNDB_PRIORITY_LOW; /* Look for a bus region matching the resource's address range */ - r_start = rman_get_start(r); - r_size = rman_get_size(r); region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); if (region != NULL) dw_priority = region->priority; @@ -1431,7 +1482,7 @@ sc = device_get_softc(dev); - if ((rm = bhndb_get_rman(sc, type)) == NULL) + if ((rm = bhndb_get_rman(sc, child, type)) == NULL) return (EINVAL); /* Mark inactive */ @@ -1439,11 +1490,13 @@ return (error); /* Free any dynamic window allocation. */ - BHNDB_LOCK(sc); - dwa = bhndb_dw_find_resource(sc->bus_res, r); - if (dwa != NULL) - bhndb_dw_release(sc->bus_res, dwa, r); - BHNDB_UNLOCK(sc); + if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { + BHNDB_LOCK(sc); + dwa = bhndb_dw_find_resource(sc->bus_res, r); + if (dwa != NULL) + bhndb_dw_release(sc->bus_res, dwa, r); + BHNDB_UNLOCK(sc); + } return (0); } @@ -1459,66 +1512,14 @@ } /** - * Default bhndb(4) implementation of BHND_BUS_ALLOC_RESOURCE(). - */ -static struct bhnd_resource * -bhndb_alloc_bhnd_resource(device_t dev, device_t child, int type, - int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) -{ - struct bhndb_softc *sc; - struct bhnd_resource *br; - - sc = device_get_softc(dev); - - /* Allocate resource wrapper */ - br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT|M_ZERO); - if (br == NULL) - return (NULL); - - /* Configure */ - br->direct = false; - br->res = bus_alloc_resource(child, type, rid, start, end, count, - flags & ~RF_ACTIVE); - if (br->res == NULL) - goto failed; - - - if (flags & RF_ACTIVE) { - if (bhnd_activate_resource(child, type, *rid, br)) - goto failed; - } - - return (br); - -failed: - if (br->res != NULL) - bus_release_resource(child, type, *rid, br->res); - - free(br, M_BHND); - return (NULL); -} - -/** - * Default bhndb(4) implementation of BHND_BUS_RELEASE_RESOURCE(). - */ -static int -bhndb_release_bhnd_resource(device_t dev, device_t child, - int type, int rid, struct bhnd_resource *r) -{ - int error; - - if ((error = bus_release_resource(child, type, rid, r->res))) - return (error); - - free(r, M_BHND); - return (0); -} - -/** * Default bhndb(4) implementation of BHND_BUS_ACTIVATE_RESOURCE(). + * + * For BHNDB_ADDRSPACE_NATIVE children, all resources may be assumed to + * be actived by the bridge. * - * Attempts to activate a static register window, a dynamic register window, - * or configures @p r as an indirect resource -- in that order. + * For BHNDB_ADDRSPACE_BRIDGED children, attempts to activate a static register + * window, a dynamic register window, or configures @p r as an indirect + * resource -- in that order. */ static int bhndb_activate_bhnd_resource(device_t dev, device_t child, @@ -1526,7 +1527,6 @@ { struct bhndb_softc *sc; struct bhndb_region *region; - bhndb_priority_t r_prio; rman_res_t r_start, r_size; int error; bool indirect; @@ -1539,19 +1539,25 @@ sc = device_get_softc(dev); - /* Fetch the address range's resource priority */ r_start = rman_get_start(r->res); r_size = rman_get_size(r->res); - r_prio = BHNDB_PRIORITY_NONE; - region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); - if (region != NULL) - r_prio = region->priority; - - /* If less than the minimum dynamic window priority, this - * resource should always be indirect. */ - if (r_prio < sc->bus_res->min_prio) - return (0); + /* Verify bridged address range's resource priority, and skip direct + * allocation if the priority is too low. */ + if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { + bhndb_priority_t r_prio; + + region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); + if (region != NULL) + r_prio = region->priority; + else + r_prio = BHNDB_PRIORITY_NONE; + + /* If less than the minimum dynamic window priority, this + * resource should always be indirect. */ + if (r_prio < sc->bus_res->min_prio) + return (0); + } /* Attempt direct activation */ error = bhndb_try_activate_resource(sc, child, type, rid, r->res, @@ -1565,7 +1571,9 @@ r->direct = false; } - if (BHNDB_DEBUG(PRIO)) { + if (BHNDB_DEBUG(PRIO) && + bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) + { device_printf(child, "activated 0x%llx-0x%llx as %s " "resource\n", (unsigned long long) r_start, @@ -1919,8 +1927,6 @@ DEVMETHOD(bhnd_bus_is_hw_disabled, bhndb_is_hw_disabled), DEVMETHOD(bhnd_bus_is_hostb_device, bhndb_is_hostb_device), DEVMETHOD(bhnd_bus_get_chipid, bhndb_get_chipid), - DEVMETHOD(bhnd_bus_alloc_resource, bhndb_alloc_bhnd_resource), - DEVMETHOD(bhnd_bus_release_resource, bhndb_release_bhnd_resource), DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource), DEVMETHOD(bhnd_bus_activate_resource, bhndb_deactivate_bhnd_resource), DEVMETHOD(bhnd_bus_read_1, bhndb_bus_read_1), Index: sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_pci.c +++ 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_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_QUIRK_HWREV_RANGE (0, 5, - BHNDB_PCI_QUIRK_SBINTVEC), + { BHND_HWREV_RANGE (0, 5), + BHNDB_PCI_QUIRK_SBINTVEC }, - BHND_QUIRK_HWREV_GTE (11, - BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI | - BHNDB_PCI_QUIRK_CLKRUN_DSBL), + { 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 } }; @@ -375,10 +379,18 @@ * access to the PCIe SerDes required by the quirk workarounds. */ if (sc->pci_devclass == BHND_DEVCLASS_PCIE) { - sc->mdio = device_add_child(dev, + sc->mdio = BUS_ADD_CHILD(dev, 0, devclass_get_name(bhnd_mdio_pci_devclass), 0); if (sc->mdio == NULL) return (ENXIO); + + error = bus_set_resource(sc->mdio, SYS_RES_MEMORY, 0, + rman_get_start(sc->mem_res) + sc->mem_off + + BHND_PCIE_MDIO_CTL, sizeof(uint32_t)*2); + if (error) { + device_printf(dev, "failed to set MDIO resource\n"); + return (error); + } if ((error = device_probe_and_attach(sc->mdio))) { device_printf(dev, "failed to attach MDIO device\n"); @@ -1021,25 +1033,6 @@ static int bhndb_mdio_pcie_probe(device_t dev) { - struct bhndb_softc *psc; - device_t parent; - - /* Parent must be a bhndb_pcie instance */ - parent = device_get_parent(dev); - if (device_get_driver(parent) != &bhndb_pci_driver) - return (ENXIO); - - /* Parent must have PCIe-Gen1 hostb device */ - psc = device_get_softc(parent); - if (psc->hostb_dev == NULL) - return (ENXIO); - - if (bhnd_get_vendor(psc->hostb_dev) != BHND_MFGID_BCM || - bhnd_get_device(psc->hostb_dev) != BHND_COREID_PCIE) - { - return (ENXIO); - } - device_quiet(dev); return (BUS_PROBE_NOWILDCARD); } @@ -1048,15 +1041,11 @@ bhndb_mdio_pcie_attach(device_t dev) { struct bhndb_pci_softc *psc; - psc = device_get_softc(device_get_parent(dev)); - return (bhnd_mdio_pcie_attach(dev, &psc->bhnd_mem_res, -1, psc->mem_off + BHND_PCIE_MDIO_CTL, (psc->quirks & BHNDB_PCIE_QUIRK_SD_C22_EXTADDR) != 0)); - - return (ENXIO); } static device_method_t bhnd_mdio_pcie_methods[] = { Index: sys/dev/bhnd/bhndb/bhndb_pcivar.h =================================================================== --- sys/dev/bhnd/bhndb/bhndb_pcivar.h +++ 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: sys/dev/bhnd/bhndb/bhndb_private.h =================================================================== --- sys/dev/bhnd/bhndb/bhndb_private.h +++ sys/dev/bhnd/bhndb/bhndb_private.h @@ -50,6 +50,10 @@ struct bhndb_region; struct bhndb_resources; +struct resource *bhndb_find_resource_range( + struct bhndb_resources *br, + rman_res_t start, rman_res_t count); + struct resource *bhndb_find_regwin_resource( struct bhndb_resources *br, const struct bhndb_regwin *win); @@ -167,6 +171,9 @@ device_t parent_dev; /**< parent device */ struct resource_spec *res_spec; /**< parent bus resource specs */ struct resource **res; /**< parent bus resources */ + + struct rman ht_mem_rman; /**< host memory manager */ + struct rman br_mem_rman; /**< bridged memory manager */ STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */ Index: sys/dev/bhnd/bhndb/bhndb_subr.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_subr.c +++ sys/dev/bhnd/bhndb/bhndb_subr.c @@ -183,6 +183,39 @@ } /** + * Find a SYS_RES_MEMORY resource containing the given address range. + * + * @param br The bhndb resource state to search. + * @param start The start address of the range to search for. + * @param count The size of the range to search for. + * + * @retval resource the host resource containing the requested range. + * @retval NULL if no resource containing the requested range can be found. + */ +struct resource * +bhndb_find_resource_range(struct bhndb_resources *br, rman_res_t start, + rman_res_t count) +{ + for (u_int i = 0; br->res_spec[i].type != -1; i++) { + struct resource *r = br->res[i]; + + if (br->res_spec->type != SYS_RES_MEMORY) + continue; + + /* Verify range */ + if (rman_get_start(r) > start) + continue; + + if (rman_get_end(r) < (start + count - 1)) + continue; + + return (r); + } + + return (NULL); +} + +/** * Find the resource containing @p win. * * @param br The bhndb resource state to search. @@ -235,8 +268,11 @@ u_int rnid; int error; bool free_parent_res; + bool free_ht_mem, free_br_mem; free_parent_res = false; + free_ht_mem = false; + free_br_mem = false; r = malloc(sizeof(*r), M_BHND, M_NOWAIT|M_ZERO); if (r == NULL) @@ -249,6 +285,37 @@ r->min_prio = BHNDB_PRIORITY_NONE; STAILQ_INIT(&r->bus_regions); + /* Initialize host address space resource manager. */ + r->ht_mem_rman.rm_start = 0; + r->ht_mem_rman.rm_end = ~0; + r->ht_mem_rman.rm_type = RMAN_ARRAY; + r->ht_mem_rman.rm_descr = "BHNDB host memory"; + if ((error = rman_init(&r->ht_mem_rman))) { + device_printf(r->dev, "could not initialize ht_mem_rman\n"); + goto failed; + } + free_ht_mem = true; + + + /* Initialize resource manager for the bridged address space. */ + r->br_mem_rman.rm_start = 0; + r->br_mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT; + r->br_mem_rman.rm_type = RMAN_ARRAY; + r->br_mem_rman.rm_descr = "BHNDB bridged memory"; + + if ((error = rman_init(&r->br_mem_rman))) { + device_printf(r->dev, "could not initialize br_mem_rman\n"); + goto failed; + } + free_br_mem = true; + + error = rman_manage_region(&r->br_mem_rman, 0, BUS_SPACE_MAXADDR_32BIT); + if (error) { + device_printf(r->dev, "could not configure br_mem_rman\n"); + goto failed; + } + + /* Determine our bridge resource count from the hardware config. */ res_num = 0; for (size_t i = 0; cfg->resource_specs[i].type != -1; i++) @@ -284,6 +351,26 @@ free_parent_res = true; } + /* Add allocated memory resources to our host memory resource manager */ + for (u_int i = 0; r->res_spec[i].type != -1; i++) { + struct resource *res; + + /* skip non-memory resources */ + if (r->res_spec[i].type != SYS_RES_MEMORY) + continue; + + /* add host resource to set of managed regions */ + res = r->res[i]; + error = rman_manage_region(&r->ht_mem_rman, rman_get_start(res), + rman_get_end(res)); + if (error) { + device_printf(r->dev, + "could not register host memory region with " + "ht_mem_rman: %d\n", error); + goto failed; + } + } + /* Fetch the dynamic regwin count and verify that it does not exceed * what is representable via our freelist bitmask. */ r->dwa_count = bhndb_regwin_count(cfg->register_windows, @@ -371,6 +458,12 @@ failed: if (free_parent_res) bus_release_resources(r->parent_dev, r->res_spec, r->res); + + if (free_ht_mem) + rman_fini(&r->ht_mem_rman); + + if (free_br_mem) + rman_fini(&r->br_mem_rman); if (r->res != NULL) free(r->res, M_BHND); @@ -423,6 +516,10 @@ free(region, M_BHND); } + /* Release our resource managers */ + rman_fini(&br->ht_mem_rman); + rman_fini(&br->br_mem_rman); + /* Free backing resource state structures */ free(br->res, M_BHND); free(br->res_spec, M_BHND); Index: sys/dev/bhnd/bhndb/bhndbvar.h =================================================================== --- sys/dev/bhnd/bhndb/bhndbvar.h +++ sys/dev/bhnd/bhndb/bhndbvar.h @@ -65,9 +65,20 @@ int bhnd_generic_br_suspend_child(device_t dev, device_t child); int bhnd_generic_br_resume_child(device_t dev, device_t child); +/** + * bhndb child address space. Children either operate in the bridged + * SoC address space, or within the address space mapped to the host + * device (e.g. the PCI BAR(s)). + */ +typedef enum { + BHNDB_ADDRSPACE_BRIDGED, /**< bridged (SoC) address space */ + BHNDB_ADDRSPACE_NATIVE /**< host address space */ +} bhndb_addrspace; + /** bhndb child instance state */ struct bhndb_devinfo { - struct resource_list resources; /**< child resources. */ + bhndb_addrspace addrspace; /**< child address space. */ + struct resource_list resources; /**< child resources. */ }; /** @@ -85,9 +96,7 @@ if the @p bus_dev has not yet called BHNDB_INIT_FULL_CONFIG() */ - struct rman mem_rman; /**< bridged bus memory manager */ struct mtx sc_mtx; /**< resource lock. */ - struct bhndb_resources *bus_res; /**< bus resource state */ }; Index: sys/dev/bhnd/bhndvar.h =================================================================== --- sys/dev/bhnd/bhndvar.h +++ sys/dev/bhnd/bhndvar.h @@ -70,37 +70,5 @@ device_t child); int bhnd_generic_resume_child(device_t dev, device_t child); - -bool bhnd_generic_is_hostb_device(device_t dev, - device_t child); -bool bhnd_generic_is_hw_disabled(device_t dev, - device_t child); -bool bhnd_generic_is_region_valid(device_t dev, - device_t child, bhnd_port_type type, u_int port, - u_int region); - -int bhnd_generic_read_nvram_var(device_t dev, - device_t child, const char *name, void *buf, - size_t *size); - -const struct bhnd_chipid *bhnd_generic_get_chipid(device_t dev, device_t child); - -struct bhnd_resource *bhnd_generic_alloc_bhnd_resource (device_t dev, - device_t child, int type, int *rid, - rman_res_t start, rman_res_t end, rman_res_t count, - u_int flags); - -int bhnd_generic_release_bhnd_resource (device_t dev, - device_t child, int type, int rid, - struct bhnd_resource *r); - -int bhnd_generic_activate_bhnd_resource (device_t dev, - device_t child, int type, int rid, - struct bhnd_resource *r); - -int bhnd_generic_deactivate_bhnd_resource (device_t dev, - device_t child, int type, int rid, - struct bhnd_resource *r); - #endif /* _BHND_BHNDVAR_H_ */ Index: sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- sys/dev/bhnd/cores/chipc/chipc.c +++ 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; - - 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); - } - } + const struct bhnd_device *id; - return (ENXIO); + id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0])); + if (id == NULL) + 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: sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c =================================================================== --- sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c +++ 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); }