From owner-svn-src-all@freebsd.org Sat Aug 27 00:03:04 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 912F6B767B3; Sat, 27 Aug 2016 00:03:04 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2F90B697; Sat, 27 Aug 2016 00:03:04 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7R033N3063005; Sat, 27 Aug 2016 00:03:03 GMT (envelope-from landonf@FreeBSD.org) Received: (from landonf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7R032kN062998; Sat, 27 Aug 2016 00:03:02 GMT (envelope-from landonf@FreeBSD.org) Message-Id: <201608270003.u7R032kN062998@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: landonf set sender to landonf@FreeBSD.org using -f From: "Landon J. Fuller" Date: Sat, 27 Aug 2016 00:03:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r304870 - in head/sys: conf dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/chipc/pwrctl dev/bhnd/cores/pmu dev/bhnd/nvram dev/bhnd/pmu dev/bhnd/siba mips/broa... X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 27 Aug 2016 00:03:04 -0000 Author: landonf Date: Sat Aug 27 00:03:02 2016 New Revision: 304870 URL: https://svnweb.freebsd.org/changeset/base/304870 Log: bhnd(4): Initial PMU/PWRCTL power and clock management support. - Added bhnd_pmu driver implementations for PMU and PWRCTL chipsets, derived from Broadcom's ISC-licensed HND code. - Added bhnd bus-level support for routing per-core clock and resource power requests to the PMU device. - Lift ChipCommon support out into the bhnd module, dropping bhnd_chipc. Reviewed by: mizhka Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D7492 Added: head/sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/ head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h (contents, props changed) head/sys/dev/bhnd/cores/pmu/ head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu.h (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h (contents, props changed) head/sys/dev/bhnd/pmu/ Deleted: head/sys/modules/bhnd/cores/bhnd_chipc/ Modified: head/sys/conf/files head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcma_dmp.h head/sys/dev/bhnd/bhnd.c head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_bus_if.m head/sys/dev/bhnd/bhnd_core.h head/sys/dev/bhnd/bhnd_ids.h head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhnd_types.h head/sys/dev/bhnd/bhndb/bhnd_bhndb.c head/sys/dev/bhnd/bhndb/bhndb.c head/sys/dev/bhnd/bhndb/bhndb_pci.c head/sys/dev/bhnd/bhndvar.h head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c head/sys/dev/bhnd/cores/chipc/chipc.c head/sys/dev/bhnd/cores/chipc/chipc.h head/sys/dev/bhnd/cores/chipc/chipc_subr.c head/sys/dev/bhnd/cores/chipc/chipcreg.h head/sys/dev/bhnd/cores/chipc/chipcvar.h head/sys/dev/bhnd/nvram/nvram_map head/sys/dev/bhnd/siba/siba.c head/sys/mips/broadcom/bcm_machdep.c head/sys/modules/bhnd/Makefile head/sys/modules/bhnd/cores/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/conf/files Sat Aug 27 00:03:02 2016 (r304870) @@ -1157,19 +1157,26 @@ dev/bhnd/bcma/bcma_bhndb.c optional bcm dev/bhnd/bcma/bcma_erom.c optional bcma bhnd dev/bhnd/bcma/bcma_nexus.c optional bcma_nexus bcma bhnd dev/bhnd/bcma/bcma_subr.c optional bcma bhnd +dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd +dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd +dev/bhnd/cores/chipc/bhnd_pmu_chipc.c optional bhnd dev/bhnd/cores/chipc/chipc.c optional bhnd dev/bhnd/cores/chipc/chipc_cfi.c optional bhnd cfi dev/bhnd/cores/chipc/chipc_slicer.c optional bhnd cfi | bhnd spibus dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus dev/bhnd/cores/chipc/chipc_subr.c optional bhnd -dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd -dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd +dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c optional bhnd +dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c optional bhnd dev/bhnd/cores/pci/bhnd_pci.c optional bhnd pci dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndb bhnd pci dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndb bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci +dev/bhnd/cores/pmu/bhnd_pmu.c optional bhnd +dev/bhnd/cores/pmu/bhnd_pmu_core.c optional bhnd +dev/bhnd/cores/pmu/bhnd_pmu_if.m optional bhnd +dev/bhnd/cores/pmu/bhnd_pmu_subr.c optional bhnd dev/bhnd/nvram/bhnd_nvram.c optional bhnd dev/bhnd/nvram/bhnd_nvram_common.c optional bhnd dev/bhnd/nvram/bhnd_nvram_cfe.c optional bhnd siba_nexus cfe | \ Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/dev/bhnd/bcma/bcma.c Sat Aug 27 00:03:02 2016 (r304870) @@ -259,6 +259,78 @@ bcma_suspend_core(device_t dev, device_t return (ENXIO); } +static uint32_t +bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width) +{ + struct bcma_devinfo *dinfo; + struct bhnd_resource *r; + + /* Must be a directly attached child core */ + if (device_get_parent(child) != dev) + return (UINT32_MAX); + + /* Fetch the agent registers */ + dinfo = device_get_ivars(child); + if ((r = dinfo->res_agent) == NULL) + return (UINT32_MAX); + + /* Verify bounds */ + if (offset > rman_get_size(r->res)) + return (UINT32_MAX); + + if (rman_get_size(r->res) - offset < width) + return (UINT32_MAX); + + switch (width) { + case 1: + return (bhnd_bus_read_1(r, offset)); + case 2: + return (bhnd_bus_read_2(r, offset)); + case 4: + return (bhnd_bus_read_4(r, offset)); + default: + return (UINT32_MAX); + } +} + +static void +bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val, + u_int width) +{ + struct bcma_devinfo *dinfo; + struct bhnd_resource *r; + + /* Must be a directly attached child core */ + if (device_get_parent(child) != dev) + return; + + /* Fetch the agent registers */ + dinfo = device_get_ivars(child); + if ((r = dinfo->res_agent) == NULL) + return; + + /* Verify bounds */ + if (offset > rman_get_size(r->res)) + return; + + if (rman_get_size(r->res) - offset < width) + return; + + switch (width) { + case 1: + bhnd_bus_write_1(r, offset, val); + break; + case 2: + bhnd_bus_write_2(r, offset, val); + break; + case 4: + bhnd_bus_write_4(r, offset, val); + break; + default: + break; + } +} + static u_int bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) { @@ -473,6 +545,9 @@ bcma_add_children(device_t bus, struct r * unpopulated, the device shouldn't be used. */ if (bhnd_is_hw_disabled(child)) device_disable(child); + + /* Issue bus callback for fully initialized child. */ + BHND_BUS_CHILD_ADDED(bus, child); } /* Hit EOF parsing cores? */ @@ -504,6 +579,8 @@ static device_method_t bcma_methods[] = 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_read_config, bcma_read_config), + DEVMETHOD(bhnd_bus_write_config, bcma_write_config), DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), Modified: head/sys/dev/bhnd/bcma/bcma_dmp.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_dmp.h Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/dev/bhnd/bcma/bcma_dmp.h Sat Aug 27 00:03:02 2016 (r304870) @@ -109,6 +109,19 @@ #define BCMA_DMP_OOBDINWIDTH 0x364 #define BCMA_DMP_OOBDOUTWIDTH 0x368 +/* The exact interpretation of these bits is unverified; these + * are our best guesses as to their use */ +#define BCMA_DMP_OOBSEL_MASK 0xFF /**< OOBSEL config mask */ +#define BCMA_DMP_OOBSEL_0_MASK BCMA_DMP_OOBSEL_MASK +#define BCMA_DMP_OOBSEL_1_MASK BCMA_DMP_OOBSEL_MASK +#define BCMA_DMP_OOBSEL_2_MASK BCMA_DMP_OOBSEL_MASK +#define BCMA_DMP_OOBSEL_3_MASK BCMA_DMP_OOBSEL_MASK +#define BCMA_DMP_OOBSEL_0_SHIFT 0 /**< first OOBSEL config */ +#define BCMA_DMP_OOBSEL_1_SHIFT 8 /**< second OOBSEL config */ +#define BCMA_DMP_OOBSEL_2_SHIFT 16 /**< third OOBSEL config */ +#define BCMA_DMP_OOBSEL_3_SHIFT 24 /**< fouth OOBSEL config */ +#define BCMA_DMP_OOBSEL_EN (1 << 7) /**< enable bit */ + // This was inherited from Broadcom's aidmp.h header // Is it required for any of our use-cases? #if 0 /* defined(IL_BIGENDIAN) && defined(BCMHND74K) */ Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/dev/bhnd/bhnd.c Sat Aug 27 00:03:02 2016 (r304870) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2016 Landon Fuller * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,6 +60,9 @@ __FBSDID("$FreeBSD$"); #include +#include +#include + #include "bhnd_chipc_if.h" #include "bhnd_nvram_if.h" @@ -342,7 +345,7 @@ bhnd_finish_attach(struct bhnd_softc *sc { struct chipc_caps *ccaps; - GIANT_REQUIRED; /* newbus */ + GIANT_REQUIRED; /* for newbus */ KASSERT(bus_current_pass >= BHND_FINISH_ATTACH_PASS, ("bhnd_finish_attach() called in pass %d", bus_current_pass)); @@ -367,10 +370,11 @@ bhnd_finish_attach(struct bhnd_softc *sc } /* Look for a PMU */ - if (ccaps->pmu) { + if (ccaps->pmu || ccaps->pwr_ctrl) { if ((sc->pmu_dev = bhnd_find_pmu(sc)) == NULL) { device_printf(sc->dev, - "warning: PMU device not found\n"); + "attach failed: supported PMU not found\n"); + return (ENXIO); } } @@ -478,8 +482,6 @@ found: static device_t bhnd_find_pmu(struct bhnd_softc *sc) { - struct chipc_caps *ccaps; - /* Make sure we're holding Giant for newbus */ GIANT_REQUIRED; @@ -494,11 +496,6 @@ bhnd_find_pmu(struct bhnd_softc *sc) return (sc->pmu_dev); } - if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) - return (NULL); - - if (!ccaps->pmu) - return (NULL); return (bhnd_find_platform_dev(sc, "bhnd_pmu")); } @@ -626,6 +623,244 @@ bhnd_generic_get_probe_order(device_t de } /** + * Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU(). + */ +int +bhnd_generic_alloc_pmu(device_t dev, device_t child) +{ + struct bhnd_softc *sc; + struct bhnd_resource *br; + struct chipc_caps *ccaps; + struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + struct resource_list *rl; + struct resource_list_entry *rle; + device_t pmu_dev; + bhnd_addr_t r_addr; + bhnd_size_t r_size; + bus_size_t pmu_regs; + int error; + + GIANT_REQUIRED; /* for newbus */ + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + pmu_regs = BHND_CLK_CTL_ST; + + if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) { + device_printf(sc->dev, "alloc_pmu failed: chipc " + "capabilities unavailable\n"); + return (ENXIO); + } + + if ((pmu_dev = bhnd_find_pmu(sc)) == NULL) { + device_printf(sc->dev, + "pmu unavailable; cannot allocate request state\n"); + return (ENXIO); + } + + /* already allocated? */ + if (dinfo->pmu_info != NULL) { + panic("duplicate PMU allocation for %s", + device_get_nameunit(child)); + } + + /* Determine address+size of the core's PMU register block */ + error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr, + &r_size); + if (error) { + device_printf(sc->dev, "error fetching register block info for " + "%s: %d\n", device_get_nameunit(child), error); + return (error); + } + + if (r_size < (pmu_regs + sizeof(uint32_t))) { + device_printf(sc->dev, "pmu offset %#jx would overrun %s " + "register block\n", (uintmax_t)pmu_regs, + device_get_nameunit(child)); + return (ENODEV); + } + + /* Locate actual resource containing the core's register block */ + if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) { + device_printf(dev, "NULL resource list returned for %s\n", + device_get_nameunit(child)); + return (ENXIO); + } + + if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) { + device_printf(dev, "cannot locate core register resource " + "for %s\n", device_get_nameunit(child)); + return (ENXIO); + } + + if (rle->res == NULL) { + device_printf(dev, "core register resource unallocated for " + "%s\n", device_get_nameunit(child)); + return (ENXIO); + } + + if (r_addr+pmu_regs < rman_get_start(rle->res) || + r_addr+pmu_regs >= rman_get_end(rle->res)) + { + device_printf(dev, "core register resource does not map PMU " + "registers at %#jx\n for %s\n", r_addr+pmu_regs, + device_get_nameunit(child)); + return (ENXIO); + } + + /* Adjust PMU register offset relative to the actual start address + * of the core's register block allocation. + * + * XXX: The saved offset will be invalid if bus_adjust_resource is + * used to modify the resource's start address. + */ + if (rman_get_start(rle->res) > r_addr) + pmu_regs -= rman_get_start(rle->res) - r_addr; + else + pmu_regs -= r_addr - rman_get_start(rle->res); + + /* Allocate and initialize PMU info */ + br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); + if (br == NULL) + return (ENOMEM); + + br->res = rle->res; + br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0); + + pm = malloc(sizeof(*dinfo->pmu_info), M_BHND, M_NOWAIT); + if (pm == NULL) { + free(br, M_BHND); + return (ENOMEM); + } + pm->pm_dev = child; + pm->pm_pmu = pmu_dev; + pm->pm_res = br; + pm->pm_regs = pmu_regs; + + dinfo->pmu_info = pm; + return (0); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU(). + */ +int +bhnd_generic_release_pmu(device_t dev, device_t child) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + device_t pmu; + int error; + + GIANT_REQUIRED; /* for newbus */ + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + if ((pmu = bhnd_find_pmu(sc)) == NULL) { + device_printf(sc->dev, + "pmu unavailable; cannot release request state\n"); + return (ENXIO); + } + + /* dispatch release request */ + if (dinfo->pmu_info == NULL) + panic("pmu over-release for %s", device_get_nameunit(child)); + + if ((error = BHND_PMU_CORE_RELEASE(pmu, dinfo->pmu_info))) + return (error); + + /* free PMU info */ + free(dinfo->pmu_info->pm_res, M_BHND); + free(dinfo->pmu_info, M_BHND); + dinfo->pmu_info = NULL; + + return (0); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK(). + */ +int +bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + if ((pm = dinfo->pmu_info) == NULL) + panic("no active PMU request state"); + + /* dispatch request to PMU */ + return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock)); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS(). + */ +int +bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + if ((pm = dinfo->pmu_info) == NULL) + panic("no active PMU request state"); + + /* dispatch request to PMU */ + return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks)); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC(). + */ +int +bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + if ((pm = dinfo->pmu_info) == NULL) + panic("no active PMU request state"); + + /* dispatch request to PMU */ + return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc)); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC(). + */ +int +bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc) +{ + struct bhnd_softc *sc; + struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + if ((pm = dinfo->pmu_info) == NULL) + panic("no active PMU request state"); + + /* dispatch request to PMU */ + return (BHND_PMU_CORE_RELEASE_EXT_RSRC(pm->pm_pmu, pm, rsrc)); +} + + +/** * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID(). * * This implementation assumes that port and region numbers are 0-indexed and @@ -815,13 +1050,21 @@ bhnd_generic_add_child(device_t dev, u_i device_set_ivars(child, dinfo); - /* Inform concrete bus driver. */ - BHND_BUS_CHILD_ADDED(dev, child); - return (child); } /** + * Default bhnd(4) bus driver implementation of BHND_BUS_CHILD_ADDED(). + * + * This implementation manages internal bhnd(4) state, and must be called + * by subclassing drivers. + */ +void +bhnd_generic_child_added(device_t dev, device_t child) +{ +} + +/** * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED(). * * This implementation manages internal bhnd(4) state, and must be called @@ -836,8 +1079,17 @@ bhnd_generic_child_deleted(device_t dev, sc = device_get_softc(dev); /* Free device info */ - if ((dinfo = device_get_ivars(child)) != NULL) + if ((dinfo = device_get_ivars(child)) != NULL) { + if (dinfo->pmu_info != NULL) { + /* Releasing PMU requests automatically would be nice, + * but we can't reference per-core PMU register + * resource after driver detach */ + panic("%s leaked device pmu state\n", + device_get_nameunit(child)); + } + BHND_BUS_FREE_DEVINFO(dev, dinfo); + } /* Clean up platform device references */ if (sc->chipc_dev == child) { @@ -998,9 +1250,20 @@ static device_method_t bhnd_methods[] = /* BHND interface */ DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid), + DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), + DEVMETHOD(bhnd_bus_read_board_info, bhnd_bus_generic_read_board_info), + DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), + + DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu), + DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu), + DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock), + DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks), + DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc), + DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc), + + DEVMETHOD(bhnd_bus_child_added, bhnd_generic_child_added), DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), - DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var), /* BHND interface (bus I/O) */ Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/dev/bhnd/bhnd.h Sat Aug 27 00:03:02 2016 (r304870) @@ -417,6 +417,67 @@ bhnd_get_chipid(device_t dev) { }; /** + * If supported by the chipset, return the clock source for the given clock. + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev A bhnd bus child device. + * @param clock The clock for which a clock source will be returned. + * + * @retval bhnd_clksrc The clock source for @p clock. + * @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its + * clock source is not known to the bus. + */ +static inline bhnd_clksrc +bhnd_pwrctl_get_clksrc(device_t dev, bhnd_clock clock) +{ + return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), dev, clock)); +} + +/** + * If supported by the chipset, gate @p clock + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev A bhnd bus child device. + * @param clock The clock to be disabled. + * + * @retval 0 success + * @retval ENODEV If bus-level clock source management is not supported. + * @retval ENXIO If bus-level management of @p clock is not supported. + */ +static inline int +bhnd_pwrctl_gate_clock(device_t dev, bhnd_clock clock) +{ + return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), dev, clock)); +} + +/** + * If supported by the chipset, ungate @p clock + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev A bhnd bus child device. + * @param clock The clock to be enabled. + * + * @retval 0 success + * @retval ENODEV If bus-level clock source management is not supported. + * @retval ENXIO If bus-level management of @p clock is not supported. + */ +static inline int +bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock clock) +{ + return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), dev, + clock)); +} + +/** * Return the BHND attachment type of the parent bhnd bus. * * @param dev A bhnd bus child device. @@ -454,6 +515,171 @@ bhnd_read_board_info(device_t dev, struc } /** + * Allocate and enable per-core PMU request handling for @p child. + * + * The region containing the core's PMU register block (if any) must be + * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before + * calling bhnd_alloc_pmu(), and must not be released until after + * calling bhnd_release_pmu(). + * + * @param dev The parent of @p child. + * @param child The requesting bhnd device. + * + * @retval 0 success + * @retval non-zero If allocating PMU request state otherwise fails, a + * regular unix error code will be returned. + */ +static inline int +bhnd_alloc_pmu(device_t dev) +{ + return (BHND_BUS_ALLOC_PMU(device_get_parent(dev), dev)); +} + +/** + * Release any per-core PMU resources allocated for @p child. Any outstanding + * PMU requests are are discarded. + * + * @param dev The parent of @p child. + * @param child The requesting bhnd device. + * + * @retval 0 success + * @retval non-zero If releasing PMU request state otherwise fails, a + * regular unix error code will be returned, and + * the core state will be left unmodified. + */ +static inline int +bhnd_release_pmu(device_t dev) +{ + return (BHND_BUS_RELEASE_PMU(device_get_parent(dev), dev)); +} + +/** + * Request that @p clock (or faster) be routed to @p dev. + * + * A driver must ask the bhnd bus to allocate clock request state + * via bhnd_alloc_pmu() before it can request clock resources. + * + * Request multiplexing is managed by the bus. + * + * @param dev The bhnd(4) device to which @p clock should be routed. + * @param clock The requested clock source. + * + * @retval 0 success + * @retval ENODEV If an unsupported clock was requested. + * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + */ +static inline int +bhnd_request_clock(device_t dev, bhnd_clock clock) +{ + return (BHND_BUS_REQUEST_CLOCK(device_get_parent(dev), dev, clock)); +} + +/** + * Request that @p clocks be powered on behalf of @p dev. + * + * This will power any clock sources (e.g. XTAL, PLL, etc) required for + * @p clocks and wait until they are ready, discarding any previous + * requests by @p dev. + * + * Request multiplexing is managed by the bus. + * + * A driver must ask the bhnd bus to allocate clock request state + * via bhnd_alloc_pmu() before it can request clock resources. + * + * @param dev The requesting bhnd(4) device. + * @param clocks The clock(s) to be enabled. + * + * @retval 0 success + * @retval ENODEV If an unsupported clock was requested. + * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + */ +static inline int +bhnd_enable_clocks(device_t dev, uint32_t clocks) +{ + return (BHND_BUS_ENABLE_CLOCKS(device_get_parent(dev), dev, clocks)); +} + +/** + * Power up an external PMU-managed resource assigned to @p dev. + * + * A driver must ask the bhnd bus to allocate PMU request state + * via bhnd_alloc_pmu() before it can request PMU resources. + * + * @param dev The requesting bhnd(4) device. + * @param rsrc The core-specific external resource identifier. + * + * @retval 0 success + * @retval ENODEV If the PMU does not support @p rsrc. + * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + */ +static inline int +bhnd_request_ext_rsrc(device_t dev, u_int rsrc) +{ + return (BHND_BUS_REQUEST_EXT_RSRC(device_get_parent(dev), dev, rsrc)); +} + +/** + * Power down an external PMU-managed resource assigned to @p dev. + * + * A driver must ask the bhnd bus to allocate PMU request state + * via bhnd_alloc_pmu() before it can request PMU resources. + * + * @param dev The requesting bhnd(4) device. + * @param rsrc The core-specific external resource identifier. + * + * @retval 0 success + * @retval ENODEV If the PMU does not support @p rsrc. + * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + */ +static inline int +bhnd_release_ext_rsrc(device_t dev, u_int rsrc) +{ + return (BHND_BUS_RELEASE_EXT_RSRC(device_get_parent(dev), dev, rsrc)); +} + + +/** + * Read @p width bytes at @p offset from the bus-specific agent/config + * space of @p dev. + * + * @param dev The bhnd device for which @p offset should be read. + * @param offset The offset to be read. + * @param width The size of the access. Must be 1, 2 or 4 bytes. + * + * The exact behavior of this method is bus-specific. In the case of + * bcma(4), this method provides access to the first agent port of @p child. + * + * @note Device drivers should only use this API for functionality + * that is not available via another bhnd(4) function. + */ +static inline uint32_t +bhnd_read_config(device_t dev, bus_size_t offset, u_int width) +{ + return (BHND_BUS_READ_CONFIG(device_get_parent(dev), dev, offset, + width)); +} + +/** + * Read @p width bytes at @p offset from the bus-specific agent/config + * space of @p dev. + * + * @param dev The bhnd device for which @p offset should be read. + * @param offset The offset to be written. + * @param width The size of the access. Must be 1, 2 or 4 bytes. + * + * The exact behavior of this method is bus-specific. In the case of + * bcma(4), this method provides access to the first agent port of @p child. + * + * @note Device drivers should only use this API for functionality + * that is not available via another bhnd(4) function. + */ +static inline void +bhnd_write_config(device_t dev, bus_size_t offset, uint32_t val, u_int width) +{ + BHND_BUS_WRITE_CONFIG(device_get_parent(dev), dev, offset, val, width); +} + +/** * Read an NVRAM variable, coerced to the requested @p type. * * @param dev A bhnd bus child device. Modified: head/sys/dev/bhnd/bhnd_bus_if.m ============================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m Fri Aug 26 23:50:44 2016 (r304869) +++ head/sys/dev/bhnd/bhnd_bus_if.m Sat Aug 27 00:03:02 2016 (r304870) @@ -61,6 +61,27 @@ CODE { { panic("bhnd_bus_get_attach_type unimplemented"); } + + static bhnd_clksrc + bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child, + bhnd_clock clock) + { + return (BHND_CLKSRC_UNKNOWN); + } + + static int + bhnd_bus_null_pwrctl_gate_clock(device_t dev, device_t child, + bhnd_clock clock) + { + return (ENODEV); + } + + static int + bhnd_bus_null_pwrctl_ungate_clock(device_t dev, device_t child, + bhnd_clock clock) + { + return (ENODEV); + } static int bhnd_bus_null_read_board_info(device_t dev, device_t child, @@ -74,6 +95,60 @@ CODE { { } + static int + bhnd_bus_null_alloc_pmu(device_t dev, device_t child) + { + panic("bhnd_bus_alloc_pmu unimplemented"); + } + + static int + bhnd_bus_null_release_pmu(device_t dev, device_t child) + { + panic("bhnd_bus_release_pmu unimplemented"); + } + + static int + bhnd_bus_null_request_clock(device_t dev, device_t child, + bhnd_clock clock) + { + panic("bhnd_bus_request_clock unimplemented"); + } + + static int + bhnd_bus_null_enable_clocks(device_t dev, device_t child, + uint32_t clocks) + { + panic("bhnd_bus_enable_clocks unimplemented"); + } + + static int + bhnd_bus_null_request_ext_rsrc(device_t dev, device_t child, + u_int rsrc) + { + panic("bhnd_bus_request_ext_rsrc unimplemented"); + } + + static int + bhnd_bus_null_release_ext_rsrc(device_t dev, device_t child, + u_int rsrc) + { + panic("bhnd_bus_release_ext_rsrc unimplemented"); + } + + static uint32_t + bhnd_bus_null_read_config(device_t dev, device_t child, + bus_size_t offset, u_int width) + { + panic("bhnd_bus_null_read_config unimplemented"); + } + + static void + bhnd_bus_null_write_config(device_t dev, device_t child, + bus_size_t offset, uint32_t val, u_int width) + { + panic("bhnd_bus_null_write_config unimplemented"); + } + static device_t bhnd_bus_null_find_hostb_device(device_t dev) { @@ -261,9 +336,8 @@ METHOD void free_devinfo { /** * 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. + * This method must be called by concrete bhnd(4) driver impementations + * after @p child's bus state is fully initialized. * * @param dev The bhnd bus whose child is being added. * @param child The child added to @p dev. @@ -304,6 +378,230 @@ METHOD int suspend_core { } /** + * If supported by the chipset, return the clock source for the given clock. + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting a clock source. + * @param clock The clock for which a clock source will be returned. + * + * @retval bhnd_clksrc The clock source for @p clock. + * @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its + * clock source is not known to the bus. + */ +METHOD bhnd_clksrc pwrctl_get_clksrc { + device_t dev; + device_t child; + bhnd_clock clock; +} DEFAULT bhnd_bus_null_pwrctl_get_clksrc; + +/** + * If supported by the chipset, gate the clock source for @p clock + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting clock gating. + * @param clock The clock to be disabled. + * + * @retval 0 success + * @retval ENODEV If bus-level clock source management is not supported. + * @retval ENXIO If bus-level management of @p clock is not supported. + */ +METHOD int pwrctl_gate_clock { + device_t dev; + device_t child; + bhnd_clock clock; +} DEFAULT bhnd_bus_null_pwrctl_gate_clock; + +/** + * If supported by the chipset, ungate the clock source for @p clock + * + * This function is only supported on early PWRCTL-equipped chipsets + * that expose clock management via their host bridge interface. Currently, + * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting clock gating. + * @param clock The clock to be enabled. + * + * @retval 0 success + * @retval ENODEV If bus-level clock source management is not supported. + * @retval ENXIO If bus-level management of @p clock is not supported. + */ +METHOD int pwrctl_ungate_clock { + device_t dev; + device_t child; + bhnd_clock clock; +} DEFAULT bhnd_bus_null_pwrctl_ungate_clock; + +/** + * Allocate and enable per-core PMU request handling for @p child. + * + * The region containing the core's PMU register block (if any) must be + * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before + * calling BHND_BUS_ALLOC_PMU(), and must not be released until after + * calling BHND_BUS_RELEASE_PMU(). + * + * @param dev The parent of @p child. + * @param child The requesting bhnd device. + */ +METHOD int alloc_pmu { + device_t dev; + device_t child; +} DEFAULT bhnd_bus_null_alloc_pmu; + +/** + * Release per-core PMU resources allocated for @p child. Any + * outstanding PMU requests are discarded. + * + * @param dev The parent of @p child. + * @param child The requesting bhnd device. + */ +METHOD int release_pmu { + device_t dev; + device_t child; +} DEFAULT bhnd_bus_null_release_pmu; + +/** + * Request that @p clock (or faster) be routed to @p child. + * + * A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before it can request clock resources. + * + * Request multiplexing is managed by the bus. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting @p clock. + * @param clock The requested clock source. + * + * @retval 0 success + * @retval ENODEV If an unsupported clock was requested. + * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + */ +METHOD int request_clock { + device_t dev; + device_t child; + bhnd_clock clock; +} DEFAULT bhnd_bus_null_request_clock; + +/** + * Request that @p clocks be powered on behalf of @p child. + * + * This will power on clock sources (e.g. XTAL, PLL, etc) required for + * @p clocks and wait until they are ready, discarding any previous + * requests by @p child. + * + * Request multiplexing is managed by the bus. + * + * A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before it can request clock resources. + * *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***