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
Landon J. Fuller
landonf at FreeBSD.org
Sat Sep 24 04:08:18 UTC 2016
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 <machine/bus.h>
-#include "bcmavar.h"
+#include <dev/bhnd/cores/pmu/bhnd_pmu.h>
#include "bcma_dmp.h"
#include "bcma_eromreg.h"
#include "bcma_eromvar.h"
-#include <dev/bhnd/bhnd_core.h>
+#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 <dev/bhnd/bhndvar.h>
+#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 ***
More information about the svn-src-head
mailing list