Date: Sat, 20 Jan 2018 17:02:18 +0000 (UTC) From: Michal Meloun <mmel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r328201 - in head/sys: arm/allwinner arm/nvidia arm/nvidia/tegra124 conf dev/extres/phy dev/usb/controller Message-ID: <201801201702.w0KH2I4U014878@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201801201702.w0KH2I4U014878>