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-all mailing list