svn commit: r328201 - in head/sys: arm/allwinner arm/nvidia arm/nvidia/tegra124 conf dev/extres/phy dev/usb/controller

Michal Meloun mmel at FreeBSD.org
Sat Jan 20 17:02:20 UTC 2018


Author: mmel
Date: Sat Jan 20 17:02:17 2018
New Revision: 328201
URL: https://svnweb.freebsd.org/changeset/base/328201

Log:
  Convert extres/phy to kobj model.
  Similarly as other extres pseudo-drivers, implement phy by using kobj model.
  This detaches it from provider device, so single device driver can export
  multiple different phys. Additionally, this  allows phy to be subclassed to
  more specialized drivers, like is USB OTG phy, or PCIe phy with hot-plug
  capability.
  
  Tested by:	manu (previous version, on Allwinner board)
  MFC after:	1 month

Added:
  head/sys/dev/extres/phy/phydev_if.m   (contents, props changed)
  head/sys/dev/extres/phy/phynode_if.m
     - copied, changed from r328200, head/sys/dev/extres/phy/phy_if.m
Deleted:
  head/sys/dev/extres/phy/phy_if.m
Modified:
  head/sys/arm/allwinner/a10_ehci.c
  head/sys/arm/allwinner/aw_usbphy.c
  head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c
  head/sys/arm/nvidia/tegra_ahci.c
  head/sys/arm/nvidia/tegra_ehci.c
  head/sys/arm/nvidia/tegra_pcie.c
  head/sys/arm/nvidia/tegra_usbphy.c
  head/sys/arm/nvidia/tegra_xhci.c
  head/sys/conf/files
  head/sys/dev/extres/phy/phy.c
  head/sys/dev/extres/phy/phy.h
  head/sys/dev/usb/controller/generic_ohci.c

Modified: head/sys/arm/allwinner/a10_ehci.c
==============================================================================
--- head/sys/arm/allwinner/a10_ehci.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/allwinner/a10_ehci.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -242,7 +242,7 @@ a10_ehci_attach(device_t self)
 
 	/* Enable USB PHY */
 	if (phy_get_by_ofw_name(self, 0, "usb", &aw_sc->phy) == 0) {
-		err = phy_enable(self, aw_sc->phy);
+		err = phy_enable(aw_sc->phy);
 		if (err != 0) {
 			device_printf(self, "Could not enable phy\n");
 			goto error;

Modified: head/sys/arm/allwinner/aw_usbphy.c
==============================================================================
--- head/sys/arm/allwinner/aw_usbphy.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/allwinner/aw_usbphy.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/extres/regulator/regulator.h>
 #include <dev/extres/phy/phy.h>
 
-#include "phy_if.h"
+#include "phynode_if.h"
 
 enum awusbphy_type {
 	AWUSBPHY_TYPE_A10 = 1,
@@ -141,6 +141,16 @@ struct awusbphy_softc {
 	struct aw_usbphy_conf	*phy_conf;
 };
 
+ /* Phy class and methods. */
+static int awusbphy_phy_enable(struct phynode *phy, bool enable);
+static phynode_method_t awusbphy_phynode_methods[] = {
+	PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable),
+
+	PHYNODEMETHOD_END
+};
+DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods,
+    0, phynode_class);
+
 #define	RD4(res, o)	bus_read_4(res, (o))
 #define	WR4(res, o, v)	bus_write_4(res, (o), (v))
 #define	CLR4(res, o, m)	WR4(res, o, RD4(res, o) & ~(m))
@@ -282,12 +292,16 @@ awusbphy_vbus_detect(device_t dev, int *val)
 }
 
 static int
-awusbphy_phy_enable(device_t dev, intptr_t phy, bool enable)
+awusbphy_phy_enable(struct phynode *phynode, bool enable)
 {
+	device_t dev;
+	intptr_t phy;
 	struct awusbphy_softc *sc;
 	regulator_t reg;
 	int error, vbus_det;
 
+	dev = phynode_get_device(phynode);
+	phy = phynode_get_id(phynode);
 	sc = device_get_softc(dev);
 
 	if (phy < 0 || phy >= sc->phy_conf->num_phys)
@@ -356,7 +370,12 @@ static int
 awusbphy_attach(device_t dev)
 {
 	int error;
+	struct phynode *phynode;
+	struct phynode_init_def phy_init;
+	struct awusbphy_softc *sc;
+	int i;
 
+	sc = device_get_softc(dev);
 	error = awusbphy_init(dev);
 	if (error) {
 		device_printf(dev, "failed to initialize USB PHY, error %d\n",
@@ -364,7 +383,22 @@ awusbphy_attach(device_t dev)
 		return (error);
 	}
 
-	phy_register_provider(dev);
+	/* Create and register phys. */
+	for (i = 0; i < sc->phy_conf->num_phys; i++) {
+		bzero(&phy_init, sizeof(phy_init));
+		phy_init.id = i;
+		phy_init.ofw_node = ofw_bus_get_node(dev);
+		phynode = phynode_create(dev, &awusbphy_phynode_class,
+		    &phy_init);
+		if (phynode == NULL) {
+			device_printf(dev, "failed to create USB PHY\n");
+			return (ENXIO);
+		}
+		if (phynode_register(phynode) == NULL) {
+			device_printf(dev, "failed to create USB PHY\n");
+			return (ENXIO);
+		}
+	}
 
 	return (error);
 }
@@ -373,9 +407,6 @@ static device_method_t awusbphy_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		awusbphy_probe),
 	DEVMETHOD(device_attach,	awusbphy_attach),
-
-	/* PHY interface */
-	DEVMETHOD(phy_enable,		awusbphy_phy_enable),
 
 	DEVMETHOD_END
 };

Modified: head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c
==============================================================================
--- head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -22,10 +22,11 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -50,7 +51,7 @@
 
 #include <gnu/dts/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
-#include "phy_if.h"
+#include "phydev_if.h"
 
 /* FUSE calibration data. */
 #define	FUSE_XUSB_CALIB				0x0F0
@@ -216,7 +217,6 @@ struct padctl_port {
 				    struct padctl_port *port);
 
 	/* Runtime data. */
-	phandle_t		xref;
 	bool			enabled;
 	regulator_t		supply_vbus;	/* USB2, USB3 */
 	bool			internal;	/* ULPI, USB2, USB3 */
@@ -303,7 +303,6 @@ struct padctl_lane {
 	int			nmux;
 	/* Runtime data. */
 	bool			enabled;
-	phandle_t		xref;
 	struct padctl_pad	*pad;
 	struct padctl_port	*port;
 	int			mux_idx;
@@ -353,6 +352,16 @@ static struct padctl_lane_map lane_map_tbl[] = {
 	LANE_MAP(1, PADCTL_PAD_SATA, 0), 	/* port USB3-1 -> lane SATA-0 */
 };
 
+ /* Phy class and methods. */
+static int xusbpadctl_phy_enable(struct phynode *phy, bool enable);
+static phynode_method_t xusbpadctl_phynode_methods[] = {
+	PHYNODEMETHOD(phynode_enable,	xusbpadctl_phy_enable),
+	PHYNODEMETHOD_END
+
+};
+DEFINE_CLASS_1(xusbpadctl_phynode, xusbpadctl_phynode_class,
+    xusbpadctl_phynode_methods, 0, phynode_class);
+
 static struct padctl_port *search_lane_port(struct padctl_softc *sc,
     struct padctl_lane *lane);
 /* -------------------------------------------------------------------------
@@ -683,13 +692,17 @@ phy_powerdown(struct padctl_softc *sc)
 }
 
 static int
-xusbpadctl_phy_enable(device_t dev, intptr_t id, bool enable)
+xusbpadctl_phy_enable(struct phynode *phy, bool enable)
 {
+	device_t dev;
+	intptr_t id;
 	struct padctl_softc *sc;
 	struct padctl_lane *lane;
 	struct padctl_pad *pad;
 	int rv;
 
+	dev = phynode_get_device(phy);
+	id = phynode_get_id(phy);
 	sc = device_get_softc(dev);
 
 	if (id < 0 || id >= nitems(lanes_tbl)) {
@@ -731,24 +744,6 @@ xusbpadctl_phy_enable(device_t dev, intptr_t id, bool 
 	return (0);
 }
 
-static int
-xusbpadctl_phy_map(device_t provider, phandle_t xref, int ncells,
-    pcell_t *cells, intptr_t *id)
-{
-	int i;
-
-	if (ncells != 0)
-		return  (ERANGE);
-
-	for (i = 0; i < nitems(lanes_tbl); i++) {
-		if (lanes_tbl[i].xref == xref) {
-			*id = i;
-			return (0);
-		}
-	}
-	return (ENXIO);
-}
-
 /* -------------------------------------------------------------------------
  *
  *   FDT processing
@@ -871,6 +866,8 @@ static int
 process_lane(struct padctl_softc *sc, phandle_t node, struct padctl_pad *pad)
 {
 	struct padctl_lane *lane;
+	struct phynode *phynode;
+	struct phynode_init_def phy_init;
 	char *name;
 	char *function;
 	int rv;
@@ -913,10 +910,25 @@ process_lane(struct padctl_softc *sc, phandle_t node, 
 		rv = ENXIO;
 		goto end;
 	}
-	lane->xref = OF_xref_from_node(node);
 	lane->pad = pad;
 	lane->enabled = true;
 	pad->lanes[pad->nlanes++] = lane;
+
+	/* Create and register phy. */
+	bzero(&phy_init, sizeof(phy_init));
+	phy_init.id = lane - lanes_tbl;
+	phy_init.ofw_node = node;
+	phynode = phynode_create(sc->dev, &xusbpadctl_phynode_class, &phy_init);
+	if (phynode == NULL) {
+		device_printf(sc->dev, "Cannot create phy\n");
+		rv = ENXIO;
+		goto end;
+	}
+	if (phynode_register(phynode) == NULL) {
+		device_printf(sc->dev, "Cannot create phy\n");
+		return (ENXIO);
+	}
+
 	rv = 0;
 
 end:
@@ -930,7 +942,6 @@ end:
 static int
 process_pad(struct padctl_softc *sc, phandle_t node)
 {
-	phandle_t  xref;
 	struct padctl_pad *pad;
 	char *name;
 	int rv;
@@ -963,9 +974,6 @@ process_pad(struct padctl_softc *sc, phandle_t node)
 		rv = process_lane(sc, node, pad);
 		if (rv != 0)
 			goto end;
-
-		xref = OF_xref_from_node(node);
-		OF_device_register_xref(xref, sc->dev);
 	}
 	pad->enabled = true;
 	rv = 0;
@@ -1193,10 +1201,6 @@ static device_method_t tegra_xusbpadctl_methods[] = {
 	DEVMETHOD(device_probe,         xusbpadctl_probe),
 	DEVMETHOD(device_attach,        xusbpadctl_attach),
 	DEVMETHOD(device_detach,        xusbpadctl_detach),
-
-	/* phy interface */
-	DEVMETHOD(phy_enable,		xusbpadctl_phy_enable),
-	DEVMETHOD(phy_map,		xusbpadctl_phy_map),
 
 	DEVMETHOD_END
 };

Modified: head/sys/arm/nvidia/tegra_ahci.c
==============================================================================
--- head/sys/arm/nvidia/tegra_ahci.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra_ahci.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -371,7 +371,7 @@ enable_fdt_resources(struct tegra_ahci_sc *sc)
 		return (rv);
 	}
 
-	rv = phy_enable(sc->dev, sc->phy);
+	rv = phy_enable(sc->phy);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable SATA phy\n");
 		return (rv);

Modified: head/sys/arm/nvidia/tegra_ehci.c
==============================================================================
--- head/sys/arm/nvidia/tegra_ehci.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra_ehci.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -214,7 +214,7 @@ tegra_ehci_attach(device_t dev)
 		goto out;
 	}
 
-	rv = phy_enable(sc->dev, sc->phy);
+	rv = phy_enable(sc->phy);
 	if (rv != 0) {
 		device_printf(dev, "Cannot enable phy: %d\n", rv);
 		goto out;

Modified: head/sys/arm/nvidia/tegra_pcie.c
==============================================================================
--- head/sys/arm/nvidia/tegra_pcie.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra_pcie.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -1309,7 +1309,7 @@ tegra_pcib_enable(struct tegra_pcib_softc *sc)
 
 	for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
 		if (sc->ports[i] != NULL) {
-			rv = phy_enable(sc->dev, sc->ports[i]->phy);
+			rv = phy_enable(sc->ports[i]->phy);
 			if (rv != 0) {
 				device_printf(sc->dev,
 				    "Cannot enable phy for port %d\n",

Modified: head/sys/arm/nvidia/tegra_usbphy.c
==============================================================================
--- head/sys/arm/nvidia/tegra_usbphy.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra_usbphy.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
-#include "phy_if.h"
+#include "phynode_if.h"
 
 #define	CTRL_ICUSB_CTRL			0x15c
 #define	  ICUSB_CTR_IC_ENB1			(1 << 3)
@@ -299,6 +299,16 @@ static struct ofw_compat_data compat_data[] = {
 	{NULL,				0},
 };
 
+ /* Phy controller class and methods. */
+static int usbphy_phy_enable(struct phynode *phy, bool enable);
+static phynode_method_t usbphy_phynode_methods[] = {
+	PHYNODEMETHOD(phynode_enable, usbphy_phy_enable),
+
+	PHYNODEMETHOD_END
+};
+DEFINE_CLASS_1(usbphy_phynode, usbphy_phynode_class, usbphy_phynode_methods,
+    0, phynode_class);
+
 #define	RD4(sc, offs)							\
 	 bus_read_4(sc->mem_res, offs)
 
@@ -554,11 +564,13 @@ usbphy_utmi_disable(struct usbphy_softc *sc)
 }
 
 static int
-usbphy_phy_enable(device_t dev, int id, bool enable)
+usbphy_phy_enable(struct phynode *phy, bool enable)
 {
+	device_t dev;
 	struct usbphy_softc *sc;
 	int rv = 0;
 
+	dev = phynode_get_device(phy);
 	sc = device_get_softc(dev);
 
 	if (sc->ifc_type != USB_IFC_TYPE_UTMI) {
@@ -700,9 +712,11 @@ usbphy_probe(device_t dev)
 static int
 usbphy_attach(device_t dev)
 {
-	struct usbphy_softc * sc;
+	struct usbphy_softc *sc;
 	int rid, rv;
 	phandle_t node;
+	struct phynode *phynode;
+	struct phynode_init_def phy_init;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
@@ -802,7 +816,20 @@ usbphy_attach(device_t dev)
 		}
 	}
 
-	phy_register_provider(dev);
+	/* Create and register phy. */
+	bzero(&phy_init, sizeof(phy_init));
+	phy_init.id = 1;
+	phy_init.ofw_node = node;
+	phynode = phynode_create(dev, &usbphy_phynode_class, &phy_init);
+	if (phynode == NULL) {
+		device_printf(sc->dev, "Cannot create phy\n");
+		return (ENXIO);
+	}
+	if (phynode_register(phynode) == NULL) {
+		device_printf(sc->dev, "Cannot create phy\n");
+		return (ENXIO);
+	}
+
 	return (0);
 }
 
@@ -819,9 +846,6 @@ static device_method_t tegra_usbphy_methods[] = {
 	DEVMETHOD(device_probe,		usbphy_probe),
 	DEVMETHOD(device_attach,	usbphy_attach),
 	DEVMETHOD(device_detach,	usbphy_detach),
-
-	/* phy interface */
-	DEVMETHOD(phy_enable,		usbphy_phy_enable),
 
 	DEVMETHOD_END
 };

Modified: head/sys/arm/nvidia/tegra_xhci.c
==============================================================================
--- head/sys/arm/nvidia/tegra_xhci.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/arm/nvidia/tegra_xhci.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -583,22 +583,22 @@ enable_fdt_resources(struct tegra_xhci_softc *sc)
 		return (rv);
 	}
 
-	rv = phy_enable(sc->dev, sc->phy_usb2_0);
+	rv = phy_enable(sc->phy_usb2_0);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable USB2_0 phy\n");
 		return (rv);
 	}
-	rv = phy_enable(sc->dev, sc->phy_usb2_1);
+	rv = phy_enable(sc->phy_usb2_1);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable USB2_1 phy\n");
 		return (rv);
 	}
-	rv = phy_enable(sc->dev, sc->phy_usb2_2);
+	rv = phy_enable(sc->phy_usb2_2);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable USB2_2 phy\n");
 		return (rv);
 	}
-	rv = phy_enable(sc->dev, sc->phy_usb3_0);
+	rv = phy_enable(sc->phy_usb3_0);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable USB3_0 phy\n");
 		return (rv);

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/conf/files	Sat Jan 20 17:02:17 2018	(r328201)
@@ -1732,7 +1732,8 @@ dev/extres/clk/clk_fixed.c	optional ext_resources clk 
 dev/extres/clk/clk_gate.c	optional ext_resources clk fdt
 dev/extres/clk/clk_mux.c	optional ext_resources clk fdt
 dev/extres/phy/phy.c		optional ext_resources phy fdt
-dev/extres/phy/phy_if.m		optional ext_resources phy fdt
+dev/extres/phy/phydev_if.m	optional ext_resources phy fdt
+dev/extres/phy/phynode_if.m	optional ext_resources phy fdt
 dev/extres/hwreset/hwreset.c	optional ext_resources hwreset fdt
 dev/extres/hwreset/hwreset_if.m	optional ext_resources hwreset fdt
 dev/extres/regulator/regdev_if.m	optional ext_resources regulator fdt

Modified: head/sys/dev/extres/phy/phy.c
==============================================================================
--- head/sys/dev/extres/phy/phy.c	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/dev/extres/phy/phy.c	Sat Jan 20 17:02:17 2018	(r328201)
@@ -22,15 +22,20 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
+
+ #include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 #include "opt_platform.h"
-#include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/queue.h>
 #include <sys/systm.h>
+#include <sys/sx.h>
 
 #ifdef FDT
 #include <dev/ofw/ofw_bus.h>
@@ -39,88 +44,452 @@
 
 #include  <dev/extres/phy/phy.h>
 
-#include "phy_if.h"
+#include "phydev_if.h"
 
+MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
+
+/* Forward declarations. */
+struct phy;
+struct phynode;
+
+typedef TAILQ_HEAD(phynode_list, phynode) phynode_list_t;
+typedef TAILQ_HEAD(phy_list, phy) phy_list_t;
+
+/* Default phy methods. */
+static int phynode_method_init(struct phynode *phynode);
+static int phynode_method_enable(struct phynode *phynode, bool disable);
+static int phynode_method_status(struct phynode *phynode, int *status);
+
+
+/*
+ * Phy controller methods.
+ */
+static phynode_method_t phynode_methods[] = {
+	PHYNODEMETHOD(phynode_init,		phynode_method_init),
+	PHYNODEMETHOD(phynode_enable,		phynode_method_enable),
+	PHYNODEMETHOD(phynode_status,		phynode_method_status),
+
+	PHYNODEMETHOD_END
+};
+DEFINE_CLASS_0(phynode, phynode_class, phynode_methods, 0);
+
+/*
+ * Phy node
+ */
+struct phynode {
+	KOBJ_FIELDS;
+
+	TAILQ_ENTRY(phynode)	phylist_link;	/* Global list entry */
+	phy_list_t		consumers_list;	/* Consumers list */
+
+
+	/* Details of this device. */
+	const char		*name;		/* Globally unique name */
+
+	device_t		pdev;		/* Producer device_t */
+	void			*softc;		/* Producer softc */
+	intptr_t		id;		/* Per producer unique id */
+#ifdef FDT
+	 phandle_t		ofw_node;	/* OFW node of phy */
+#endif
+	struct sx		lock;		/* Lock for this phy */
+	int			ref_cnt;	/* Reference counter */
+	int			enable_cnt;	/* Enabled counter */
+};
+
 struct phy {
-	device_t	consumer_dev;	/* consumer device*/
-	device_t	provider_dev;	/* provider device*/
-	uintptr_t	phy_id;		/* phy id */
+	device_t		cdev;		/* consumer device*/
+	struct phynode		*phynode;
+	TAILQ_ENTRY(phy)	link;		/* Consumers list entry */
+
+	int			enable_cnt;
 };
 
-MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
+static phynode_list_t phynode_list = TAILQ_HEAD_INITIALIZER(phynode_list);
 
+static struct sx		phynode_topo_lock;
+SX_SYSINIT(phy_topology, &phynode_topo_lock, "Phy topology lock");
+
+#define PHY_TOPO_SLOCK()	sx_slock(&phynode_topo_lock)
+#define PHY_TOPO_XLOCK()	sx_xlock(&phynode_topo_lock)
+#define PHY_TOPO_UNLOCK()	sx_unlock(&phynode_topo_lock)
+#define PHY_TOPO_ASSERT()	sx_assert(&phynode_topo_lock, SA_LOCKED)
+#define PHY_TOPO_XASSERT() 	sx_assert(&phynode_topo_lock, SA_XLOCKED)
+
+#define PHYNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
+#define PHYNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
+#define PHYNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
+
+/* ----------------------------------------------------------------------------
+ *
+ * Default phy methods for base class.
+ *
+ */
+
+static int
+phynode_method_init(struct phynode *phynode)
+{
+
+	return (0);
+}
+
+static int
+phynode_method_enable(struct phynode *phynode, bool enable)
+{
+
+	if (!enable)
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+phynode_method_status(struct phynode *phynode, int *status)
+{
+	*status = PHY_STATUS_ENABLED;
+	return (0);
+}
+
+/* ----------------------------------------------------------------------------
+ *
+ * Internal functions.
+ *
+ */
+/*
+ * Create and initialize phy object, but do not register it.
+ */
+struct phynode *
+phynode_create(device_t pdev, phynode_class_t phynode_class,
+    struct phynode_init_def *def)
+{
+	struct phynode *phynode;
+
+
+	/* Create object and initialize it. */
+	phynode = malloc(sizeof(struct phynode), M_PHY, M_WAITOK | M_ZERO);
+	kobj_init((kobj_t)phynode, (kobj_class_t)phynode_class);
+	sx_init(&phynode->lock, "Phy node lock");
+
+	/* Allocate softc if required. */
+	if (phynode_class->size > 0) {
+		phynode->softc = malloc(phynode_class->size, M_PHY,
+		    M_WAITOK | M_ZERO);
+	}
+
+	/* Rest of init. */
+	TAILQ_INIT(&phynode->consumers_list);
+	phynode->id = def->id;
+	phynode->pdev = pdev;
+#ifdef FDT
+	phynode->ofw_node = def->ofw_node;
+#endif
+
+	return (phynode);
+}
+
+/* Register phy object. */
+struct phynode *
+phynode_register(struct phynode *phynode)
+{
+	int rv;
+
+#ifdef FDT
+	if (phynode->ofw_node <= 0)
+		phynode->ofw_node = ofw_bus_get_node(phynode->pdev);
+	if (phynode->ofw_node <= 0)
+		return (NULL);
+#endif
+
+	rv = PHYNODE_INIT(phynode);
+	if (rv != 0) {
+		printf("PHYNODE_INIT failed: %d\n", rv);
+		return (NULL);
+	}
+
+	PHY_TOPO_XLOCK();
+	TAILQ_INSERT_TAIL(&phynode_list, phynode, phylist_link);
+	PHY_TOPO_UNLOCK();
+#ifdef FDT
+	OF_device_register_xref(OF_xref_from_node(phynode->ofw_node),
+	    phynode->pdev);
+#endif
+	return (phynode);
+}
+
+static struct phynode *
+phynode_find_by_id(device_t dev, intptr_t id)
+{
+	struct phynode *entry;
+
+	PHY_TOPO_ASSERT();
+
+	TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
+		if ((entry->pdev == dev) && (entry->id ==  id))
+			return (entry);
+	}
+
+	return (NULL);
+}
+
+/* --------------------------------------------------------------------------
+ *
+ * Phy providers interface
+ *
+ */
+
+void *
+phynode_get_softc(struct phynode *phynode)
+{
+
+	return (phynode->softc);
+}
+
+device_t
+phynode_get_device(struct phynode *phynode)
+{
+
+	return (phynode->pdev);
+}
+
+intptr_t phynode_get_id(struct phynode *phynode)
+{
+
+	return (phynode->id);
+}
+
+#ifdef FDT
+phandle_t
+phynode_get_ofw_node(struct phynode *phynode)
+{
+
+	return (phynode->ofw_node);
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ *
+ * Real consumers executive
+ *
+ */
+
+/*
+ * Enable phy.
+ */
 int
-phy_init(device_t consumer, phy_t phy)
+phynode_enable(struct phynode *phynode)
 {
+	int rv;
 
-	return (PHY_INIT(phy->provider_dev, phy->phy_id, true));
+	PHY_TOPO_ASSERT();
+
+	PHYNODE_XLOCK(phynode);
+	if (phynode->enable_cnt == 0) {
+		rv = PHYNODE_ENABLE(phynode, true);
+		if (rv != 0) {
+			PHYNODE_UNLOCK(phynode);
+			return (rv);
+		}
+	}
+	phynode->enable_cnt++;
+	PHYNODE_UNLOCK(phynode);
+	return (0);
 }
 
+/*
+ * Disable phy.
+ */
 int
-phy_deinit(device_t consumer, phy_t phy)
+phynode_disable(struct phynode *phynode)
 {
+	int rv;
 
-	return (PHY_INIT(phy->provider_dev, phy->phy_id, false));
+	PHY_TOPO_ASSERT();
+
+	PHYNODE_XLOCK(phynode);
+	if (phynode->enable_cnt == 1) {
+		rv = PHYNODE_ENABLE(phynode, false);
+		if (rv != 0) {
+			PHYNODE_UNLOCK(phynode);
+			return (rv);
+		}
+	}
+	phynode->enable_cnt--;
+	PHYNODE_UNLOCK(phynode);
+	return (0);
 }
 
 
+/*
+ * Get phy status. (PHY_STATUS_*)
+ */
 int
-phy_enable(device_t consumer, phy_t phy)
+phynode_status(struct phynode *phynode, int *status)
 {
+	int rv;
 
-	return (PHY_ENABLE(phy->provider_dev, phy->phy_id, true));
+	PHY_TOPO_ASSERT();
+
+	PHYNODE_XLOCK(phynode);
+	rv = PHYNODE_STATUS(phynode, status);
+	PHYNODE_UNLOCK(phynode);
+	return (rv);
 }
 
+ /* --------------------------------------------------------------------------
+ *
+ * Phy consumers interface.
+ *
+ */
+
+/* Helper function for phy_get*() */
+static phy_t
+phy_create(struct phynode *phynode, device_t cdev)
+{
+	struct phy *phy;
+
+	PHY_TOPO_ASSERT();
+
+	phy =  malloc(sizeof(struct phy), M_PHY, M_WAITOK | M_ZERO);
+	phy->cdev = cdev;
+	phy->phynode = phynode;
+	phy->enable_cnt = 0;
+
+	PHYNODE_XLOCK(phynode);
+	phynode->ref_cnt++;
+	TAILQ_INSERT_TAIL(&phynode->consumers_list, phy, link);
+	PHYNODE_UNLOCK(phynode);
+
+	return (phy);
+}
+
 int
-phy_disable(device_t consumer, phy_t phy)
+phy_enable(phy_t phy)
 {
+	int rv;
+	struct phynode *phynode;
 
-	return (PHY_ENABLE(phy->provider_dev, phy->phy_id, false));
+	phynode = phy->phynode;
+	KASSERT(phynode->ref_cnt > 0,
+	    ("Attempt to access unreferenced phy.\n"));
+
+	PHY_TOPO_SLOCK();
+	rv = phynode_enable(phynode);
+	if (rv == 0)
+		phy->enable_cnt++;
+	PHY_TOPO_UNLOCK();
+	return (rv);
 }
 
 int
-phy_status(device_t consumer, phy_t phy, int *value)
+phy_disable(phy_t phy)
 {
+	int rv;
+	struct phynode *phynode;
 
-	return (PHY_STATUS(phy->provider_dev, phy->phy_id, value));
+	phynode = phy->phynode;
+	KASSERT(phynode->ref_cnt > 0,
+	   ("Attempt to access unreferenced phy.\n"));
+	KASSERT(phy->enable_cnt > 0,
+	   ("Attempt to disable already disabled phy.\n"));
+
+	PHY_TOPO_SLOCK();
+	rv = phynode_disable(phynode);
+	if (rv == 0)
+		phy->enable_cnt--;
+	PHY_TOPO_UNLOCK();
+	return (rv);
 }
 
 int
+phy_status(phy_t phy, int *status)
+{
+	int rv;
+	struct phynode *phynode;
+
+	phynode = phy->phynode;
+	KASSERT(phynode->ref_cnt > 0,
+	   ("Attempt to access unreferenced phy.\n"));
+
+	PHY_TOPO_SLOCK();
+	rv = phynode_status(phynode, status);
+	PHY_TOPO_UNLOCK();
+	return (rv);
+}
+
+int
 phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
-    phy_t *phy_out)
+    phy_t *phy)
 {
-	phy_t phy;
+	struct phynode *phynode;
 
-	/* Create handle */
-	phy = malloc(sizeof(struct phy), M_PHY,
-	    M_WAITOK | M_ZERO);
-	phy->consumer_dev = consumer_dev;
-	phy->provider_dev = provider_dev;
-	phy->phy_id = id;
-	*phy_out = phy;
+	PHY_TOPO_SLOCK();
+
+	phynode = phynode_find_by_id(provider_dev, id);
+	if (phynode == NULL) {
+		PHY_TOPO_UNLOCK();
+		return (ENODEV);
+	}
+	*phy = phy_create(phynode, consumer_dev);
+	PHY_TOPO_UNLOCK();
+
 	return (0);
 }
 
 void
 phy_release(phy_t phy)
 {
+	struct phynode *phynode;
+
+	phynode = phy->phynode;
+	KASSERT(phynode->ref_cnt > 0,
+	   ("Attempt to access unreferenced phy.\n"));
+
+	PHY_TOPO_SLOCK();
+	while (phy->enable_cnt > 0) {
+		phynode_disable(phynode);
+		phy->enable_cnt--;
+	}
+	PHYNODE_XLOCK(phynode);
+	TAILQ_REMOVE(&phynode->consumers_list, phy, link);
+	phynode->ref_cnt--;
+	PHYNODE_UNLOCK(phynode);
+	PHY_TOPO_UNLOCK();
+
 	free(phy, M_PHY);
 }
 
-
 #ifdef FDT
-int phy_default_map(device_t provider, phandle_t xref, int ncells,
+int phydev_default_ofw_map(device_t provider, phandle_t xref, int ncells,
     pcell_t *cells, intptr_t *id)
 {
+	struct phynode *entry;
+	phandle_t node;
 
-	if (ncells == 0)
-		*id = 1;
-	else if (ncells == 1)
+	/* Single device can register multiple subnodes. */
+	if (ncells == 0) {
+
+		node = OF_node_from_xref(xref);
+		PHY_TOPO_XLOCK();
+		TAILQ_FOREACH(entry, &phynode_list, phylist_link) {
+			if ((entry->pdev == provider) &&
+			    (entry->ofw_node == node)) {
+				*id = entry->id;
+				PHY_TOPO_UNLOCK();
+				return (0);
+			}
+		}
+		PHY_TOPO_UNLOCK();
+		return (ERANGE);
+	}
+
+	/* First cell is ID. */
+	if (ncells == 1) {
 		*id = cells[0];
-	else
-		return  (ERANGE);
+		return (0);
+	}
 
-	return (0);
+	/* No default way how to get ID, custom mapper is required. */
+	return  (ERANGE);
 }
 
 int
@@ -151,7 +520,7 @@ phy_get_by_ofw_idx(device_t consumer_dev, phandle_t cn
 		return (ENODEV);
 	}
 	/* Map phy to number. */
-	rv = PHY_MAP(phydev, xnode, ncells, cells, &id);
+	rv = PHYDEV_MAP(phydev, xnode, ncells, cells, &id);
 	OF_prop_free(cells);
 	if (rv != 0)
 		return (rv);
@@ -206,33 +575,11 @@ phy_get_by_ofw_property(device_t consumer_dev, phandle
 		return (ENODEV);
 	}
 	/* Map phy to number. */
-	rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
+	rv = PHYDEV_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
 	OF_prop_free(cells);
 	if (rv != 0)
 		return (rv);
 
 	return (phy_get_by_id(consumer_dev, phydev, id, phy));
-}
-
-void
-phy_register_provider(device_t provider_dev)
-{
-	phandle_t xref, node;
-
-	node = ofw_bus_get_node(provider_dev);
-	if (node <= 0)
-		panic("%s called on not ofw based device.\n", __func__);
-
-	xref = OF_xref_from_node(node);
-	OF_device_register_xref(xref, provider_dev);
-}
-
-void
-phy_unregister_provider(device_t provider_dev)
-{
-	phandle_t xref;
-
-	xref = OF_xref_from_device(provider_dev);
-	OF_device_register_xref(xref, NULL);
 }
 #endif

Modified: head/sys/dev/extres/phy/phy.h
==============================================================================
--- head/sys/dev/extres/phy/phy.h	Sat Jan 20 15:37:47 2018	(r328200)
+++ head/sys/dev/extres/phy/phy.h	Sat Jan 20 17:02:17 2018	(r328201)
@@ -27,21 +27,49 @@
 
 #ifndef DEV_EXTRES_PHY_H
 #define DEV_EXTRES_PHY_H
-
 #include "opt_platform.h"
-#include <sys/types.h>
+
+#include <sys/kobj.h>
 #ifdef FDT

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list