Index: head/sys/dev/bhnd/bcma/bcma.c =================================================================== --- head/sys/dev/bhnd/bcma/bcma.c +++ head/sys/dev/bhnd/bcma/bcma.c @@ -181,14 +181,6 @@ } } -static void -bcma_child_deleted(device_t dev, device_t child) -{ - struct bcma_devinfo *dinfo = device_get_ivars(child); - if (dinfo != NULL) - bcma_free_dinfo(dev, dinfo); -} - static struct resource_list * bcma_get_resource_list(device_t dev, device_t child) { @@ -415,6 +407,19 @@ return (ENOENT); } +static struct bhnd_devinfo * +bcma_alloc_bhnd_dinfo(device_t dev) +{ + struct bcma_devinfo *dinfo = bcma_alloc_dinfo(dev); + return ((struct bhnd_devinfo *)dinfo); +} + +static void +bcma_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo) +{ + bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo); +} + /** * Scan a device enumeration ROM table, adding all valid discovered cores to * the bus. @@ -431,8 +436,7 @@ struct bcma_devinfo *dinfo; device_t child; int error; - - dinfo = NULL; + corecfg = NULL; /* Initialize our reader */ @@ -450,26 +454,20 @@ goto failed; } - /* Allocate per-device bus info */ - dinfo = bcma_alloc_dinfo(bus, corecfg); - if (dinfo == NULL) { - error = ENXIO; - goto failed; - } - - /* The dinfo instance now owns the corecfg value */ - corecfg = NULL; - /* Add the child device */ - child = device_add_child(bus, NULL, -1); + child = BUS_ADD_CHILD(bus, 0, NULL, -1); if (child == NULL) { error = ENXIO; goto failed; } - /* The child device now owns the dinfo pointer */ - device_set_ivars(child, dinfo); - dinfo = NULL; + /* Initialize device ivars */ + dinfo = device_get_ivars(child); + if ((error = bcma_init_dinfo(bus, dinfo, corecfg))) + goto failed; + + /* The dinfo instance now owns the corecfg value */ + corecfg = NULL; /* If pins are floating or the hardware is otherwise * unpopulated, the device shouldn't be used. */ @@ -482,9 +480,6 @@ return (0); failed: - if (dinfo != NULL) - bcma_free_dinfo(bus, dinfo); - if (corecfg != NULL) bcma_free_corecfg(corecfg); @@ -499,13 +494,14 @@ DEVMETHOD(device_detach, bcma_detach), /* Bus interface */ - DEVMETHOD(bus_child_deleted, bcma_child_deleted), DEVMETHOD(bus_read_ivar, bcma_read_ivar), DEVMETHOD(bus_write_ivar, bcma_write_ivar), DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), /* BHND interface */ DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device), + DEVMETHOD(bhnd_bus_alloc_devinfo, bcma_alloc_bhnd_dinfo), + DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo), DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core), DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core), DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), Index: head/sys/dev/bhnd/bcma/bcma_subr.c =================================================================== --- head/sys/dev/bhnd/bcma/bcma_subr.c +++ head/sys/dev/bhnd/bcma/bcma_subr.c @@ -186,28 +186,54 @@ } } + /** - * Allocate and initialize new device info structure, assuming ownership - * of the provided core configuration. + * Allocate and return a new empty device info structure. * * @param bus The requesting bus device. - * @param corecfg Device core configuration. + * + * @retval NULL if allocation failed. */ struct bcma_devinfo * -bcma_alloc_dinfo(device_t bus, struct bcma_corecfg *corecfg) +bcma_alloc_dinfo(device_t bus) { struct bcma_devinfo *dinfo; - dinfo = malloc(sizeof(struct bcma_devinfo), M_BHND, M_NOWAIT); + dinfo = malloc(sizeof(struct bcma_devinfo), M_BHND, M_NOWAIT|M_ZERO); if (dinfo == NULL) - return NULL; + return (NULL); - dinfo->corecfg = corecfg; + dinfo->corecfg = NULL; dinfo->res_agent = NULL; dinfo->rid_agent = -1; resource_list_init(&dinfo->resources); + return (dinfo); +} + +/** + * Initialize a device info structure previously allocated via + * bcma_alloc_dinfo, assuming ownership of the provided core + * configuration. + * + * @param bus The requesting bus device. + * @param dinfo The device info instance. + * @param corecfg Device core configuration; ownership of this value + * will be assumed by @p dinfo. + * + * @retval 0 success + * @retval non-zero initialization failed. + */ +int +bcma_init_dinfo(device_t bus, struct bcma_devinfo *dinfo, + struct bcma_corecfg *corecfg) +{ + KASSERT(dinfo->corecfg == NULL, ("dinfo previously initialized")); + + /* Save core configuration value */ + dinfo->corecfg = corecfg; + /* The device ports must always be initialized first to ensure that * rid 0 maps to the first device port */ bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->dev_ports); @@ -215,7 +241,7 @@ bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->bridge_ports); bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->wrapper_ports); - return dinfo; + return (0); } /** @@ -227,9 +253,11 @@ void bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo) { - bcma_free_corecfg(dinfo->corecfg); resource_list_free(&dinfo->resources); + if (dinfo->corecfg != NULL) + bcma_free_corecfg(dinfo->corecfg); + /* Release agent resource, if any */ if (dinfo->res_agent != NULL) { bhnd_release_resource(bus, SYS_RES_MEMORY, dinfo->rid_agent, Index: head/sys/dev/bhnd/bcma/bcmavar.h =================================================================== --- head/sys/dev/bhnd/bcma/bcmavar.h +++ head/sys/dev/bhnd/bcma/bcmavar.h @@ -69,7 +69,9 @@ struct bcma_sport_list *bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, bhnd_port_type type); -struct bcma_devinfo *bcma_alloc_dinfo(device_t bus, +struct bcma_devinfo *bcma_alloc_dinfo(device_t bus); +int bcma_init_dinfo(device_t bus, + struct bcma_devinfo *dinfo, struct bcma_corecfg *corecfg); void bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo); @@ -132,7 +134,9 @@ * BCMA per-device info */ struct bcma_devinfo { - struct resource_list resources; /**< Slave port memory regions. */ + struct bhnd_devinfo bhnd_dinfo; /**< superclass device info. */ + + struct resource_list resources; /**< Slave port memory regions. */ struct bcma_corecfg *corecfg; /**< IP core/block config */ struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not @@ -147,4 +151,4 @@ device_t hostb_dev; /**< host bridge core, or NULL */ }; -#endif /* _BCMA_BCMAVAR_H_ */ \ No newline at end of file +#endif /* _BCMA_BCMAVAR_H_ */ Index: head/sys/dev/bhnd/bhnd.c =================================================================== --- head/sys/dev/bhnd/bhnd.c +++ head/sys/dev/bhnd/bhnd.c @@ -493,6 +493,54 @@ } /** + * Default bhnd(4) bus driver implementation of BUS_ADD_CHILD(). + * + * This implementation manages internal bhnd(4) state, and must be called + * by subclassing drivers. + */ +device_t +bhnd_generic_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct bhnd_devinfo *dinfo; + device_t child; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); + + if ((dinfo = BHND_BUS_ALLOC_DEVINFO(dev)) == NULL) { + device_delete_child(dev, child); + return (NULL); + } + + device_set_ivars(child, dinfo); + + /* Inform concrete bus driver. */ + BHND_BUS_CHILD_ADDED(dev, child); + + return (child); +} + +/** + * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED(). + * + * This implementation manages internal bhnd(4) state, and must be called + * by subclassing drivers. + */ +void +bhnd_generic_child_deleted(device_t dev, device_t child) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + + sc = device_get_softc(dev); + + /* Free device info */ + if ((dinfo = device_get_ivars(child)) != NULL) + BHND_BUS_FREE_DEVINFO(dev, dinfo); +} + +/** * Helper function for implementing BUS_SUSPEND_CHILD(). * * TODO: Power management @@ -611,6 +659,8 @@ DEVMETHOD(device_resume, bhnd_generic_resume), /* Bus interface */ + DEVMETHOD(bus_add_child, bhnd_generic_add_child), + DEVMETHOD(bus_child_deleted, bhnd_generic_child_deleted), DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), DEVMETHOD(bus_print_child, bhnd_generic_print_child), DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), Index: head/sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m +++ head/sys/dev/bhnd/bhnd_bus_if.m @@ -41,6 +41,7 @@ struct bhnd_board_info; struct bhnd_core_info; struct bhnd_chipid; + struct bhnd_devinfo; struct bhnd_resource; } @@ -67,6 +68,11 @@ { panic("bhnd_bus_read_boardinfo unimplemented"); } + + static void + bhnd_bus_null_child_added(device_t dev, device_t child) + { + } static device_t bhnd_bus_null_find_hostb_device(device_t dev) @@ -228,6 +234,46 @@ } DEFAULT bhnd_bus_null_read_board_info; /** + * Allocate and zero-initialize a buffer suitably sized and aligned for a + * bhnd_devinfo structure. + * + * @param dev The bhnd bus device. + * + * @retval non-NULL success + * @retval NULL allocation failed + */ +METHOD struct bhnd_devinfo * alloc_devinfo { + device_t dev; +}; + +/** + * Release memory previously allocated for @p devinfo. + * + * @param dev The bhnd bus device. + * @param dinfo A devinfo buffer previously allocated via + * BHND_BUS_ALLOC_DEVINFO(). + */ +METHOD void free_devinfo { + device_t dev; + struct bhnd_devinfo *dinfo; +}; + +/** + * Notify a bhnd bus that a child was added. + * + * Called at the end of BUS_ADD_CHILD() to allow the concrete bhnd(4) + * driver instance to initialize any additional driver-specific state for the + * child. + * + * @param dev The bhnd bus whose child is being added. + * @param child The child added to @p dev. + */ +METHOD void child_added { + device_t dev; + device_t child; +} DEFAULT bhnd_bus_null_child_added; + +/** * Reset the device's hardware core. * * @param dev The parent of @p child. Index: head/sys/dev/bhnd/bhndvar.h =================================================================== --- head/sys/dev/bhnd/bhndvar.h +++ head/sys/dev/bhnd/bhndvar.h @@ -46,6 +46,13 @@ DECLARE_CLASS(bhnd_driver); /** + * bhnd per-device info. Must be first member of all subclass + * devinfo structures. + */ +struct bhnd_devinfo { +}; + +/** * bhnd driver instance state. Must be first member of all subclass * softc structures. */ @@ -66,6 +73,10 @@ void bhnd_generic_probe_nomatch(device_t dev, device_t child); +device_t bhnd_generic_add_child(device_t dev, u_int order, + const char *name, int unit); +void bhnd_generic_child_deleted(device_t dev, + device_t child); int bhnd_generic_suspend_child(device_t dev, device_t child); int bhnd_generic_resume_child(device_t dev, Index: head/sys/dev/bhnd/siba/siba.c =================================================================== --- head/sys/dev/bhnd/siba/siba.c +++ head/sys/dev/bhnd/siba/siba.c @@ -206,14 +206,6 @@ } } -static void -siba_child_deleted(device_t dev, device_t child) -{ - struct siba_devinfo *dinfo = device_get_ivars(child); - if (dinfo != NULL) - siba_free_dinfo(dev, dinfo); -} - static struct resource_list * siba_get_resource_list(device_t dev, device_t child) { @@ -436,6 +428,19 @@ return (0); } +static struct bhnd_devinfo * +siba_alloc_bhnd_dinfo(device_t dev) +{ + struct siba_devinfo *dinfo = siba_alloc_dinfo(dev); + return ((struct bhnd_devinfo *)dinfo); +} + +static void +siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo) +{ + siba_free_dinfo(dev, (struct siba_devinfo *)dinfo); +} + /** * Scan the core table and add all valid discovered cores to * the bus. @@ -556,6 +561,13 @@ goto cleanup; } + /* Add the child device */ + child = BUS_ADD_CHILD(dev, 0, NULL, -1); + if (child == NULL) { + error = ENXIO; + goto cleanup; + } + /* Read the core info */ idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW)); @@ -570,27 +582,18 @@ cores[i].unit++; } - /* Allocate per-device bus info */ - dinfo = siba_alloc_dinfo(dev, &cid); - if (dinfo == NULL) { + /* Initialize per-device bus info */ + if ((dinfo = device_get_ivars(child)) == NULL) { error = ENXIO; goto cleanup; } - /* Register the core's address space(s). */ - if ((error = siba_register_addrspaces(dev, dinfo, r))) + if ((error = siba_init_dinfo(dev, dinfo, &cid))) goto cleanup; - /* Add the child device */ - child = device_add_child(dev, NULL, -1); - if (child == NULL) { - error = ENXIO; + /* Register the core's address space(s). */ + if ((error = siba_register_addrspaces(dev, dinfo, r))) goto cleanup; - } - - /* The child device now owns the dinfo pointer */ - device_set_ivars(child, dinfo); - dinfo = NULL; /* If pins are floating or the hardware is otherwise * unpopulated, the device shouldn't be used. */ @@ -606,9 +609,6 @@ if (cores != NULL) free(cores, M_BHND); - if (dinfo != NULL) - siba_free_dinfo(dev, dinfo); - if (r != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rid, r); @@ -624,13 +624,14 @@ DEVMETHOD(device_suspend, siba_suspend), /* Bus interface */ - DEVMETHOD(bus_child_deleted, siba_child_deleted), DEVMETHOD(bus_read_ivar, siba_read_ivar), DEVMETHOD(bus_write_ivar, siba_write_ivar), DEVMETHOD(bus_get_resource_list, siba_get_resource_list), /* BHND interface */ DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device), + DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo), + DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo), DEVMETHOD(bhnd_bus_reset_core, siba_reset_core), DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core), DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count), Index: head/sys/dev/bhnd/siba/siba_subr.c =================================================================== --- head/sys/dev/bhnd/siba/siba_subr.c +++ head/sys/dev/bhnd/siba/siba_subr.c @@ -106,23 +106,21 @@ } /** - * Allocate and initialize new device info structure, copying the - * provided core id. + * Allocate and return a new empty device info structure. * - * @param dev The requesting bus device. - * @param core Device core info. + * @param bus The requesting bus device. + * + * @retval NULL if allocation failed. */ struct siba_devinfo * -siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id) +siba_alloc_dinfo(device_t bus) { struct siba_devinfo *dinfo; - dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT); + dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO); if (dinfo == NULL) return NULL; - dinfo->core_id = *core_id; - for (u_int i = 0; i < nitems(dinfo->cfg); i++) { dinfo->cfg[i] = NULL; dinfo->cfg_rid[i] = -1; @@ -134,6 +132,25 @@ } /** + * Initialize a device info structure previously allocated via + * siba_alloc_dinfo, copying the provided core id. + * + * @param dev The requesting bus device. + * @param dinfo The device info instance. + * @param core Device core info. + * + * @retval 0 success + * @retval non-zero initialization failed. + */ +int +siba_init_dinfo(device_t dev, struct siba_devinfo *dinfo, + const struct siba_core_id *core_id) +{ + dinfo->core_id = *core_id; + return (0); +} + +/** * Map an addrspace index to its corresponding bhnd(4) port number. * * @param addrspace Address space index. Index: head/sys/dev/bhnd/siba/sibavar.h =================================================================== --- head/sys/dev/bhnd/siba/sibavar.h +++ head/sys/dev/bhnd/siba/sibavar.h @@ -63,7 +63,9 @@ int siba_add_children(device_t bus, const struct bhnd_chipid *chipid); -struct siba_devinfo *siba_alloc_dinfo(device_t dev, +struct siba_devinfo *siba_alloc_dinfo(device_t dev); +int siba_init_dinfo(device_t dev, + struct siba_devinfo *dinfo, const struct siba_core_id *core_id); void siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo); @@ -136,6 +138,8 @@ * siba(4) per-device info */ struct siba_devinfo { + struct bhnd_devinfo bhnd_dinfo; /**< superclass device info. */ + struct resource_list resources; /**< per-core memory regions. */ struct siba_core_id core_id; /**< core identification info */ struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */