svn commit: r301971 - in head/sys/dev/bhnd: . cores/chipc

Landon J. Fuller landonf at FreeBSD.org
Thu Jun 16 19:57:26 UTC 2016


Author: landonf
Date: Thu Jun 16 19:57:24 2016
New Revision: 301971
URL: https://svnweb.freebsd.org/changeset/base/301971

Log:
  bhnd(4): Fix resource allocation issues exposed by chipc PMU support.
  
  - Delete all chipc children on attachment failure.
  - Added missing bhnd_nexus bhnd_bus_deactivate_resource implementation.
  - Drop a CHIPC_UNLOCK() accidentally left behind after lifting
    synchronization into the chipc region refcounting API.
  - Fix re-allocation of chipc resources. Previously, the resource ID was
    reset to -1 on release, preventing later re-allocation.
  
  Approved by:	re (gjb), adrian (mentor)
  Differential Revision:	 https://reviews.freebsd.org/D6849

Modified:
  head/sys/dev/bhnd/bhnd_nexus.c
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/dev/bhnd/cores/chipc/chipc_private.h
  head/sys/dev/bhnd/cores/chipc/chipc_subr.c

Modified: head/sys/dev/bhnd/bhnd_nexus.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_nexus.c	Thu Jun 16 17:59:15 2016	(r301970)
+++ head/sys/dev/bhnd/bhnd_nexus.c	Thu Jun 16 19:57:24 2016	(r301971)
@@ -106,10 +106,26 @@ bhnd_nexus_activate_resource(device_t de
 	return (0);
 }
 
+static int
+bhnd_nexus_deactivate_resource(device_t dev, device_t child,
+    int type, int rid, struct bhnd_resource *r)
+{
+	int error;
+
+	/* Always direct */
+	KASSERT(r->direct, ("indirect resource delegated to bhnd_nexus\n"));
+
+	if ((error = bus_deactivate_resource(child, type, rid, r->res)))
+		return (error);
+
+	r->direct = false;
+	return (0);
+}
 
 static device_method_t bhnd_nexus_methods[] = {
 	/* bhnd interface */
 	DEVMETHOD(bhnd_bus_activate_resource,	bhnd_nexus_activate_resource),
+	DEVMETHOD(bhnd_bus_deactivate_resource, bhnd_nexus_deactivate_resource),
 	DEVMETHOD(bhnd_bus_is_hw_disabled,	bhnd_nexus_is_hw_disabled),
 	DEVMETHOD(bhnd_bus_get_attach_type,	bhnd_nexus_get_attach_type),
 

Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c	Thu Jun 16 17:59:15 2016	(r301970)
+++ head/sys/dev/bhnd/cores/chipc/chipc.c	Thu Jun 16 19:57:24 2016	(r301971)
@@ -282,6 +282,8 @@ chipc_attach(device_t dev)
 	return (0);
 	
 failed:
+	device_delete_children(sc->dev);
+
 	if (sc->core_region != NULL) {
 		chipc_release_region(sc, sc->core_region,
 		    RF_ALLOCATED|RF_ACTIVE);
@@ -878,10 +880,8 @@ chipc_alloc_resource(device_t dev, devic
 	}
 
 	/* Try to retain a region reference */
-	if ((error = chipc_retain_region(sc, cr, RF_ALLOCATED))) {
-		CHIPC_UNLOCK(sc);
+	if ((error = chipc_retain_region(sc, cr, RF_ALLOCATED)))
 		return (NULL);
-	}
 
 	/* Make our rman reservation */
 	rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,

Modified: head/sys/dev/bhnd/cores/chipc/chipc_private.h
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc_private.h	Thu Jun 16 17:59:15 2016	(r301970)
+++ head/sys/dev/bhnd/cores/chipc/chipc_private.h	Thu Jun 16 19:57:24 2016	(r301971)
@@ -84,11 +84,13 @@ struct chipc_region {
 	bhnd_addr_t		 cr_addr;	/**< region base address */
 	bhnd_addr_t		 cr_end;	/**< region end address */
 	bhnd_size_t		 cr_count;	/**< region count */
-	int			 cr_rid;	/**< rid, or -1 if no rid
-						  *  is allocated by the bus for
-						  *  this region */
+	int			 cr_rid;	/**< rid to use when performing
+						     resource allocation, or -1
+						     if region has no assigned
+						     resource ID */
 
 	struct bhnd_resource	*cr_res;	/**< bus resource, or NULL */
+	int			 cr_res_rid;	/**< cr_res RID, if any. */
 	u_int			 cr_refs;	/**< RF_ALLOCATED refcount */
 	u_int			 cr_act_refs;	/**< RF_ACTIVE refcount */
 

Modified: head/sys/dev/bhnd/cores/chipc/chipc_subr.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc_subr.c	Thu Jun 16 17:59:15 2016	(r301970)
+++ head/sys/dev/bhnd/cores/chipc/chipc_subr.c	Thu Jun 16 19:57:24 2016	(r301971)
@@ -150,9 +150,10 @@ chipc_alloc_region(struct chipc_softc *s
 
 	cr->cr_end = cr->cr_addr + cr->cr_count - 1;
 
-	/* Note that not all regions have an assigned rid, in which case
-	 * this will return -1 */
+	/* Fetch default resource ID for this region. Not all regions have an
+	 * assigned rid, in which case this will return -1 */
 	cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region);
+
 	return (cr);
 
 failed:
@@ -177,7 +178,7 @@ chipc_free_region(struct chipc_softc *sc
 	     cr->cr_region_num, cr->cr_refs));
 
 	if (cr->cr_res != NULL) {
-		bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_rid,
+		bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid,
 		    cr->cr_res);
 	}
 
@@ -264,10 +265,16 @@ chipc_retain_region(struct chipc_softc *
 			KASSERT(cr->cr_res == NULL,
 			    ("non-NULL resource has refcount"));
 
+			/* Fetch initial resource ID */			
+			if ((cr->cr_res_rid = cr->cr_rid) == -1) {
+				CHIPC_UNLOCK(sc);
+				return (EINVAL);
+			}
+
+			/* Allocate resource */
 			cr->cr_res = bhnd_alloc_resource(sc->dev,
-			    SYS_RES_MEMORY, &cr->cr_rid, cr->cr_addr,
+			    SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr,
 			    cr->cr_end, cr->cr_count, 0);
-
 			if (cr->cr_res == NULL) {
 				CHIPC_UNLOCK(sc);
 				return (ENXIO);
@@ -287,7 +294,7 @@ chipc_retain_region(struct chipc_softc *
 		/* If this is the first reference, activate the resource */
 		if (cr->cr_act_refs == 0) {
 			error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY,
-			    cr->cr_rid, cr->cr_res);
+			    cr->cr_res_rid, cr->cr_res);
 			if (error) {
 				/* Drop any allocation reference acquired
 				 * above */
@@ -324,6 +331,8 @@ chipc_release_region(struct chipc_softc 
 	CHIPC_LOCK(sc);
 	error = 0;
 
+	KASSERT(cr->cr_res != NULL, ("release on NULL region resource"));
+
 	if (flags & RF_ACTIVE) {
 		KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released"));
 		KASSERT(cr->cr_act_refs <= cr->cr_refs,
@@ -332,7 +341,7 @@ chipc_release_region(struct chipc_softc 
 		/* If this is the last reference, deactivate the resource */
 		if (cr->cr_act_refs == 1) {
 			error = bhnd_deactivate_resource(sc->dev,
-			    SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+			    SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res);
 			if (error)
 				goto done;
 		}
@@ -343,16 +352,14 @@ chipc_release_region(struct chipc_softc 
 
 	if (flags & RF_ALLOCATED) {
 		KASSERT(cr->cr_refs > 0, ("overrelease of refs"));
-
 		/* If this is the last reference, release the resource */
 		if (cr->cr_refs == 1) {
-			error = bhnd_release_resource(sc->dev,
-			    SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+			error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY,
+			    cr->cr_res_rid, cr->cr_res);
 			if (error)
 				goto done;
 
 			cr->cr_res = NULL;
-			cr->cr_rid = -1;
 		}
 
 		/* Drop our allocation refcount */


More information about the svn-src-head mailing list