From owner-svn-src-all@freebsd.org Sat Sep 24 04:08:18 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 CD7A1BDCBE1; Sat, 24 Sep 2016 04:08:18 +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 69A78B00; Sat, 24 Sep 2016 04:08:18 +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 u8O48HmR081313; Sat, 24 Sep 2016 04:08:17 GMT (envelope-from landonf@FreeBSD.org) Received: (from landonf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u8O48HGn081306; Sat, 24 Sep 2016 04:08:17 GMT (envelope-from landonf@FreeBSD.org) Message-Id: <201609240408.u8O48HGn081306@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: landonf set sender to landonf@FreeBSD.org using -f From: "Landon J. Fuller" Date: Sat, 24 Sep 2016 04:08:17 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r306287 - in head/sys: dev/bhnd dev/bhnd/bcma dev/bhnd/cores/pmu dev/bhnd/cores/usb dev/bhnd/siba modules/bhnd/bcma modules/bhnd/siba 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.23 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, 24 Sep 2016 04:08:18 -0000 Author: landonf Date: Sat Sep 24 04:08:16 2016 New Revision: 306287 URL: https://svnweb.freebsd.org/changeset/base/306287 Log: bhnd(4): Implement common API for IOST/IOCTL register access and core reset - Added bhnd(4) bus APIs for per-core ioctl/iost register access. - Updated reset/suspend bhnd(4) APIs for compatibility with ioctl/iost changes. - Implemented core reset/suspend support for both bcma(4) and siba(4). - Implemented explicit release of all outstanding PMU requests at the bus level when putting a core into reset. Approved by: adrian (mentor, implicit) Differential Revision: https://reviews.freebsd.org/D8009 Deleted: head/sys/dev/bhnd/bhnd_core.h Modified: head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcma_dmp.h head/sys/dev/bhnd/bcma/bcma_subr.c head/sys/dev/bhnd/bcma/bcmavar.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/bhndvar.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c head/sys/dev/bhnd/cores/pmu/bhnd_pmu.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c head/sys/dev/bhnd/cores/usb/bhnd_usb.c head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba_subr.c head/sys/dev/bhnd/siba/sibareg.h head/sys/dev/bhnd/siba/sibavar.h head/sys/modules/bhnd/bcma/Makefile head/sys/modules/bhnd/siba/Makefile Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bcma/bcma.c Sat Sep 24 04:08:16 2016 (r306287) @@ -39,14 +39,14 @@ __FBSDID("$FreeBSD$"); #include -#include "bcmavar.h" +#include #include "bcma_dmp.h" #include "bcma_eromreg.h" #include "bcma_eromvar.h" -#include +#include "bcmavar.h" /* RID used when allocating EROM table */ #define BCMA_EROM_RID 0 @@ -91,6 +91,44 @@ bcma_detach(device_t dev) return (bhnd_generic_detach(dev)); } +static device_t +bcma_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct bcma_devinfo *dinfo; + device_t child; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); + + if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) { + device_delete_child(dev, child); + return (NULL); + } + + device_set_ivars(child, dinfo); + + return (child); +} + +static void +bcma_child_deleted(device_t dev, device_t child) +{ + struct bhnd_softc *sc; + struct bcma_devinfo *dinfo; + + sc = device_get_softc(dev); + + /* Call required bhnd(4) implementation */ + bhnd_generic_child_deleted(dev, child); + + /* Free bcma device info */ + if ((dinfo = device_get_ivars(child)) != NULL) + bcma_free_dinfo(dev, dinfo); + + device_set_ivars(child, NULL); +} + static int bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { @@ -125,6 +163,9 @@ bcma_read_ivar(device_t dev, device_t ch case BHND_IVAR_CORE_UNIT: *result = ci->unit; return (0); + case BHND_IVAR_PMU_INFO: + *result = (uintptr_t) dinfo->pmu_info; + return (0); default: return (ENOENT); } @@ -133,6 +174,10 @@ bcma_read_ivar(device_t dev, device_t ch static int bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) { + struct bcma_devinfo *dinfo; + + dinfo = device_get_ivars(child); + switch (index) { case BHND_IVAR_VENDOR: case BHND_IVAR_DEVICE: @@ -143,6 +188,9 @@ bcma_write_ivar(device_t dev, device_t c case BHND_IVAR_CORE_INDEX: case BHND_IVAR_CORE_UNIT: return (EINVAL); + case BHND_IVAR_PMU_INFO: + dinfo->pmu_info = (struct bhnd_core_pmu_info *) value; + return (0); default: return (ENOENT); } @@ -156,136 +204,262 @@ bcma_get_resource_list(device_t dev, dev } static int -bcma_reset_core(device_t dev, device_t child, uint16_t flags) +bcma_read_iost(device_t dev, device_t child, uint16_t *iost) { - struct bcma_devinfo *dinfo; + uint32_t value; + int error; + + if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4))) + return (error); + + /* Return only the bottom 16 bits */ + *iost = (value & BCMA_DMP_IOST_MASK); + return (0); +} + +static int +bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl) +{ + uint32_t value; + int error; + + if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4))) + return (error); + + /* Return only the bottom 16 bits */ + *ioctl = (value & BCMA_DMP_IOCTRL_MASK); + return (0); +} + +static int +bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask) +{ + struct bcma_devinfo *dinfo; + struct bhnd_resource *r; + uint32_t ioctl; if (device_get_parent(child) != dev) - BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); + return (EINVAL); dinfo = device_get_ivars(child); - - /* Can't reset the core without access to the agent registers */ - if (dinfo->res_agent == NULL) + if ((r = dinfo->res_agent) == NULL) return (ENODEV); - /* Start reset */ - bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, BHND_RESET_CF_ENABLE); - bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF); - DELAY(10); + /* Write new value */ + ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); + ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask); + ioctl |= (value & mask); - /* Disable clock */ - bhnd_bus_write_4(dinfo->res_agent, BHND_CF, flags); - bhnd_bus_read_4(dinfo->res_agent, BHND_CF); - DELAY(10); + bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl); - /* Enable clocks & force clock gating */ - bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN | - BHND_CF_FGC | flags); - bhnd_bus_read_4(dinfo->res_agent, BHND_CF); + /* Perform read-back and wait for completion */ + bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); DELAY(10); - /* Complete reset */ - bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, 0); - bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF); - DELAY(10); + return (0); +} - /* Release force clock gating */ - bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN | flags); - bhnd_bus_read_4(dinfo->res_agent, BHND_CF); - DELAY(10); +static bool +bcma_is_hw_suspended(device_t dev, device_t child) +{ + uint32_t rst; + uint16_t ioctl; + int error; + + /* Is core held in RESET? */ + error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4); + if (error) { + device_printf(child, "error reading HW reset state: %d\n", + error); + return (true); + } + + if (rst & BMCA_DMP_RC_RESET) + return (true); + + /* Is core clocked? */ + error = bhnd_read_ioctl(child, &ioctl); + if (error) { + device_printf(child, "error reading HW ioctl register: %d\n", + error); + return (true); + } + + if (!(ioctl & BHND_IOCTL_CLK_EN)) + return (true); + + return (false); +} + +static int +bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl) +{ + struct bcma_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + struct bhnd_resource *r; + int error; + + if (device_get_parent(child) != dev) + return (EINVAL); + + dinfo = device_get_ivars(child); + pm = dinfo->pmu_info; + + /* We require exclusive control over BHND_IOCTL_CLK_EN and + * BHND_IOCTL_CLK_FORCE. */ + if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE)) + return (EINVAL); + + /* Can't suspend the core without access to the agent registers */ + if ((r = dinfo->res_agent) == NULL) + return (ENODEV); + + /* Place core into known RESET state */ + if ((error = BHND_BUS_SUSPEND_HW(dev, child))) + return (error); + + /* + * Leaving the core in reset: + * - Set the caller's IOCTL flags + * - Enable clocks + * - Force clock distribution to ensure propagation throughout the + * core. + */ + error = bhnd_write_ioctl(child, + ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE, UINT16_MAX); + if (error) + return (error); + + /* Bring the core out of reset */ + if ((error = bcma_dmp_write_reset(child, dinfo, 0x0))) + return (error); + + /* Disable forced clock gating (leaving clock enabled) */ + error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE); + if (error) + return (error); return (0); } static int -bcma_suspend_core(device_t dev, device_t child) +bcma_suspend_hw(device_t dev, device_t child) { - struct bcma_devinfo *dinfo; + struct bcma_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; + struct bhnd_resource *r; + uint32_t rst; + int error; if (device_get_parent(child) != dev) - BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); + return (EINVAL); dinfo = device_get_ivars(child); + pm = dinfo->pmu_info; /* Can't suspend the core without access to the agent registers */ - if (dinfo->res_agent == NULL) + if ((r = dinfo->res_agent) == NULL) return (ENODEV); - // TODO - perform suspend + /* Wait for any pending reset operations to clear */ + if ((error = bcma_dmp_wait_reset(child, dinfo))) + return (error); - return (ENXIO); + /* Already in reset? */ + rst = bhnd_bus_read_4(r, BCMA_DMP_RESETCTRL); + if (rst & BMCA_DMP_RC_RESET) + return (0); + + /* Put core into reset */ + if ((error = bcma_dmp_write_reset(child, dinfo, BMCA_DMP_RC_RESET))) + return (error); + + /* Clear core flags */ + if ((error = bhnd_write_ioctl(child, 0x0, UINT16_MAX))) + return (error); + + /* Inform PMU that all outstanding request state should be discarded */ + if (pm != NULL) { + if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm))) + return (error); + } + + return (0); } -static uint32_t -bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width) +static int +bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value, + 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); + return (EINVAL); /* Fetch the agent registers */ dinfo = device_get_ivars(child); if ((r = dinfo->res_agent) == NULL) - return (UINT32_MAX); + return (ENODEV); /* Verify bounds */ if (offset > rman_get_size(r->res)) - return (UINT32_MAX); + return (EFAULT); if (rman_get_size(r->res) - offset < width) - return (UINT32_MAX); + return (EFAULT); switch (width) { case 1: - return (bhnd_bus_read_1(r, offset)); + *((uint8_t *)value) = bhnd_bus_read_1(r, offset); + return (0); case 2: - return (bhnd_bus_read_2(r, offset)); + *((uint16_t *)value) = bhnd_bus_read_2(r, offset); + return (0); case 4: - return (bhnd_bus_read_4(r, offset)); + *((uint32_t *)value) = bhnd_bus_read_4(r, offset); + return (0); default: - return (UINT32_MAX); + return (EINVAL); } } -static void -bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val, - u_int width) +static int +bcma_write_config(device_t dev, device_t child, bus_size_t offset, + const void *value, 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; + return (EINVAL); /* Fetch the agent registers */ dinfo = device_get_ivars(child); if ((r = dinfo->res_agent) == NULL) - return; + return (ENODEV); /* Verify bounds */ if (offset > rman_get_size(r->res)) - return; + return (EFAULT); if (rman_get_size(r->res) - offset < width) - return; + return (EFAULT); switch (width) { case 1: - bhnd_bus_write_1(r, offset, val); - break; + bhnd_bus_write_1(r, offset, *(const uint8_t *)value); + return (0); case 2: - bhnd_bus_write_2(r, offset, val); - break; + bhnd_bus_write_2(r, offset, *(const uint16_t *)value); + return (0); case 4: - bhnd_bus_write_4(r, offset, val); - break; + bhnd_bus_write_4(r, offset, *(const uint32_t *)value); + return (0); default: - break; + return (EINVAL); } } @@ -501,19 +675,6 @@ bcma_get_core_ivec(device_t dev, device_ return (0); } -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 the device enumeration ROM table, adding all valid discovered cores to * the bus. @@ -607,16 +768,20 @@ static device_method_t bcma_methods[] = DEVMETHOD(device_detach, bcma_detach), /* Bus interface */ + DEVMETHOD(bus_add_child, bcma_add_child), + 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_get_erom_class, bcma_get_erom_class), - 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_read_ioctl, bcma_read_ioctl), + DEVMETHOD(bhnd_bus_write_ioctl, bcma_write_ioctl), + DEVMETHOD(bhnd_bus_read_iost, bcma_read_iost), + DEVMETHOD(bhnd_bus_is_hw_suspended, bcma_is_hw_suspended), + DEVMETHOD(bhnd_bus_reset_hw, bcma_reset_hw), + DEVMETHOD(bhnd_bus_suspend_hw, bcma_suspend_hw), 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), Modified: head/sys/dev/bhnd/bcma/bcma_dmp.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_dmp.h Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bcma/bcma_dmp.h Sat Sep 24 04:08:16 2016 (r306287) @@ -245,8 +245,14 @@ #define BCMA_DMP_OOBSEL_6_SHIFT BCMA_DMP_OOBSEL_2_SHIFT #define BCMA_DMP_OOBSEL_7_SHIFT BCMA_DMP_OOBSEL_3_SHIFT +/* ioctrl */ +#define BCMA_DMP_IOCTRL_MASK 0x0000FFFF + +/* iostatus */ +#define BCMA_DMP_IOST_MASK 0x0000FFFF + /* resetctrl */ -#define BMCA_DMP_RC_RESET 1 +#define BMCA_DMP_RC_RESET 0x00000001 /* config */ #define BCMA_DMP_CFG_OOB 0x00000020 Modified: head/sys/dev/bhnd/bcma/bcma_subr.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_subr.c Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bcma/bcma_subr.c Sat Sep 24 04:08:16 2016 (r306287) @@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$"); #include +#include "bcma_dmp.h" + #include "bcmavar.h" /* Return the resource ID for a device's agent register allocation */ @@ -368,3 +370,62 @@ bcma_free_sport(struct bcma_sport *sport free(sport, M_BHND); } + +/** + * Given a bcma(4) child's device info, spin waiting for the device's DMP + * resetstatus register to clear. + * + * @param child The bcma(4) child device. + * @param dinfo The @p child device info. + * + * @retval 0 success + * @retval ENODEV if @p dinfo does not map an agent register resource. + * @retval ETIMEDOUT if timeout occurs + */ +int +bcma_dmp_wait_reset(device_t child, struct bcma_devinfo *dinfo) +{ + uint32_t rst; + + if (dinfo->res_agent == NULL) + return (ENODEV); + + /* 300us should be long enough, but there are references to this + * requiring up to 10ms when performing reset of an 80211 core + * after a MAC PSM microcode watchdog event. */ + for (int i = 0; i < 10000; i += 10) { + rst = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_RESETSTATUS); + if (rst == 0) + return (0); + + DELAY(10); + } + + device_printf(child, "BCMA_DMP_RESETSTATUS timeout\n"); + return (ETIMEDOUT); +} + +/** + * Set the bcma(4) child's DMP resetctrl register value, and then wait + * for all backplane operations to complete. + * + * @param child The bcma(4) child device. + * @param dinfo The @p child device info. + * @param value The new ioctrl value to set. + * + * @retval 0 success + * @retval ENODEV if @p dinfo does not map an agent register resource. + * @retval ETIMEDOUT if timeout occurs waiting for reset completion + */ +int +bcma_dmp_write_reset(device_t child, struct bcma_devinfo *dinfo, uint32_t value) +{ + if (dinfo->res_agent == NULL) + return (ENODEV); + + bhnd_bus_write_4(dinfo->res_agent, BCMA_DMP_RESETCTRL, value); + bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_RESETCTRL); /* read-back */ + DELAY(10); + + return (bcma_dmp_wait_reset(child, dinfo)); +} Modified: head/sys/dev/bhnd/bcma/bcmavar.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcmavar.h Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bcma/bcmavar.h Sat Sep 24 04:08:16 2016 (r306287) @@ -99,6 +99,11 @@ void bcma_free_corecfg(struct bcma_co struct bcma_sport *bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type); void bcma_free_sport(struct bcma_sport *sport); +int bcma_dmp_wait_reset(device_t child, + struct bcma_devinfo *dinfo); +int bcma_dmp_write_reset(device_t child, + struct bcma_devinfo *dinfo, uint32_t value); + /** BCMA master port descriptor */ struct bcma_mport { bcma_pid_t mp_num; /**< AXI port identifier (bus-unique) */ @@ -150,14 +155,14 @@ struct bcma_corecfg { * BCMA per-device info */ struct bcma_devinfo { - 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 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 + * all bcma(4) cores have or require an agent. */ + int rid_agent; /**< Agent resource ID, or -1 */ - struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not - * all bcma(4) cores have or require an agent. */ - int rid_agent; /**< Agent resource ID, or -1 */ + struct bhnd_core_pmu_info *pmu_info; /**< Bus-managed PMU state, or NULL */ }; Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bhnd.c Sat Sep 24 04:08:16 2016 (r306287) @@ -631,7 +631,6 @@ bhnd_generic_alloc_pmu(device_t dev, dev 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; @@ -644,7 +643,7 @@ bhnd_generic_alloc_pmu(device_t dev, dev GIANT_REQUIRED; /* for newbus */ sc = device_get_softc(dev); - dinfo = device_get_ivars(child); + pm = bhnd_get_pmu_info(child); pmu_regs = BHND_CLK_CTL_ST; if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) { @@ -660,7 +659,7 @@ bhnd_generic_alloc_pmu(device_t dev, dev } /* already allocated? */ - if (dinfo->pmu_info != NULL) { + if (pm != NULL) { panic("duplicate PMU allocation for %s", device_get_nameunit(child)); } @@ -728,7 +727,7 @@ bhnd_generic_alloc_pmu(device_t dev, dev br->res = rle->res; br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0); - pm = malloc(sizeof(*dinfo->pmu_info), M_BHND, M_NOWAIT); + pm = malloc(sizeof(*pm), M_BHND, M_NOWAIT); if (pm == NULL) { free(br, M_BHND); return (ENOMEM); @@ -738,7 +737,7 @@ bhnd_generic_alloc_pmu(device_t dev, dev pm->pm_res = br; pm->pm_regs = pmu_regs; - dinfo->pmu_info = pm; + bhnd_set_pmu_info(child, pm); return (0); } @@ -749,14 +748,13 @@ int bhnd_generic_release_pmu(device_t dev, device_t child) { struct bhnd_softc *sc; - struct bhnd_devinfo *dinfo; + struct bhnd_core_pmu_info *pm; 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, @@ -765,16 +763,17 @@ bhnd_generic_release_pmu(device_t dev, d } /* dispatch release request */ - if (dinfo->pmu_info == NULL) + pm = bhnd_get_pmu_info(child); + if (pm == NULL) panic("pmu over-release for %s", device_get_nameunit(child)); - if ((error = BHND_PMU_CORE_RELEASE(pmu, dinfo->pmu_info))) + if ((error = BHND_PMU_CORE_RELEASE(pmu, pm))) return (error); /* free PMU info */ - free(dinfo->pmu_info->pm_res, M_BHND); - free(dinfo->pmu_info, M_BHND); - dinfo->pmu_info = NULL; + bhnd_set_pmu_info(child, NULL); + free(pm->pm_res, M_BHND); + free(pm, M_BHND); return (0); } @@ -786,13 +785,11 @@ 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) + if ((pm = bhnd_get_pmu_info(child)) == NULL) panic("no active PMU request state"); /* dispatch request to PMU */ @@ -806,13 +803,11 @@ 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) + if ((pm = bhnd_get_pmu_info(child)) == NULL) panic("no active PMU request state"); /* dispatch request to PMU */ @@ -826,13 +821,11 @@ 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) + if ((pm = bhnd_get_pmu_info(child)) == NULL) panic("no active PMU request state"); /* dispatch request to PMU */ @@ -846,13 +839,11 @@ 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) + if ((pm = bhnd_get_pmu_info(child)) == NULL) panic("no active PMU request state"); /* dispatch request to PMU */ @@ -1035,43 +1026,6 @@ bhnd_child_location_str(device_t dev, de } /** - * 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); - - 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 @@ -1081,21 +1035,16 @@ 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) { - 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); + if (bhnd_get_pmu_info(child) != 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)); } /* Clean up platform device references */ @@ -1228,7 +1177,6 @@ static device_method_t bhnd_methods[] = /* Bus interface */ DEVMETHOD(bus_new_pass, bhnd_new_pass), - 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), @@ -1269,7 +1217,6 @@ static device_method_t bhnd_methods[] = 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_get_nvram_var, bhnd_generic_get_nvram_var), Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Sat Sep 24 01:21:42 2016 (r306286) +++ head/sys/dev/bhnd/bhnd.h Sat Sep 24 04:08:16 2016 (r306287) @@ -46,6 +46,8 @@ #include "nvram/bhnd_nvram.h" +struct bhnd_core_pmu_info; + extern devclass_t bhnd_devclass; extern devclass_t bhnd_hostb_devclass; extern devclass_t bhnd_nvram_devclass; @@ -67,6 +69,7 @@ enum bhnd_device_vars { BHND_IVAR_CORE_UNIT, /**< Bus-assigned core unit number, assigned sequentially (starting at 0) for each vendor/device pair. */ + BHND_IVAR_PMU_INFO, /**< Internal bus-managed PMU state */ }; /** @@ -99,6 +102,39 @@ enum { }; + +/** + * Per-core IOCTL flags common to all bhnd(4) cores. + */ +enum { + BHND_IOCTL_BIST = 0x8000, /**< Initiate a built-in self-test (BIST). Must be cleared + after BIST results are read via BHND_IOST_BIST_* */ + BHND_IOCTL_PME = 0x4000, /**< Enable posting of power management events by the core. */ + BHND_IOCTL_CFLAGS = 0x3FFC, /**< Reserved for core-specific ioctl flags. */ + BHND_IOCTL_CLK_FORCE = 0x0002, /**< Force disable of clock gating, resulting in all clocks + being distributed within the core. Should be set when + asserting/deasserting reset to ensure the reset signal + fully propagates to the entire core. */ + BHND_IOCTL_CLK_EN = 0x0001, /**< If cleared, the core clock will be disabled. Should be + set during normal operation, and cleared when the core is + held in reset. */ +}; + +/** + * Per-core IOST flags common to all bhnd(4) cores. + */ +enum { + BHND_IOST_BIST_DONE = 0x8000, /**< Set upon BIST completion (see BHND_IOCTL_BIST), and cleared + if 0 is written to BHND_IOCTL_BIST. */ + BHND_IOST_BIST_FAIL = 0x4000, /**< Set upon detection of a BIST error; the value is unspecified + if BIST has not completed and BHND_IOST_BIST_DONE is not set. */ + BHND_IOST_CLK = 0x2000, /**< Set if the core has requested that gated clocks be enabled, or + cleared otherwise. The value is undefined if a core does not + support clock gating. */ + BHND_IOST_DMA64 = 0x1000, /**< Set if this core supports 64-bit DMA */ + BHND_IOST_CFLAGS = 0x0FFC, /**< Reserved for core-specific status flags. */ +}; + /* * Simplified accessors for bhnd device ivars */ @@ -113,6 +149,7 @@ BHND_ACCESSOR(vendor_name, VENDOR_NAME, BHND_ACCESSOR(device_name, DEVICE_NAME, const char *); BHND_ACCESSOR(core_index, CORE_INDEX, u_int); BHND_ACCESSOR(core_unit, CORE_UNIT, int); +BHND_ACCESSOR(pmu_info, PMU_INFO, struct bhnd_core_pmu_info *); #undef BHND_ACCESSOR @@ -451,6 +488,119 @@ bhnd_get_chipid(device_t dev) { return (BHND_BUS_GET_CHIPID(device_get_parent(dev), dev)); }; + +/** + * Read the current value of a bhnd(4) device's per-core I/O control register. + * + * @param dev The bhnd bus child device to be queried. + * @param[out] ioctl On success, the I/O control register value. + * + * @retval 0 success + * @retval EINVAL If @p child is not a direct child of @p dev. + * @retval ENODEV If agent/config space for @p child is unavailable. + * @retval non-zero If reading the IOCTL register otherwise fails, a regular + * unix error code will be returned. + */ +static inline int +bhnd_read_ioctl(device_t dev, uint16_t *ioctl) +{ + return (BHND_BUS_READ_IOCTL(device_get_parent(dev), dev, ioctl)); +} + +/** + * Write @p value and @p mask to a bhnd(4) device's per-core I/O control + * register. + * + * @param dev The bhnd bus child device for which the IOCTL register will be + * written. + * @param value The value to be written (see BHND_IOCTL_*). + * @param mask Only the bits defined by @p mask will be updated from @p value. + * + * @retval 0 success + * @retval EINVAL If @p child is not a direct child of @p dev. + * @retval ENODEV If agent/config space for @p child is unavailable. + * @retval non-zero If writing the IOCTL register otherwise fails, a regular + * unix error code will be returned. + */ +static inline int +bhnd_write_ioctl(device_t dev, uint16_t value, uint16_t mask) +{ + return (BHND_BUS_WRITE_IOCTL(device_get_parent(dev), dev, value, mask)); +} + +/** + * Read the current value of a bhnd(4) device's per-core I/O status register. + * + * @param dev The bhnd bus child device to be queried. + * @param[out] iost On success, the I/O status register value. + * + * @retval 0 success + * @retval EINVAL If @p child is not a direct child of @p dev. + * @retval ENODEV If agent/config space for @p child is unavailable. + * @retval non-zero If reading the IOST register otherwise fails, a regular + * unix error code will be returned. + */ +static inline int +bhnd_read_iost(device_t dev, uint16_t *iost) +{ + return (BHND_BUS_READ_IOST(device_get_parent(dev), dev, iost)); +} + +/** + * Return true if the given bhnd device's hardware is currently held + * in a RESET state or otherwise not clocked (BHND_IOCTL_CLK_EN). + * + * @param dev The device to query. + * + * @retval true If @p dev is held in RESET or not clocked (BHND_IOCTL_CLK_EN), + * or an error occured determining @p dev's hardware state. + * @retval false If @p dev is clocked and is not held in RESET. + */ +static inline bool +bhnd_is_hw_suspended(device_t dev) +{ + return (BHND_BUS_IS_HW_SUSPENDED(device_get_parent(dev), dev)); +} + +/** + * Place the bhnd(4) device's hardware into a reset state, and then bring the + * hardware out of reset with BHND_IOCTL_CLK_EN and @p ioctl flags set. + * + * Any clock or resource PMU requests previously made by @p dev will be + * invalidated. + * + * @param dev The device to be reset. + * @param ioctl Device-specific core ioctl flags to be supplied on reset + * (see BHND_IOCTL_*). + * + * @retval 0 success + * @retval non-zero error + */ +static inline int +bhnd_reset_hw(device_t dev, uint16_t ioctl) +{ + return (BHND_BUS_RESET_HW(device_get_parent(dev), dev, ioctl)); +} + +/** + * Suspend @p child's hardware in a low-power reset state. + * + * Any clock or resource PMU requests previously made by @p dev will be + * invalidated. + * + * The hardware may be brought out of reset via bhnd_reset_hw(). + * + * @param dev The device to be suspended. + * + * @retval 0 success + * @retval non-zero error + */ +static inline int +bhnd_suspend_hw(device_t dev) +{ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***