All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-03  1:54 ` yankejian
  0 siblings, 0 replies; 18+ messages in thread
From: yankejian @ 2015-12-03  1:54 UTC (permalink / raw)
  To: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	yankejian
  Cc: linux-kernel, linux-acpi, linuxarm

Add support for getting the PHY devices on an MDIO bus by ACPI.
Currently many of the ethernet drivers are open coding a solution
for reading data out of ACPI to find the correct PHY device.
This patch implements a set of common routines are similar to of_mdio.c

Signed-off-by: yankejian <yankejian@huawei.com>
---
 drivers/acpi/Makefile     |   3 +
 drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi_mdio.h |  68 ++++++++++++
 3 files changed, 334 insertions(+)
 create mode 100644 drivers/acpi/acpi_mdio.c
 create mode 100644 include/linux/acpi_mdio.h

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..832e7d6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
 acpi-y				+= scan.o
 acpi-y				+= resource.o
 acpi-y				+= acpi_processor.o
+acpi-y				+= acpi_mdio.o
 acpi-y				+= processor_core.o
 acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
@@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
 obj-$(CONFIG_ACPI_FAN)		+= fan.o
 obj-$(CONFIG_ACPI_VIDEO)	+= video.o
 obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
+obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
 obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
 obj-y				+= container.o
 obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
@@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
+obj-$(CONFIG_IORT_TABLE) 	+= iort.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o
diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
new file mode 100644
index 0000000..3a5871d
--- /dev/null
+++ b/drivers/acpi/acpi_mdio.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/acpi_mdio.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock_types.h>
+
+static
+int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
+			      u32 addr)
+{
+	struct phy_device *phy;
+	const char *phy_type;
+	bool is_c45;
+	int rc;
+
+	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
+	if (rc < 0)
+		return rc;
+
+	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
+		     sizeof("ethernet-phy-ieee802.3-c45")))
+		is_c45 = 1;
+	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
+			  sizeof("ethernet-phy-ieee802.3-c22")))
+		is_c45 = 0;
+	else
+		return -ENODATA;
+
+	phy = get_phy_device(mdio, addr, is_c45);
+	if (!phy || IS_ERR(phy))
+		return 1;
+
+	/* Associate the fw node with the device structure so it
+	 * can be looked up later
+	 */
+	phy->dev.fwnode = child;
+
+	if (mdio->irq)
+		phy->irq = mdio->irq[addr];
+
+	if (fwnode_property_read_bool(child, "broken-turn-around"))
+		mdio->phy_ignore_ta_mask |= 1 << addr;
+
+	/* All data is now stored in the phy struct;
+	 * register it
+	 */
+	rc = phy_device_register(phy);
+	if (rc) {
+		phy_device_free(phy);
+		return 1;
+	}
+
+	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
+
+	return 0;
+}
+
+int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
+{
+	u32 addr;
+	int ret;
+
+	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
+	if (ret < 0) {
+		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
+		return ret;
+	}
+
+	if (addr >= PHY_MAX_ADDR) {
+		dev_err(dev, "PHY address %i is too large\n", addr);
+		return -EINVAL;
+	}
+
+	return addr;
+}
+EXPORT_SYMBOL(acpi_mdio_parse_addr);
+
+/**
+ * acpi_mdiobus_register - Register mii_bus and create PHYs
+ * @mdio: pointer to mii_bus structure
+ * @fwnode: pointer to framework node of MDIO bus.
+ *
+ * This function registers the mii_bus structure and registers a phy_device
+ * for each child node of mdio device.
+ */
+int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
+{
+	struct fwnode_handle *child;
+	struct acpi_device *adev;
+	bool scanphys = false;
+	int addr, rc, i;
+
+	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
+	 * the framework node are populated after the bus has been registered
+	 */
+	mdio->phy_mask = ~0;
+
+	/* Clear all the IRQ properties */
+	if (mdio->irq)
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			mdio->irq[i] = PHY_POLL;
+
+	mdio->dev.fwnode = fwnode;
+
+	/* Register the MDIO bus */
+	rc = mdiobus_register(mdio);
+	if (rc)
+		return rc;
+
+	/* Loop over the child nodes and register a phy_device for each one */
+	device_for_each_child_node(&mdio->dev, child) {
+		adev = to_acpi_device_node(child);
+		if (!adev)
+			continue;
+
+		addr = acpi_mdio_parse_addr(&adev->dev, child);
+		if (addr < 0) {
+			scanphys = true;
+			continue;
+		}
+
+		rc = acpi_mdiobus_register_phy(mdio, child, addr);
+		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
+		if (rc)
+			continue;
+	}
+
+	if (!scanphys)
+		return 0;
+
+	/* auto scan for PHYs with empty reg property */
+	device_for_each_child_node(&mdio->dev, child) {
+		/* Skip PHYs with reg property set */
+		if (!fwnode_property_present(child, "reg"))
+			continue;
+
+		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+			/* skip already registered PHYs */
+			if (mdio->phy_map[addr])
+				continue;
+
+			/* be noisy to encourage people to set reg property */
+			dev_info(&mdio->dev, "scan phy %s at address %i\n",
+				 acpi_dev_name(to_acpi_device_node(child)),
+				 addr);
+
+			rc = acpi_mdiobus_register_phy(mdio, child, addr);
+			if (rc)
+				continue;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_mdiobus_register);
+
+/* Helper function for acpi_phy_find_device */
+static int acpi_phy_match(struct device *dev, void *phy_fwnode)
+{
+	return dev->fwnode == phy_fwnode;
+}
+
+/**
+ * acpi_phy_find_device - Give a PHY node, find the phy_device
+ * @phy_fwnode: Pointer to the phy's framework node
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure.
+ */
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
+{
+	struct device *d;
+
+	if (!phy_fwnode)
+		return NULL;
+
+	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
+
+	return d ? to_phy_device(d) : NULL;
+}
+EXPORT_SYMBOL(acpi_phy_find_device);
+
+/**
+ * acpi_phy_attach - Attach to a PHY without starting the state machine
+ * @dev: pointer to net_device claiming the phy
+ * @phy_fwnode: framework Node pointer for the PHY
+ * @flags: flags to pass to the PHY
+ * @iface: PHY data interface type
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
+ */
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface)
+{
+	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
+	int ret;
+
+	if (!phy)
+		return NULL;
+
+	ret = phy_attach_direct(dev, phy, flags, iface);
+
+	/* refcount is held by phy_attach_direct() on success */
+	put_device(&phy->dev);
+
+	return ret ? NULL : phy;
+}
+EXPORT_SYMBOL(acpi_phy_attach);
+
+/**
+ * acpi_phy_connect - Connect to the phy described
+ * @dev: pointer to net_device claiming the phy
+ * @phy_fwnode: Pointer to framework node for the PHY
+ * @hndlr: Link state callback for the network device
+ * @iface: PHY data interface type
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
+ */
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface)
+{
+	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
+	int ret;
+
+	if (!phy)
+		return NULL;
+
+	phy->dev_flags = flags;
+
+	ret = phy_connect_direct(dev, phy, hndlr, iface);
+
+	/* refcount is held by phy_connect_direct() on success */
+	put_device(&phy->dev);
+
+	return ret ? NULL : phy;
+}
+EXPORT_SYMBOL(acpi_phy_connect);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
new file mode 100644
index 0000000..82b5be5
--- /dev/null
+++ b/include/linux/acpi_mdio.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_ACPI_MDIO_H
+#define __LINUX_ACPI_MDIO_H
+
+#include <linux/phy.h>
+
+#ifdef CONFIG_ACPI
+
+int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
+int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface);
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface);
+
+#else
+static inline int acpi_mdio_parse_addr(struct device *dev,
+				       struct fwnode_handle *fwnode)
+{
+	return -ENXIO;
+}
+
+static inline int acpi_mdiobus_register(struct mii_bus *mdio,
+					struct fwnode_handle *fwnode)
+{
+	return -ENXIO;
+}
+
+static inline
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
+{
+	return NULL;
+}
+
+static inline
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface)
+{
+	return NULL;
+}
+
+static inline
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface)
+{
+	return NULL;
+}
+
+#endif
+
+#endif /* __LINUX_ACPI_MDIO_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-03  1:54 ` yankejian
  0 siblings, 0 replies; 18+ messages in thread
From: yankejian @ 2015-12-03  1:54 UTC (permalink / raw)
  To: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	yankejian
  Cc: linux-kernel, linux-acpi, linuxarm

Add support for getting the PHY devices on an MDIO bus by ACPI.
Currently many of the ethernet drivers are open coding a solution
for reading data out of ACPI to find the correct PHY device.
This patch implements a set of common routines are similar to of_mdio.c

Signed-off-by: yankejian <yankejian@huawei.com>
---
 drivers/acpi/Makefile     |   3 +
 drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi_mdio.h |  68 ++++++++++++
 3 files changed, 334 insertions(+)
 create mode 100644 drivers/acpi/acpi_mdio.c
 create mode 100644 include/linux/acpi_mdio.h

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..832e7d6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
 acpi-y				+= scan.o
 acpi-y				+= resource.o
 acpi-y				+= acpi_processor.o
+acpi-y				+= acpi_mdio.o
 acpi-y				+= processor_core.o
 acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
@@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
 obj-$(CONFIG_ACPI_FAN)		+= fan.o
 obj-$(CONFIG_ACPI_VIDEO)	+= video.o
 obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
+obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
 obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
 obj-y				+= container.o
 obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
@@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
+obj-$(CONFIG_IORT_TABLE) 	+= iort.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o
diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
new file mode 100644
index 0000000..3a5871d
--- /dev/null
+++ b/drivers/acpi/acpi_mdio.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/acpi_mdio.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock_types.h>
+
+static
+int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
+			      u32 addr)
+{
+	struct phy_device *phy;
+	const char *phy_type;
+	bool is_c45;
+	int rc;
+
+	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
+	if (rc < 0)
+		return rc;
+
+	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
+		     sizeof("ethernet-phy-ieee802.3-c45")))
+		is_c45 = 1;
+	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
+			  sizeof("ethernet-phy-ieee802.3-c22")))
+		is_c45 = 0;
+	else
+		return -ENODATA;
+
+	phy = get_phy_device(mdio, addr, is_c45);
+	if (!phy || IS_ERR(phy))
+		return 1;
+
+	/* Associate the fw node with the device structure so it
+	 * can be looked up later
+	 */
+	phy->dev.fwnode = child;
+
+	if (mdio->irq)
+		phy->irq = mdio->irq[addr];
+
+	if (fwnode_property_read_bool(child, "broken-turn-around"))
+		mdio->phy_ignore_ta_mask |= 1 << addr;
+
+	/* All data is now stored in the phy struct;
+	 * register it
+	 */
+	rc = phy_device_register(phy);
+	if (rc) {
+		phy_device_free(phy);
+		return 1;
+	}
+
+	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
+
+	return 0;
+}
+
+int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
+{
+	u32 addr;
+	int ret;
+
+	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
+	if (ret < 0) {
+		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
+		return ret;
+	}
+
+	if (addr >= PHY_MAX_ADDR) {
+		dev_err(dev, "PHY address %i is too large\n", addr);
+		return -EINVAL;
+	}
+
+	return addr;
+}
+EXPORT_SYMBOL(acpi_mdio_parse_addr);
+
+/**
+ * acpi_mdiobus_register - Register mii_bus and create PHYs
+ * @mdio: pointer to mii_bus structure
+ * @fwnode: pointer to framework node of MDIO bus.
+ *
+ * This function registers the mii_bus structure and registers a phy_device
+ * for each child node of mdio device.
+ */
+int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
+{
+	struct fwnode_handle *child;
+	struct acpi_device *adev;
+	bool scanphys = false;
+	int addr, rc, i;
+
+	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
+	 * the framework node are populated after the bus has been registered
+	 */
+	mdio->phy_mask = ~0;
+
+	/* Clear all the IRQ properties */
+	if (mdio->irq)
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			mdio->irq[i] = PHY_POLL;
+
+	mdio->dev.fwnode = fwnode;
+
+	/* Register the MDIO bus */
+	rc = mdiobus_register(mdio);
+	if (rc)
+		return rc;
+
+	/* Loop over the child nodes and register a phy_device for each one */
+	device_for_each_child_node(&mdio->dev, child) {
+		adev = to_acpi_device_node(child);
+		if (!adev)
+			continue;
+
+		addr = acpi_mdio_parse_addr(&adev->dev, child);
+		if (addr < 0) {
+			scanphys = true;
+			continue;
+		}
+
+		rc = acpi_mdiobus_register_phy(mdio, child, addr);
+		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
+		if (rc)
+			continue;
+	}
+
+	if (!scanphys)
+		return 0;
+
+	/* auto scan for PHYs with empty reg property */
+	device_for_each_child_node(&mdio->dev, child) {
+		/* Skip PHYs with reg property set */
+		if (!fwnode_property_present(child, "reg"))
+			continue;
+
+		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+			/* skip already registered PHYs */
+			if (mdio->phy_map[addr])
+				continue;
+
+			/* be noisy to encourage people to set reg property */
+			dev_info(&mdio->dev, "scan phy %s at address %i\n",
+				 acpi_dev_name(to_acpi_device_node(child)),
+				 addr);
+
+			rc = acpi_mdiobus_register_phy(mdio, child, addr);
+			if (rc)
+				continue;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_mdiobus_register);
+
+/* Helper function for acpi_phy_find_device */
+static int acpi_phy_match(struct device *dev, void *phy_fwnode)
+{
+	return dev->fwnode == phy_fwnode;
+}
+
+/**
+ * acpi_phy_find_device - Give a PHY node, find the phy_device
+ * @phy_fwnode: Pointer to the phy's framework node
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure.
+ */
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
+{
+	struct device *d;
+
+	if (!phy_fwnode)
+		return NULL;
+
+	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
+
+	return d ? to_phy_device(d) : NULL;
+}
+EXPORT_SYMBOL(acpi_phy_find_device);
+
+/**
+ * acpi_phy_attach - Attach to a PHY without starting the state machine
+ * @dev: pointer to net_device claiming the phy
+ * @phy_fwnode: framework Node pointer for the PHY
+ * @flags: flags to pass to the PHY
+ * @iface: PHY data interface type
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
+ */
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface)
+{
+	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
+	int ret;
+
+	if (!phy)
+		return NULL;
+
+	ret = phy_attach_direct(dev, phy, flags, iface);
+
+	/* refcount is held by phy_attach_direct() on success */
+	put_device(&phy->dev);
+
+	return ret ? NULL : phy;
+}
+EXPORT_SYMBOL(acpi_phy_attach);
+
+/**
+ * acpi_phy_connect - Connect to the phy described
+ * @dev: pointer to net_device claiming the phy
+ * @phy_fwnode: Pointer to framework node for the PHY
+ * @hndlr: Link state callback for the network device
+ * @iface: PHY data interface type
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
+ */
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface)
+{
+	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
+	int ret;
+
+	if (!phy)
+		return NULL;
+
+	phy->dev_flags = flags;
+
+	ret = phy_connect_direct(dev, phy, hndlr, iface);
+
+	/* refcount is held by phy_connect_direct() on success */
+	put_device(&phy->dev);
+
+	return ret ? NULL : phy;
+}
+EXPORT_SYMBOL(acpi_phy_connect);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
new file mode 100644
index 0000000..82b5be5
--- /dev/null
+++ b/include/linux/acpi_mdio.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_ACPI_MDIO_H
+#define __LINUX_ACPI_MDIO_H
+
+#include <linux/phy.h>
+
+#ifdef CONFIG_ACPI
+
+int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
+int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface);
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface);
+
+#else
+static inline int acpi_mdio_parse_addr(struct device *dev,
+				       struct fwnode_handle *fwnode)
+{
+	return -ENXIO;
+}
+
+static inline int acpi_mdiobus_register(struct mii_bus *mdio,
+					struct fwnode_handle *fwnode)
+{
+	return -ENXIO;
+}
+
+static inline
+struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
+{
+	return NULL;
+}
+
+static inline
+struct phy_device *acpi_phy_attach(struct net_device *dev,
+				   struct fwnode_handle *phy_fwnode, u32 flags,
+				   phy_interface_t iface)
+{
+	return NULL;
+}
+
+static inline
+struct phy_device *acpi_phy_connect(struct net_device *dev,
+				    struct fwnode_handle *phy_fwnode,
+				    void (*hndlr)(struct net_device *),
+				    u32 flags,
+				    phy_interface_t iface)
+{
+	return NULL;
+}
+
+#endif
+
+#endif /* __LINUX_ACPI_MDIO_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-03  1:54 ` yankejian
@ 2015-12-03  4:45   ` kbuild test robot
  -1 siblings, 0 replies; 18+ messages in thread
From: kbuild test robot @ 2015-12-03  4:45 UTC (permalink / raw)
  To: yankejian
  Cc: kbuild-all, rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode,
	lipeng321, yankejian, linux-kernel, linux-acpi, linuxarm

[-- Attachment #1: Type: text/plain, Size: 813 bytes --]

Hi yankejian,

[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.4-rc3 next-20151202]

url:    https://github.com/0day-ci/linux/commits/yankejian/ACPI-Add-phylib-support-code-for-mdio/20151203-115039
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-s1-201548 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> make[3]: *** No rule to make target 'drivers/acpi/mcfg.o', needed by 'drivers/acpi/built-in.o'.
   make[3]: Target '__build' not remade because of errors.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 23950 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-03  4:45   ` kbuild test robot
  0 siblings, 0 replies; 18+ messages in thread
From: kbuild test robot @ 2015-12-03  4:45 UTC (permalink / raw)
  Cc: kbuild-all, rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode,
	lipeng321, yankejian, linux-kernel, linux-acpi, linuxarm

[-- Attachment #1: Type: text/plain, Size: 813 bytes --]

Hi yankejian,

[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.4-rc3 next-20151202]

url:    https://github.com/0day-ci/linux/commits/yankejian/ACPI-Add-phylib-support-code-for-mdio/20151203-115039
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-s1-201548 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> make[3]: *** No rule to make target 'drivers/acpi/mcfg.o', needed by 'drivers/acpi/built-in.o'.
   make[3]: Target '__build' not remade because of errors.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 23950 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-03  1:54 ` yankejian
@ 2015-12-03  4:55   ` kbuild test robot
  -1 siblings, 0 replies; 18+ messages in thread
From: kbuild test robot @ 2015-12-03  4:55 UTC (permalink / raw)
  To: yankejian
  Cc: kbuild-all, rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode,
	lipeng321, yankejian, linux-kernel, linux-acpi, linuxarm

[-- Attachment #1: Type: text/plain, Size: 1419 bytes --]

Hi yankejian,

[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.4-rc3 next-20151202]

url:    https://github.com/0day-ci/linux/commits/yankejian/ACPI-Add-phylib-support-code-for-mdio/20151203-115039
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-i0-201548 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `acpi_mdiobus_register_phy':
>> acpi_mdio.c:(.text+0x2de27): undefined reference to `get_phy_device'
>> acpi_mdio.c:(.text+0x2de84): undefined reference to `phy_device_register'
>> acpi_mdio.c:(.text+0x2de8f): undefined reference to `phy_device_free'
   drivers/built-in.o: In function `acpi_phy_find_device':
>> (.text+0x2dee4): undefined reference to `mdio_bus_type'
   drivers/built-in.o: In function `acpi_phy_attach':
>> (.text+0x2df25): undefined reference to `phy_attach_direct'
   drivers/built-in.o: In function `acpi_phy_connect':
>> (.text+0x2df71): undefined reference to `phy_connect_direct'
   drivers/built-in.o: In function `acpi_mdiobus_register':
>> (.text+0x2e01a): undefined reference to `__mdiobus_register'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 24519 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-03  4:55   ` kbuild test robot
  0 siblings, 0 replies; 18+ messages in thread
From: kbuild test robot @ 2015-12-03  4:55 UTC (permalink / raw)
  Cc: kbuild-all, rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode,
	lipeng321, yankejian, linux-kernel, linux-acpi, linuxarm

[-- Attachment #1: Type: text/plain, Size: 1419 bytes --]

Hi yankejian,

[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.4-rc3 next-20151202]

url:    https://github.com/0day-ci/linux/commits/yankejian/ACPI-Add-phylib-support-code-for-mdio/20151203-115039
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: i386-randconfig-i0-201548 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `acpi_mdiobus_register_phy':
>> acpi_mdio.c:(.text+0x2de27): undefined reference to `get_phy_device'
>> acpi_mdio.c:(.text+0x2de84): undefined reference to `phy_device_register'
>> acpi_mdio.c:(.text+0x2de8f): undefined reference to `phy_device_free'
   drivers/built-in.o: In function `acpi_phy_find_device':
>> (.text+0x2dee4): undefined reference to `mdio_bus_type'
   drivers/built-in.o: In function `acpi_phy_attach':
>> (.text+0x2df25): undefined reference to `phy_attach_direct'
   drivers/built-in.o: In function `acpi_phy_connect':
>> (.text+0x2df71): undefined reference to `phy_connect_direct'
   drivers/built-in.o: In function `acpi_mdiobus_register':
>> (.text+0x2e01a): undefined reference to `__mdiobus_register'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 24519 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-03  1:54 ` yankejian
                   ` (2 preceding siblings ...)
  (?)
@ 2015-12-03 10:47 ` Graeme Gregory
  2015-12-08 19:55   ` Al Stone
  2016-01-12 12:12     ` Yankejian (Hackim Yim)
  -1 siblings, 2 replies; 18+ messages in thread
From: Graeme Gregory @ 2015-12-03 10:47 UTC (permalink / raw)
  To: yankejian
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm

On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
> Add support for getting the PHY devices on an MDIO bus by ACPI.
> Currently many of the ethernet drivers are open coding a solution
> for reading data out of ACPI to find the correct PHY device.
> This patch implements a set of common routines are similar to of_mdio.c
> 

The general conclusion for the ACPI on ARM64 discussion so far has been that
things like PHYs should be setup by the firmware before the kernel takes
control.

I am unsure that this doing it the same way as DT with a different
description language is the way to go.

Graeme

> Signed-off-by: yankejian <yankejian@huawei.com>
> ---
>  drivers/acpi/Makefile     |   3 +
>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/acpi_mdio.h |  68 ++++++++++++
>  3 files changed, 334 insertions(+)
>  create mode 100644 drivers/acpi/acpi_mdio.c
>  create mode 100644 include/linux/acpi_mdio.h
> 
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 675eaf3..832e7d6 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
>  acpi-y				+= scan.o
>  acpi-y				+= resource.o
>  acpi-y				+= acpi_processor.o
> +acpi-y				+= acpi_mdio.o
>  acpi-y				+= processor_core.o
>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
>  acpi-y				+= ec.o
> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
>  obj-y				+= container.o
>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
>  
>  # processor has its own "processor." module_param namespace
>  processor-y			:= processor_driver.o
> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
> new file mode 100644
> index 0000000..3a5871d
> --- /dev/null
> +++ b/drivers/acpi/acpi_mdio.c
> @@ -0,0 +1,263 @@
> +/*
> + * Copyright (c) 2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/acpi_mdio.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/phy.h>
> +#include <linux/phy_fixed.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock_types.h>
> +
> +static
> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
> +			      u32 addr)
> +{
> +	struct phy_device *phy;
> +	const char *phy_type;
> +	bool is_c45;
> +	int rc;
> +
> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
> +	if (rc < 0)
> +		return rc;
> +
> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
> +		     sizeof("ethernet-phy-ieee802.3-c45")))
> +		is_c45 = 1;
> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
> +			  sizeof("ethernet-phy-ieee802.3-c22")))
> +		is_c45 = 0;
> +	else
> +		return -ENODATA;
> +
> +	phy = get_phy_device(mdio, addr, is_c45);
> +	if (!phy || IS_ERR(phy))
> +		return 1;
> +
> +	/* Associate the fw node with the device structure so it
> +	 * can be looked up later
> +	 */
> +	phy->dev.fwnode = child;
> +
> +	if (mdio->irq)
> +		phy->irq = mdio->irq[addr];
> +
> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
> +		mdio->phy_ignore_ta_mask |= 1 << addr;
> +
> +	/* All data is now stored in the phy struct;
> +	 * register it
> +	 */
> +	rc = phy_device_register(phy);
> +	if (rc) {
> +		phy_device_free(phy);
> +		return 1;
> +	}
> +
> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
> +
> +	return 0;
> +}
> +
> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
> +{
> +	u32 addr;
> +	int ret;
> +
> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
> +	if (ret < 0) {
> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
> +		return ret;
> +	}
> +
> +	if (addr >= PHY_MAX_ADDR) {
> +		dev_err(dev, "PHY address %i is too large\n", addr);
> +		return -EINVAL;
> +	}
> +
> +	return addr;
> +}
> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
> +
> +/**
> + * acpi_mdiobus_register - Register mii_bus and create PHYs
> + * @mdio: pointer to mii_bus structure
> + * @fwnode: pointer to framework node of MDIO bus.
> + *
> + * This function registers the mii_bus structure and registers a phy_device
> + * for each child node of mdio device.
> + */
> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
> +{
> +	struct fwnode_handle *child;
> +	struct acpi_device *adev;
> +	bool scanphys = false;
> +	int addr, rc, i;
> +
> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
> +	 * the framework node are populated after the bus has been registered
> +	 */
> +	mdio->phy_mask = ~0;
> +
> +	/* Clear all the IRQ properties */
> +	if (mdio->irq)
> +		for (i = 0; i < PHY_MAX_ADDR; i++)
> +			mdio->irq[i] = PHY_POLL;
> +
> +	mdio->dev.fwnode = fwnode;
> +
> +	/* Register the MDIO bus */
> +	rc = mdiobus_register(mdio);
> +	if (rc)
> +		return rc;
> +
> +	/* Loop over the child nodes and register a phy_device for each one */
> +	device_for_each_child_node(&mdio->dev, child) {
> +		adev = to_acpi_device_node(child);
> +		if (!adev)
> +			continue;
> +
> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
> +		if (addr < 0) {
> +			scanphys = true;
> +			continue;
> +		}
> +
> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
> +		if (rc)
> +			continue;
> +	}
> +
> +	if (!scanphys)
> +		return 0;
> +
> +	/* auto scan for PHYs with empty reg property */
> +	device_for_each_child_node(&mdio->dev, child) {
> +		/* Skip PHYs with reg property set */
> +		if (!fwnode_property_present(child, "reg"))
> +			continue;
> +
> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
> +			/* skip already registered PHYs */
> +			if (mdio->phy_map[addr])
> +				continue;
> +
> +			/* be noisy to encourage people to set reg property */
> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
> +				 acpi_dev_name(to_acpi_device_node(child)),
> +				 addr);
> +
> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
> +			if (rc)
> +				continue;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(acpi_mdiobus_register);
> +
> +/* Helper function for acpi_phy_find_device */
> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
> +{
> +	return dev->fwnode == phy_fwnode;
> +}
> +
> +/**
> + * acpi_phy_find_device - Give a PHY node, find the phy_device
> + * @phy_fwnode: Pointer to the phy's framework node
> + *
> + * If successful, returns a pointer to the phy_device with the embedded
> + * struct device refcount incremented by one, or NULL on failure.
> + */
> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> +{
> +	struct device *d;
> +
> +	if (!phy_fwnode)
> +		return NULL;
> +
> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
> +
> +	return d ? to_phy_device(d) : NULL;
> +}
> +EXPORT_SYMBOL(acpi_phy_find_device);
> +
> +/**
> + * acpi_phy_attach - Attach to a PHY without starting the state machine
> + * @dev: pointer to net_device claiming the phy
> + * @phy_fwnode: framework Node pointer for the PHY
> + * @flags: flags to pass to the PHY
> + * @iface: PHY data interface type
> + *
> + * If successful, returns a pointer to the phy_device with the embedded
> + * struct device refcount incremented by one, or NULL on failure. The
> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> + */
> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> +				   phy_interface_t iface)
> +{
> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> +	int ret;
> +
> +	if (!phy)
> +		return NULL;
> +
> +	ret = phy_attach_direct(dev, phy, flags, iface);
> +
> +	/* refcount is held by phy_attach_direct() on success */
> +	put_device(&phy->dev);
> +
> +	return ret ? NULL : phy;
> +}
> +EXPORT_SYMBOL(acpi_phy_attach);
> +
> +/**
> + * acpi_phy_connect - Connect to the phy described
> + * @dev: pointer to net_device claiming the phy
> + * @phy_fwnode: Pointer to framework node for the PHY
> + * @hndlr: Link state callback for the network device
> + * @iface: PHY data interface type
> + *
> + * If successful, returns a pointer to the phy_device with the embedded
> + * struct device refcount incremented by one, or NULL on failure. The
> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> + */
> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> +				    struct fwnode_handle *phy_fwnode,
> +				    void (*hndlr)(struct net_device *),
> +				    u32 flags,
> +				    phy_interface_t iface)
> +{
> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> +	int ret;
> +
> +	if (!phy)
> +		return NULL;
> +
> +	phy->dev_flags = flags;
> +
> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
> +
> +	/* refcount is held by phy_connect_direct() on success */
> +	put_device(&phy->dev);
> +
> +	return ret ? NULL : phy;
> +}
> +EXPORT_SYMBOL(acpi_phy_connect);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
> new file mode 100644
> index 0000000..82b5be5
> --- /dev/null
> +++ b/include/linux/acpi_mdio.h
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright (c) 2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __LINUX_ACPI_MDIO_H
> +#define __LINUX_ACPI_MDIO_H
> +
> +#include <linux/phy.h>
> +
> +#ifdef CONFIG_ACPI
> +
> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> +				   phy_interface_t iface);
> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> +				    struct fwnode_handle *phy_fwnode,
> +				    void (*hndlr)(struct net_device *),
> +				    u32 flags,
> +				    phy_interface_t iface);
> +
> +#else
> +static inline int acpi_mdio_parse_addr(struct device *dev,
> +				       struct fwnode_handle *fwnode)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
> +					struct fwnode_handle *fwnode)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline
> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> +{
> +	return NULL;
> +}
> +
> +static inline
> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> +				   phy_interface_t iface)
> +{
> +	return NULL;
> +}
> +
> +static inline
> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> +				    struct fwnode_handle *phy_fwnode,
> +				    void (*hndlr)(struct net_device *),
> +				    u32 flags,
> +				    phy_interface_t iface)
> +{
> +	return NULL;
> +}
> +
> +#endif
> +
> +#endif /* __LINUX_ACPI_MDIO_H */
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-03 10:47 ` Graeme Gregory
@ 2015-12-08 19:55   ` Al Stone
  2015-12-09 10:31       ` Yankejian (Hackim Yim)
  2016-01-12 12:12     ` Yankejian (Hackim Yim)
  1 sibling, 1 reply; 18+ messages in thread
From: Al Stone @ 2015-12-08 19:55 UTC (permalink / raw)
  To: Graeme Gregory, yankejian
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm

On 12/03/2015 03:47 AM, Graeme Gregory wrote:
> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>> Currently many of the ethernet drivers are open coding a solution
>> for reading data out of ACPI to find the correct PHY device.
>> This patch implements a set of common routines are similar to of_mdio.c
>>
> 
> The general conclusion for the ACPI on ARM64 discussion so far has been that
> things like PHYs should be setup by the firmware before the kernel takes
> control.
> 
> I am unsure that this doing it the same way as DT with a different
> description language is the way to go.
> 
> Graeme

I have to agree with Graeme: if this is supposed to be an arm64 server using
ACPI, please make sure the PHYs/clocks/regulators are set up properly before
passing control to the kernel.  That's the consensus so far on how this is to
be done.

This also looks to be using _DSD in ACPI, which is another topic that's still
under discussion.  What does the ASL look like for these PHYs, as used in this
patch?

-- 
ciao,
al
-----------------------------------
Al Stone
Software Engineer
Red Hat, Inc.
ahs3@redhat.com
-----------------------------------

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-08 19:55   ` Al Stone
@ 2015-12-09 10:31       ` Yankejian (Hackim Yim)
  0 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2015-12-09 10:31 UTC (permalink / raw)
  To: Al Stone, Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On 2015/12/9 3:55, Al Stone wrote:
> On 12/03/2015 03:47 AM, Graeme Gregory wrote:
>> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>>> Currently many of the ethernet drivers are open coding a solution
>>> for reading data out of ACPI to find the correct PHY device.
>>> This patch implements a set of common routines are similar to of_mdio.c
>>>
>> The general conclusion for the ACPI on ARM64 discussion so far has been that
>> things like PHYs should be setup by the firmware before the kernel takes
>> control.
>>
>> I am unsure that this doing it the same way as DT with a different
>> description language is the way to go.
>>
>> Graeme
> I have to agree with Graeme: if this is supposed to be an arm64 server using
> ACPI, please make sure the PHYs/clocks/regulators are set up properly before
> passing control to the kernel.  That's the consensus so far on how this is to
> be done.
>
> This also looks to be using _DSD in ACPI, which is another topic that's still
> under discussion.  What does the ASL look like for these PHYs, as used in this
> patch?
>
Hi Al

The sample of the ASL for these PHYs is below:

                Device (PHY0) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 0},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }

Best Regards,
yankejian



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-09 10:31       ` Yankejian (Hackim Yim)
  0 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2015-12-09 10:31 UTC (permalink / raw)
  To: Al Stone, Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On 2015/12/9 3:55, Al Stone wrote:
> On 12/03/2015 03:47 AM, Graeme Gregory wrote:
>> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>>> Currently many of the ethernet drivers are open coding a solution
>>> for reading data out of ACPI to find the correct PHY device.
>>> This patch implements a set of common routines are similar to of_mdio.c
>>>
>> The general conclusion for the ACPI on ARM64 discussion so far has been that
>> things like PHYs should be setup by the firmware before the kernel takes
>> control.
>>
>> I am unsure that this doing it the same way as DT with a different
>> description language is the way to go.
>>
>> Graeme
> I have to agree with Graeme: if this is supposed to be an arm64 server using
> ACPI, please make sure the PHYs/clocks/regulators are set up properly before
> passing control to the kernel.  That's the consensus so far on how this is to
> be done.
>
> This also looks to be using _DSD in ACPI, which is another topic that's still
> under discussion.  What does the ASL look like for these PHYs, as used in this
> patch?
>
Hi Al

The sample of the ASL for these PHYs is below:

                Device (PHY0) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 0},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }

Best Regards,
yankejian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-09 10:31       ` Yankejian (Hackim Yim)
@ 2015-12-10  1:27         ` Yankejian (Hackim Yim)
  -1 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2015-12-10  1:27 UTC (permalink / raw)
  To: Al Stone, Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On 2015/12/9 18:31, Yankejian (Hackim Yim) wrote:
>
> On 2015/12/9 3:55, Al Stone wrote:
>> On 12/03/2015 03:47 AM, Graeme Gregory wrote:
>>> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>>>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>>>> Currently many of the ethernet drivers are open coding a solution
>>>> for reading data out of ACPI to find the correct PHY device.
>>>> This patch implements a set of common routines are similar to of_mdio.c
>>>>
>>> The general conclusion for the ACPI on ARM64 discussion so far has been that
>>> things like PHYs should be setup by the firmware before the kernel takes
>>> control.
>>>
>>> I am unsure that this doing it the same way as DT with a different
>>> description language is the way to go.
>>>
>>> Graeme
>> I have to agree with Graeme: if this is supposed to be an arm64 server using
>> ACPI, please make sure the PHYs/clocks/regulators are set up properly before
>> passing control to the kernel.  That's the consensus so far on how this is to
>> be done.
>>
>> This also looks to be using _DSD in ACPI, which is another topic that's still
>> under discussion.  What does the ASL look like for these PHYs, as used in this
>> patch?
>>
> Hi Al
>
> The sample of the ASL for these PHYs is below:
>
>                 Device (PHY0) {
>                         Name (_DSD, Package () {
>                                 ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>                                 Package () {
>                                         Package () {"phy-addr", 0},
>                                         Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
>                                 }
>                         })
>                 }
>
> Best Regards,
> yankejian
>
Maybe we need to add the ASL for mdio as well, the sample is shown below:

Device (MDIO) {
                Name(_HID, "HISI00B1")
                Name (_CRS, ResourceTemplate (){
                        Memory32Fixed (ReadWrite, 0x803c0000 , 0x10000)
                })

                Device (PHY0) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 0},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }
                Device (PHY1) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 1},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }
        }

Best Regards,
yankejian




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2015-12-10  1:27         ` Yankejian (Hackim Yim)
  0 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2015-12-10  1:27 UTC (permalink / raw)
  To: Al Stone, Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On 2015/12/9 18:31, Yankejian (Hackim Yim) wrote:
>
> On 2015/12/9 3:55, Al Stone wrote:
>> On 12/03/2015 03:47 AM, Graeme Gregory wrote:
>>> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>>>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>>>> Currently many of the ethernet drivers are open coding a solution
>>>> for reading data out of ACPI to find the correct PHY device.
>>>> This patch implements a set of common routines are similar to of_mdio.c
>>>>
>>> The general conclusion for the ACPI on ARM64 discussion so far has been that
>>> things like PHYs should be setup by the firmware before the kernel takes
>>> control.
>>>
>>> I am unsure that this doing it the same way as DT with a different
>>> description language is the way to go.
>>>
>>> Graeme
>> I have to agree with Graeme: if this is supposed to be an arm64 server using
>> ACPI, please make sure the PHYs/clocks/regulators are set up properly before
>> passing control to the kernel.  That's the consensus so far on how this is to
>> be done.
>>
>> This also looks to be using _DSD in ACPI, which is another topic that's still
>> under discussion.  What does the ASL look like for these PHYs, as used in this
>> patch?
>>
> Hi Al
>
> The sample of the ASL for these PHYs is below:
>
>                 Device (PHY0) {
>                         Name (_DSD, Package () {
>                                 ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>                                 Package () {
>                                         Package () {"phy-addr", 0},
>                                         Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
>                                 }
>                         })
>                 }
>
> Best Regards,
> yankejian
>
Maybe we need to add the ASL for mdio as well, the sample is shown below:

Device (MDIO) {
                Name(_HID, "HISI00B1")
                Name (_CRS, ResourceTemplate (){
                        Memory32Fixed (ReadWrite, 0x803c0000 , 0x10000)
                })

                Device (PHY0) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 0},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }
                Device (PHY1) {
                        Name (_DSD, Package () {
                                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                                Package () {
                                        Package () {"phy-addr", 1},
                                        Package () {"ethernet-phy", "ethernet-phy-ieee802.3-c22"},
                                }
                        })
                }
        }

Best Regards,
yankejian




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2015-12-03 10:47 ` Graeme Gregory
@ 2016-01-12 12:12     ` Yankejian (Hackim Yim)
  2016-01-12 12:12     ` Yankejian (Hackim Yim)
  1 sibling, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2016-01-12 12:12 UTC (permalink / raw)
  To: Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm

Hi Graeme,
I some how missed to reply this. Sorry for this!

HNS needs to configure PHYs dynamically parameter. So HNS try to call
Linux PHY driver to help access to PHYs. If PHYs access will be implemented in BIOS,
it seems that HNS needs repeatedly communication with BIOS.
And we have read other ethernet drivers with PHYs as well, like
1) APM X-Gene Ethernet Driver, and
2) AMD 10Gb Ethernet driver, and
3) Intel IXGBE.
Both AMD and Intel try to implement PHYs access routines itself. The drivers
needs to implement PHY access routines includes the popular PHYs.
APM X-Gene Ethernet Driver needs Linux PHY driver help to access PHYs. It
implements the new routines help to access Linux PHY driver, then access PHYs.
As the drivers shows, each MDIO controller connects one PHY. Sometimes, one MDIO
may control several PHYs, like HNS.

Firstly, let's go over the HNS hardware topology as below. The MDIO controller may
control several PHYs, and each PHY connects to a MAC device.
                       cpu                       
                        |                        
                        |                        
     ------------------------------------------- 
    |                   |                       |
    |                   |                       |
    |                  dsaf                     |
    |                   |                       |
    |      ---------------------------          |
    |     |         |         |       |         |
    |     |         |         |       |         |
    |    MAC       MAC       MAC     MAC        |
    |     |         |         |       |         |
     ---- |-------- |-------- |       | --------|
         ||        ||        ||       ||         
         PHY       PHY       PHY     PHY         

As we know, Linux Mido bus can be registered by multi phy devices. Then net device
can find mdio bus through phy node information. So

 MDIO_BUS0    NET-DEVECE0    NET-DEVICE1   ...   NET-DEVICEn    MDIO_BUS1
    |                 |               |             |                |
    |                 |               |             |                |
    |                 |               |             |                |
    |                 |               |             |    ------------
     -----------------|------------   |             |   |
                  |   |            |  |             |   |
              PHY-DEVICE0    PHY-DEVICE1   ...   PHY-DEVICEn


If we push this patch successfully, the other SOC with the same topology can use this
common routines directly.
Thanks again.



On 2015/12/3 18:47, Graeme Gregory wrote:
> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>> Currently many of the ethernet drivers are open coding a solution
>> for reading data out of ACPI to find the correct PHY device.
>> This patch implements a set of common routines are similar to of_mdio.c
>>
> The general conclusion for the ACPI on ARM64 discussion so far has been that
> things like PHYs should be setup by the firmware before the kernel takes
> control.
>
> I am unsure that this doing it the same way as DT with a different
> description language is the way to go.
>
> Graeme
>
>> Signed-off-by: yankejian <yankejian@huawei.com>
>> ---
>>  drivers/acpi/Makefile     |   3 +
>>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/acpi_mdio.h |  68 ++++++++++++
>>  3 files changed, 334 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_mdio.c
>>  create mode 100644 include/linux/acpi_mdio.h
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index 675eaf3..832e7d6 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
>>  acpi-y				+= scan.o
>>  acpi-y				+= resource.o
>>  acpi-y				+= acpi_processor.o
>> +acpi-y				+= acpi_mdio.o
>>  acpi-y				+= processor_core.o
>>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
>>  acpi-y				+= ec.o
>> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
>>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
>>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
>>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
>> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
>>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
>>  obj-y				+= container.o
>>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
>> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
>>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
>>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
>>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
>> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
>>  
>>  # processor has its own "processor." module_param namespace
>>  processor-y			:= processor_driver.o
>> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
>> new file mode 100644
>> index 0000000..3a5871d
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_mdio.c
>> @@ -0,0 +1,263 @@
>> +/*
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/acpi_mdio.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/phy.h>
>> +#include <linux/phy_fixed.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/spinlock_types.h>
>> +
>> +static
>> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
>> +			      u32 addr)
>> +{
>> +	struct phy_device *phy;
>> +	const char *phy_type;
>> +	bool is_c45;
>> +	int rc;
>> +
>> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
>> +		     sizeof("ethernet-phy-ieee802.3-c45")))
>> +		is_c45 = 1;
>> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
>> +			  sizeof("ethernet-phy-ieee802.3-c22")))
>> +		is_c45 = 0;
>> +	else
>> +		return -ENODATA;
>> +
>> +	phy = get_phy_device(mdio, addr, is_c45);
>> +	if (!phy || IS_ERR(phy))
>> +		return 1;
>> +
>> +	/* Associate the fw node with the device structure so it
>> +	 * can be looked up later
>> +	 */
>> +	phy->dev.fwnode = child;
>> +
>> +	if (mdio->irq)
>> +		phy->irq = mdio->irq[addr];
>> +
>> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
>> +		mdio->phy_ignore_ta_mask |= 1 << addr;
>> +
>> +	/* All data is now stored in the phy struct;
>> +	 * register it
>> +	 */
>> +	rc = phy_device_register(phy);
>> +	if (rc) {
>> +		phy_device_free(phy);
>> +		return 1;
>> +	}
>> +
>> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
>> +
>> +	return 0;
>> +}
>> +
>> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
>> +{
>> +	u32 addr;
>> +	int ret;
>> +
>> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
>> +	if (ret < 0) {
>> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	if (addr >= PHY_MAX_ADDR) {
>> +		dev_err(dev, "PHY address %i is too large\n", addr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	return addr;
>> +}
>> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
>> +
>> +/**
>> + * acpi_mdiobus_register - Register mii_bus and create PHYs
>> + * @mdio: pointer to mii_bus structure
>> + * @fwnode: pointer to framework node of MDIO bus.
>> + *
>> + * This function registers the mii_bus structure and registers a phy_device
>> + * for each child node of mdio device.
>> + */
>> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
>> +{
>> +	struct fwnode_handle *child;
>> +	struct acpi_device *adev;
>> +	bool scanphys = false;
>> +	int addr, rc, i;
>> +
>> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
>> +	 * the framework node are populated after the bus has been registered
>> +	 */
>> +	mdio->phy_mask = ~0;
>> +
>> +	/* Clear all the IRQ properties */
>> +	if (mdio->irq)
>> +		for (i = 0; i < PHY_MAX_ADDR; i++)
>> +			mdio->irq[i] = PHY_POLL;
>> +
>> +	mdio->dev.fwnode = fwnode;
>> +
>> +	/* Register the MDIO bus */
>> +	rc = mdiobus_register(mdio);
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* Loop over the child nodes and register a phy_device for each one */
>> +	device_for_each_child_node(&mdio->dev, child) {
>> +		adev = to_acpi_device_node(child);
>> +		if (!adev)
>> +			continue;
>> +
>> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
>> +		if (addr < 0) {
>> +			scanphys = true;
>> +			continue;
>> +		}
>> +
>> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
>> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
>> +		if (rc)
>> +			continue;
>> +	}
>> +
>> +	if (!scanphys)
>> +		return 0;
>> +
>> +	/* auto scan for PHYs with empty reg property */
>> +	device_for_each_child_node(&mdio->dev, child) {
>> +		/* Skip PHYs with reg property set */
>> +		if (!fwnode_property_present(child, "reg"))
>> +			continue;
>> +
>> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
>> +			/* skip already registered PHYs */
>> +			if (mdio->phy_map[addr])
>> +				continue;
>> +
>> +			/* be noisy to encourage people to set reg property */
>> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
>> +				 acpi_dev_name(to_acpi_device_node(child)),
>> +				 addr);
>> +
>> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
>> +			if (rc)
>> +				continue;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(acpi_mdiobus_register);
>> +
>> +/* Helper function for acpi_phy_find_device */
>> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
>> +{
>> +	return dev->fwnode == phy_fwnode;
>> +}
>> +
>> +/**
>> + * acpi_phy_find_device - Give a PHY node, find the phy_device
>> + * @phy_fwnode: Pointer to the phy's framework node
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure.
>> + */
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
>> +{
>> +	struct device *d;
>> +
>> +	if (!phy_fwnode)
>> +		return NULL;
>> +
>> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
>> +
>> +	return d ? to_phy_device(d) : NULL;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_find_device);
>> +
>> +/**
>> + * acpi_phy_attach - Attach to a PHY without starting the state machine
>> + * @dev: pointer to net_device claiming the phy
>> + * @phy_fwnode: framework Node pointer for the PHY
>> + * @flags: flags to pass to the PHY
>> + * @iface: PHY data interface type
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure. The
>> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
>> + */
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface)
>> +{
>> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
>> +	int ret;
>> +
>> +	if (!phy)
>> +		return NULL;
>> +
>> +	ret = phy_attach_direct(dev, phy, flags, iface);
>> +
>> +	/* refcount is held by phy_attach_direct() on success */
>> +	put_device(&phy->dev);
>> +
>> +	return ret ? NULL : phy;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_attach);
>> +
>> +/**
>> + * acpi_phy_connect - Connect to the phy described
>> + * @dev: pointer to net_device claiming the phy
>> + * @phy_fwnode: Pointer to framework node for the PHY
>> + * @hndlr: Link state callback for the network device
>> + * @iface: PHY data interface type
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure. The
>> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
>> + */
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface)
>> +{
>> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
>> +	int ret;
>> +
>> +	if (!phy)
>> +		return NULL;
>> +
>> +	phy->dev_flags = flags;
>> +
>> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
>> +
>> +	/* refcount is held by phy_connect_direct() on success */
>> +	put_device(&phy->dev);
>> +
>> +	return ret ? NULL : phy;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_connect);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
>> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
>> new file mode 100644
>> index 0000000..82b5be5
>> --- /dev/null
>> +++ b/include/linux/acpi_mdio.h
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#ifndef __LINUX_ACPI_MDIO_H
>> +#define __LINUX_ACPI_MDIO_H
>> +
>> +#include <linux/phy.h>
>> +
>> +#ifdef CONFIG_ACPI
>> +
>> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
>> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface);
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface);
>> +
>> +#else
>> +static inline int acpi_mdio_parse_addr(struct device *dev,
>> +				       struct fwnode_handle *fwnode)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
>> +					struct fwnode_handle *fwnode)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface)
>> +{
>> +	return NULL;
>> +}
>> +
>> +#endif
>> +
>> +#endif /* __LINUX_ACPI_MDIO_H */
>> -- 
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> .
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2016-01-12 12:12     ` Yankejian (Hackim Yim)
  0 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2016-01-12 12:12 UTC (permalink / raw)
  To: Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm

Hi Graeme,
I some how missed to reply this. Sorry for this!

HNS needs to configure PHYs dynamically parameter. So HNS try to call
Linux PHY driver to help access to PHYs. If PHYs access will be implemented in BIOS,
it seems that HNS needs repeatedly communication with BIOS.
And we have read other ethernet drivers with PHYs as well, like
1) APM X-Gene Ethernet Driver, and
2) AMD 10Gb Ethernet driver, and
3) Intel IXGBE.
Both AMD and Intel try to implement PHYs access routines itself. The drivers
needs to implement PHY access routines includes the popular PHYs.
APM X-Gene Ethernet Driver needs Linux PHY driver help to access PHYs. It
implements the new routines help to access Linux PHY driver, then access PHYs.
As the drivers shows, each MDIO controller connects one PHY. Sometimes, one MDIO
may control several PHYs, like HNS.

Firstly, let's go over the HNS hardware topology as below. The MDIO controller may
control several PHYs, and each PHY connects to a MAC device.
                       cpu                       
                        |                        
                        |                        
     ------------------------------------------- 
    |                   |                       |
    |                   |                       |
    |                  dsaf                     |
    |                   |                       |
    |      ---------------------------          |
    |     |         |         |       |         |
    |     |         |         |       |         |
    |    MAC       MAC       MAC     MAC        |
    |     |         |         |       |         |
     ---- |-------- |-------- |       | --------|
         ||        ||        ||       ||         
         PHY       PHY       PHY     PHY         

As we know, Linux Mido bus can be registered by multi phy devices. Then net device
can find mdio bus through phy node information. So

 MDIO_BUS0    NET-DEVECE0    NET-DEVICE1   ...   NET-DEVICEn    MDIO_BUS1
    |                 |               |             |                |
    |                 |               |             |                |
    |                 |               |             |                |
    |                 |               |             |    ------------
     -----------------|------------   |             |   |
                  |   |            |  |             |   |
              PHY-DEVICE0    PHY-DEVICE1   ...   PHY-DEVICEn


If we push this patch successfully, the other SOC with the same topology can use this
common routines directly.
Thanks again.



On 2015/12/3 18:47, Graeme Gregory wrote:
> On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
>> Add support for getting the PHY devices on an MDIO bus by ACPI.
>> Currently many of the ethernet drivers are open coding a solution
>> for reading data out of ACPI to find the correct PHY device.
>> This patch implements a set of common routines are similar to of_mdio.c
>>
> The general conclusion for the ACPI on ARM64 discussion so far has been that
> things like PHYs should be setup by the firmware before the kernel takes
> control.
>
> I am unsure that this doing it the same way as DT with a different
> description language is the way to go.
>
> Graeme
>
>> Signed-off-by: yankejian <yankejian@huawei.com>
>> ---
>>  drivers/acpi/Makefile     |   3 +
>>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/acpi_mdio.h |  68 ++++++++++++
>>  3 files changed, 334 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_mdio.c
>>  create mode 100644 include/linux/acpi_mdio.h
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index 675eaf3..832e7d6 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
>>  acpi-y				+= scan.o
>>  acpi-y				+= resource.o
>>  acpi-y				+= acpi_processor.o
>> +acpi-y				+= acpi_mdio.o
>>  acpi-y				+= processor_core.o
>>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
>>  acpi-y				+= ec.o
>> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
>>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
>>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
>>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
>> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
>>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
>>  obj-y				+= container.o
>>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
>> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
>>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
>>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
>>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
>> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
>>  
>>  # processor has its own "processor." module_param namespace
>>  processor-y			:= processor_driver.o
>> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
>> new file mode 100644
>> index 0000000..3a5871d
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_mdio.c
>> @@ -0,0 +1,263 @@
>> +/*
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/acpi_mdio.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/phy.h>
>> +#include <linux/phy_fixed.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/spinlock_types.h>
>> +
>> +static
>> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
>> +			      u32 addr)
>> +{
>> +	struct phy_device *phy;
>> +	const char *phy_type;
>> +	bool is_c45;
>> +	int rc;
>> +
>> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
>> +		     sizeof("ethernet-phy-ieee802.3-c45")))
>> +		is_c45 = 1;
>> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
>> +			  sizeof("ethernet-phy-ieee802.3-c22")))
>> +		is_c45 = 0;
>> +	else
>> +		return -ENODATA;
>> +
>> +	phy = get_phy_device(mdio, addr, is_c45);
>> +	if (!phy || IS_ERR(phy))
>> +		return 1;
>> +
>> +	/* Associate the fw node with the device structure so it
>> +	 * can be looked up later
>> +	 */
>> +	phy->dev.fwnode = child;
>> +
>> +	if (mdio->irq)
>> +		phy->irq = mdio->irq[addr];
>> +
>> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
>> +		mdio->phy_ignore_ta_mask |= 1 << addr;
>> +
>> +	/* All data is now stored in the phy struct;
>> +	 * register it
>> +	 */
>> +	rc = phy_device_register(phy);
>> +	if (rc) {
>> +		phy_device_free(phy);
>> +		return 1;
>> +	}
>> +
>> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
>> +
>> +	return 0;
>> +}
>> +
>> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
>> +{
>> +	u32 addr;
>> +	int ret;
>> +
>> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
>> +	if (ret < 0) {
>> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	if (addr >= PHY_MAX_ADDR) {
>> +		dev_err(dev, "PHY address %i is too large\n", addr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	return addr;
>> +}
>> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
>> +
>> +/**
>> + * acpi_mdiobus_register - Register mii_bus and create PHYs
>> + * @mdio: pointer to mii_bus structure
>> + * @fwnode: pointer to framework node of MDIO bus.
>> + *
>> + * This function registers the mii_bus structure and registers a phy_device
>> + * for each child node of mdio device.
>> + */
>> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
>> +{
>> +	struct fwnode_handle *child;
>> +	struct acpi_device *adev;
>> +	bool scanphys = false;
>> +	int addr, rc, i;
>> +
>> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
>> +	 * the framework node are populated after the bus has been registered
>> +	 */
>> +	mdio->phy_mask = ~0;
>> +
>> +	/* Clear all the IRQ properties */
>> +	if (mdio->irq)
>> +		for (i = 0; i < PHY_MAX_ADDR; i++)
>> +			mdio->irq[i] = PHY_POLL;
>> +
>> +	mdio->dev.fwnode = fwnode;
>> +
>> +	/* Register the MDIO bus */
>> +	rc = mdiobus_register(mdio);
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* Loop over the child nodes and register a phy_device for each one */
>> +	device_for_each_child_node(&mdio->dev, child) {
>> +		adev = to_acpi_device_node(child);
>> +		if (!adev)
>> +			continue;
>> +
>> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
>> +		if (addr < 0) {
>> +			scanphys = true;
>> +			continue;
>> +		}
>> +
>> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
>> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
>> +		if (rc)
>> +			continue;
>> +	}
>> +
>> +	if (!scanphys)
>> +		return 0;
>> +
>> +	/* auto scan for PHYs with empty reg property */
>> +	device_for_each_child_node(&mdio->dev, child) {
>> +		/* Skip PHYs with reg property set */
>> +		if (!fwnode_property_present(child, "reg"))
>> +			continue;
>> +
>> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
>> +			/* skip already registered PHYs */
>> +			if (mdio->phy_map[addr])
>> +				continue;
>> +
>> +			/* be noisy to encourage people to set reg property */
>> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
>> +				 acpi_dev_name(to_acpi_device_node(child)),
>> +				 addr);
>> +
>> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
>> +			if (rc)
>> +				continue;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(acpi_mdiobus_register);
>> +
>> +/* Helper function for acpi_phy_find_device */
>> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
>> +{
>> +	return dev->fwnode == phy_fwnode;
>> +}
>> +
>> +/**
>> + * acpi_phy_find_device - Give a PHY node, find the phy_device
>> + * @phy_fwnode: Pointer to the phy's framework node
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure.
>> + */
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
>> +{
>> +	struct device *d;
>> +
>> +	if (!phy_fwnode)
>> +		return NULL;
>> +
>> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
>> +
>> +	return d ? to_phy_device(d) : NULL;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_find_device);
>> +
>> +/**
>> + * acpi_phy_attach - Attach to a PHY without starting the state machine
>> + * @dev: pointer to net_device claiming the phy
>> + * @phy_fwnode: framework Node pointer for the PHY
>> + * @flags: flags to pass to the PHY
>> + * @iface: PHY data interface type
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure. The
>> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
>> + */
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface)
>> +{
>> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
>> +	int ret;
>> +
>> +	if (!phy)
>> +		return NULL;
>> +
>> +	ret = phy_attach_direct(dev, phy, flags, iface);
>> +
>> +	/* refcount is held by phy_attach_direct() on success */
>> +	put_device(&phy->dev);
>> +
>> +	return ret ? NULL : phy;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_attach);
>> +
>> +/**
>> + * acpi_phy_connect - Connect to the phy described
>> + * @dev: pointer to net_device claiming the phy
>> + * @phy_fwnode: Pointer to framework node for the PHY
>> + * @hndlr: Link state callback for the network device
>> + * @iface: PHY data interface type
>> + *
>> + * If successful, returns a pointer to the phy_device with the embedded
>> + * struct device refcount incremented by one, or NULL on failure. The
>> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
>> + */
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface)
>> +{
>> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
>> +	int ret;
>> +
>> +	if (!phy)
>> +		return NULL;
>> +
>> +	phy->dev_flags = flags;
>> +
>> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
>> +
>> +	/* refcount is held by phy_connect_direct() on success */
>> +	put_device(&phy->dev);
>> +
>> +	return ret ? NULL : phy;
>> +}
>> +EXPORT_SYMBOL(acpi_phy_connect);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
>> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
>> new file mode 100644
>> index 0000000..82b5be5
>> --- /dev/null
>> +++ b/include/linux/acpi_mdio.h
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#ifndef __LINUX_ACPI_MDIO_H
>> +#define __LINUX_ACPI_MDIO_H
>> +
>> +#include <linux/phy.h>
>> +
>> +#ifdef CONFIG_ACPI
>> +
>> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
>> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface);
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface);
>> +
>> +#else
>> +static inline int acpi_mdio_parse_addr(struct device *dev,
>> +				       struct fwnode_handle *fwnode)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
>> +					struct fwnode_handle *fwnode)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_attach(struct net_device *dev,
>> +				   struct fwnode_handle *phy_fwnode, u32 flags,
>> +				   phy_interface_t iface)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline
>> +struct phy_device *acpi_phy_connect(struct net_device *dev,
>> +				    struct fwnode_handle *phy_fwnode,
>> +				    void (*hndlr)(struct net_device *),
>> +				    u32 flags,
>> +				    phy_interface_t iface)
>> +{
>> +	return NULL;
>> +}
>> +
>> +#endif
>> +
>> +#endif /* __LINUX_ACPI_MDIO_H */
>> -- 
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> .
>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2016-01-12 12:12     ` Yankejian (Hackim Yim)
@ 2016-01-12 12:39       ` Graeme Gregory
  -1 siblings, 0 replies; 18+ messages in thread
From: Graeme Gregory @ 2016-01-12 12:39 UTC (permalink / raw)
  To: Yankejian
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On Tue, 12 Jan 2016, at 12:12 PM, Yankejian (Hackim Yim) wrote:
> Hi Graeme,
> I some how missed to reply this. Sorry for this!
> 
> HNS needs to configure PHYs dynamically parameter. So HNS try to call
> Linux PHY driver to help access to PHYs. If PHYs access will be
> implemented in BIOS,
> it seems that HNS needs repeatedly communication with BIOS.
> And we have read other ethernet drivers with PHYs as well, like
> 1) APM X-Gene Ethernet Driver, and
> 2) AMD 10Gb Ethernet driver, and
> 3) Intel IXGBE.
> Both AMD and Intel try to implement PHYs access routines itself. The
> drivers
> needs to implement PHY access routines includes the popular PHYs.
> APM X-Gene Ethernet Driver needs Linux PHY driver help to access PHYs. It
> implements the new routines help to access Linux PHY driver, then access
> PHYs.
> As the drivers shows, each MDIO controller connects one PHY. Sometimes,
> one MDIO
> may control several PHYs, like HNS.
> 
> Firstly, let's go over the HNS hardware topology as below. The MDIO
> controller may
> control several PHYs, and each PHY connects to a MAC device.
>                        cpu                       
>                         |                        
>                         |                        
>      ------------------------------------------- 
>     |                   |                       |
>     |                   |                       |
>     |                  dsaf                     |
>     |                   |                       |
>     |      ---------------------------          |
>     |     |         |         |       |         |
>     |     |         |         |       |         |
>     |    MAC       MAC       MAC     MAC        |
>     |     |         |         |       |         |
>      ---- |-------- |-------- |       | --------|
>          ||        ||        ||       ||         
>          PHY       PHY       PHY     PHY         
> 
> As we know, Linux Mido bus can be registered by multi phy devices. Then
> net device
> can find mdio bus through phy node information. So
> 
>  MDIO_BUS0    NET-DEVECE0    NET-DEVICE1   ...   NET-DEVICEn    MDIO_BUS1
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |    ------------
>      -----------------|------------   |             |   |
>                   |   |            |  |             |   |
>               PHY-DEVICE0    PHY-DEVICE1   ...   PHY-DEVICEn
> 
> 
> If we push this patch successfully, the other SOC with the same topology
> can use this
> common routines directly.
> Thanks again.
> 

Thanks for the detailed explanation, I see now why you wish to do this
dynamically.

Then I guess the job is to make sure that the PHY stuff is well defined
in _DSD. I know Redhat submitted a document.

Thanks

Graeme

> 
> 
> On 2015/12/3 18:47, Graeme Gregory wrote:
> > On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
> >> Add support for getting the PHY devices on an MDIO bus by ACPI.
> >> Currently many of the ethernet drivers are open coding a solution
> >> for reading data out of ACPI to find the correct PHY device.
> >> This patch implements a set of common routines are similar to of_mdio.c
> >>
> > The general conclusion for the ACPI on ARM64 discussion so far has been that
> > things like PHYs should be setup by the firmware before the kernel takes
> > control.
> >
> > I am unsure that this doing it the same way as DT with a different
> > description language is the way to go.
> >
> > Graeme
> >
> >> Signed-off-by: yankejian <yankejian@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile     |   3 +
> >>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/linux/acpi_mdio.h |  68 ++++++++++++
> >>  3 files changed, 334 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_mdio.c
> >>  create mode 100644 include/linux/acpi_mdio.h
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index 675eaf3..832e7d6 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
> >>  acpi-y				+= scan.o
> >>  acpi-y				+= resource.o
> >>  acpi-y				+= acpi_processor.o
> >> +acpi-y				+= acpi_mdio.o
> >>  acpi-y				+= processor_core.o
> >>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
> >>  acpi-y				+= ec.o
> >> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
> >>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
> >>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
> >>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
> >> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
> >>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
> >>  obj-y				+= container.o
> >>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
> >> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
> >>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
> >>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
> >>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
> >> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
> >>  
> >>  # processor has its own "processor." module_param namespace
> >>  processor-y			:= processor_driver.o
> >> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
> >> new file mode 100644
> >> index 0000000..3a5871d
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_mdio.c
> >> @@ -0,0 +1,263 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/acpi.h>
> >> +#include <linux/acpi_mdio.h>
> >> +#include <linux/device.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/module.h>
> >> +#include <linux/netdevice.h>
> >> +#include <linux/phy.h>
> >> +#include <linux/phy_fixed.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/spinlock_types.h>
> >> +
> >> +static
> >> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
> >> +			      u32 addr)
> >> +{
> >> +	struct phy_device *phy;
> >> +	const char *phy_type;
> >> +	bool is_c45;
> >> +	int rc;
> >> +
> >> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
> >> +	if (rc < 0)
> >> +		return rc;
> >> +
> >> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
> >> +		     sizeof("ethernet-phy-ieee802.3-c45")))
> >> +		is_c45 = 1;
> >> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
> >> +			  sizeof("ethernet-phy-ieee802.3-c22")))
> >> +		is_c45 = 0;
> >> +	else
> >> +		return -ENODATA;
> >> +
> >> +	phy = get_phy_device(mdio, addr, is_c45);
> >> +	if (!phy || IS_ERR(phy))
> >> +		return 1;
> >> +
> >> +	/* Associate the fw node with the device structure so it
> >> +	 * can be looked up later
> >> +	 */
> >> +	phy->dev.fwnode = child;
> >> +
> >> +	if (mdio->irq)
> >> +		phy->irq = mdio->irq[addr];
> >> +
> >> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
> >> +		mdio->phy_ignore_ta_mask |= 1 << addr;
> >> +
> >> +	/* All data is now stored in the phy struct;
> >> +	 * register it
> >> +	 */
> >> +	rc = phy_device_register(phy);
> >> +	if (rc) {
> >> +		phy_device_free(phy);
> >> +		return 1;
> >> +	}
> >> +
> >> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
> >> +{
> >> +	u32 addr;
> >> +	int ret;
> >> +
> >> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
> >> +	if (ret < 0) {
> >> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	if (addr >= PHY_MAX_ADDR) {
> >> +		dev_err(dev, "PHY address %i is too large\n", addr);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	return addr;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
> >> +
> >> +/**
> >> + * acpi_mdiobus_register - Register mii_bus and create PHYs
> >> + * @mdio: pointer to mii_bus structure
> >> + * @fwnode: pointer to framework node of MDIO bus.
> >> + *
> >> + * This function registers the mii_bus structure and registers a phy_device
> >> + * for each child node of mdio device.
> >> + */
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
> >> +{
> >> +	struct fwnode_handle *child;
> >> +	struct acpi_device *adev;
> >> +	bool scanphys = false;
> >> +	int addr, rc, i;
> >> +
> >> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
> >> +	 * the framework node are populated after the bus has been registered
> >> +	 */
> >> +	mdio->phy_mask = ~0;
> >> +
> >> +	/* Clear all the IRQ properties */
> >> +	if (mdio->irq)
> >> +		for (i = 0; i < PHY_MAX_ADDR; i++)
> >> +			mdio->irq[i] = PHY_POLL;
> >> +
> >> +	mdio->dev.fwnode = fwnode;
> >> +
> >> +	/* Register the MDIO bus */
> >> +	rc = mdiobus_register(mdio);
> >> +	if (rc)
> >> +		return rc;
> >> +
> >> +	/* Loop over the child nodes and register a phy_device for each one */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		adev = to_acpi_device_node(child);
> >> +		if (!adev)
> >> +			continue;
> >> +
> >> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
> >> +		if (addr < 0) {
> >> +			scanphys = true;
> >> +			continue;
> >> +		}
> >> +
> >> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
> >> +		if (rc)
> >> +			continue;
> >> +	}
> >> +
> >> +	if (!scanphys)
> >> +		return 0;
> >> +
> >> +	/* auto scan for PHYs with empty reg property */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		/* Skip PHYs with reg property set */
> >> +		if (!fwnode_property_present(child, "reg"))
> >> +			continue;
> >> +
> >> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
> >> +			/* skip already registered PHYs */
> >> +			if (mdio->phy_map[addr])
> >> +				continue;
> >> +
> >> +			/* be noisy to encourage people to set reg property */
> >> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
> >> +				 acpi_dev_name(to_acpi_device_node(child)),
> >> +				 addr);
> >> +
> >> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +			if (rc)
> >> +				continue;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdiobus_register);
> >> +
> >> +/* Helper function for acpi_phy_find_device */
> >> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
> >> +{
> >> +	return dev->fwnode == phy_fwnode;
> >> +}
> >> +
> >> +/**
> >> + * acpi_phy_find_device - Give a PHY node, find the phy_device
> >> + * @phy_fwnode: Pointer to the phy's framework node
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure.
> >> + */
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	struct device *d;
> >> +
> >> +	if (!phy_fwnode)
> >> +		return NULL;
> >> +
> >> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
> >> +
> >> +	return d ? to_phy_device(d) : NULL;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_find_device);
> >> +
> >> +/**
> >> + * acpi_phy_attach - Attach to a PHY without starting the state machine
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: framework Node pointer for the PHY
> >> + * @flags: flags to pass to the PHY
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	ret = phy_attach_direct(dev, phy, flags, iface);
> >> +
> >> +	/* refcount is held by phy_attach_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_attach);
> >> +
> >> +/**
> >> + * acpi_phy_connect - Connect to the phy described
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: Pointer to framework node for the PHY
> >> + * @hndlr: Link state callback for the network device
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	phy->dev_flags = flags;
> >> +
> >> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
> >> +
> >> +	/* refcount is held by phy_connect_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_connect);
> >> +
> >> +MODULE_LICENSE("GPL");
> >> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
> >> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
> >> new file mode 100644
> >> index 0000000..82b5be5
> >> --- /dev/null
> >> +++ b/include/linux/acpi_mdio.h
> >> @@ -0,0 +1,68 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#ifndef __LINUX_ACPI_MDIO_H
> >> +#define __LINUX_ACPI_MDIO_H
> >> +
> >> +#include <linux/phy.h>
> >> +
> >> +#ifdef CONFIG_ACPI
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface);
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface);
> >> +
> >> +#else
> >> +static inline int acpi_mdio_parse_addr(struct device *dev,
> >> +				       struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
> >> +					struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +#endif
> >> +
> >> +#endif /* __LINUX_ACPI_MDIO_H */
> >> -- 
> >> 1.9.1
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > .
> >
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2016-01-12 12:39       ` Graeme Gregory
  0 siblings, 0 replies; 18+ messages in thread
From: Graeme Gregory @ 2016-01-12 12:39 UTC (permalink / raw)
  To: Yankejian
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm



On Tue, 12 Jan 2016, at 12:12 PM, Yankejian (Hackim Yim) wrote:
> Hi Graeme,
> I some how missed to reply this. Sorry for this!
> 
> HNS needs to configure PHYs dynamically parameter. So HNS try to call
> Linux PHY driver to help access to PHYs. If PHYs access will be
> implemented in BIOS,
> it seems that HNS needs repeatedly communication with BIOS.
> And we have read other ethernet drivers with PHYs as well, like
> 1) APM X-Gene Ethernet Driver, and
> 2) AMD 10Gb Ethernet driver, and
> 3) Intel IXGBE.
> Both AMD and Intel try to implement PHYs access routines itself. The
> drivers
> needs to implement PHY access routines includes the popular PHYs.
> APM X-Gene Ethernet Driver needs Linux PHY driver help to access PHYs. It
> implements the new routines help to access Linux PHY driver, then access
> PHYs.
> As the drivers shows, each MDIO controller connects one PHY. Sometimes,
> one MDIO
> may control several PHYs, like HNS.
> 
> Firstly, let's go over the HNS hardware topology as below. The MDIO
> controller may
> control several PHYs, and each PHY connects to a MAC device.
>                        cpu                       
>                         |                        
>                         |                        
>      ------------------------------------------- 
>     |                   |                       |
>     |                   |                       |
>     |                  dsaf                     |
>     |                   |                       |
>     |      ---------------------------          |
>     |     |         |         |       |         |
>     |     |         |         |       |         |
>     |    MAC       MAC       MAC     MAC        |
>     |     |         |         |       |         |
>      ---- |-------- |-------- |       | --------|
>          ||        ||        ||       ||         
>          PHY       PHY       PHY     PHY         
> 
> As we know, Linux Mido bus can be registered by multi phy devices. Then
> net device
> can find mdio bus through phy node information. So
> 
>  MDIO_BUS0    NET-DEVECE0    NET-DEVICE1   ...   NET-DEVICEn    MDIO_BUS1
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |    ------------
>      -----------------|------------   |             |   |
>                   |   |            |  |             |   |
>               PHY-DEVICE0    PHY-DEVICE1   ...   PHY-DEVICEn
> 
> 
> If we push this patch successfully, the other SOC with the same topology
> can use this
> common routines directly.
> Thanks again.
> 

Thanks for the detailed explanation, I see now why you wish to do this
dynamically.

Then I guess the job is to make sure that the PHY stuff is well defined
in _DSD. I know Redhat submitted a document.

Thanks

Graeme

> 
> 
> On 2015/12/3 18:47, Graeme Gregory wrote:
> > On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
> >> Add support for getting the PHY devices on an MDIO bus by ACPI.
> >> Currently many of the ethernet drivers are open coding a solution
> >> for reading data out of ACPI to find the correct PHY device.
> >> This patch implements a set of common routines are similar to of_mdio.c
> >>
> > The general conclusion for the ACPI on ARM64 discussion so far has been that
> > things like PHYs should be setup by the firmware before the kernel takes
> > control.
> >
> > I am unsure that this doing it the same way as DT with a different
> > description language is the way to go.
> >
> > Graeme
> >
> >> Signed-off-by: yankejian <yankejian@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile     |   3 +
> >>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/linux/acpi_mdio.h |  68 ++++++++++++
> >>  3 files changed, 334 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_mdio.c
> >>  create mode 100644 include/linux/acpi_mdio.h
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index 675eaf3..832e7d6 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
> >>  acpi-y				+= scan.o
> >>  acpi-y				+= resource.o
> >>  acpi-y				+= acpi_processor.o
> >> +acpi-y				+= acpi_mdio.o
> >>  acpi-y				+= processor_core.o
> >>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
> >>  acpi-y				+= ec.o
> >> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
> >>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
> >>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
> >>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
> >> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
> >>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
> >>  obj-y				+= container.o
> >>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
> >> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
> >>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
> >>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
> >>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
> >> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
> >>  
> >>  # processor has its own "processor." module_param namespace
> >>  processor-y			:= processor_driver.o
> >> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
> >> new file mode 100644
> >> index 0000000..3a5871d
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_mdio.c
> >> @@ -0,0 +1,263 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/acpi.h>
> >> +#include <linux/acpi_mdio.h>
> >> +#include <linux/device.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/module.h>
> >> +#include <linux/netdevice.h>
> >> +#include <linux/phy.h>
> >> +#include <linux/phy_fixed.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/spinlock_types.h>
> >> +
> >> +static
> >> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
> >> +			      u32 addr)
> >> +{
> >> +	struct phy_device *phy;
> >> +	const char *phy_type;
> >> +	bool is_c45;
> >> +	int rc;
> >> +
> >> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
> >> +	if (rc < 0)
> >> +		return rc;
> >> +
> >> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
> >> +		     sizeof("ethernet-phy-ieee802.3-c45")))
> >> +		is_c45 = 1;
> >> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
> >> +			  sizeof("ethernet-phy-ieee802.3-c22")))
> >> +		is_c45 = 0;
> >> +	else
> >> +		return -ENODATA;
> >> +
> >> +	phy = get_phy_device(mdio, addr, is_c45);
> >> +	if (!phy || IS_ERR(phy))
> >> +		return 1;
> >> +
> >> +	/* Associate the fw node with the device structure so it
> >> +	 * can be looked up later
> >> +	 */
> >> +	phy->dev.fwnode = child;
> >> +
> >> +	if (mdio->irq)
> >> +		phy->irq = mdio->irq[addr];
> >> +
> >> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
> >> +		mdio->phy_ignore_ta_mask |= 1 << addr;
> >> +
> >> +	/* All data is now stored in the phy struct;
> >> +	 * register it
> >> +	 */
> >> +	rc = phy_device_register(phy);
> >> +	if (rc) {
> >> +		phy_device_free(phy);
> >> +		return 1;
> >> +	}
> >> +
> >> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
> >> +{
> >> +	u32 addr;
> >> +	int ret;
> >> +
> >> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
> >> +	if (ret < 0) {
> >> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	if (addr >= PHY_MAX_ADDR) {
> >> +		dev_err(dev, "PHY address %i is too large\n", addr);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	return addr;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
> >> +
> >> +/**
> >> + * acpi_mdiobus_register - Register mii_bus and create PHYs
> >> + * @mdio: pointer to mii_bus structure
> >> + * @fwnode: pointer to framework node of MDIO bus.
> >> + *
> >> + * This function registers the mii_bus structure and registers a phy_device
> >> + * for each child node of mdio device.
> >> + */
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
> >> +{
> >> +	struct fwnode_handle *child;
> >> +	struct acpi_device *adev;
> >> +	bool scanphys = false;
> >> +	int addr, rc, i;
> >> +
> >> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
> >> +	 * the framework node are populated after the bus has been registered
> >> +	 */
> >> +	mdio->phy_mask = ~0;
> >> +
> >> +	/* Clear all the IRQ properties */
> >> +	if (mdio->irq)
> >> +		for (i = 0; i < PHY_MAX_ADDR; i++)
> >> +			mdio->irq[i] = PHY_POLL;
> >> +
> >> +	mdio->dev.fwnode = fwnode;
> >> +
> >> +	/* Register the MDIO bus */
> >> +	rc = mdiobus_register(mdio);
> >> +	if (rc)
> >> +		return rc;
> >> +
> >> +	/* Loop over the child nodes and register a phy_device for each one */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		adev = to_acpi_device_node(child);
> >> +		if (!adev)
> >> +			continue;
> >> +
> >> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
> >> +		if (addr < 0) {
> >> +			scanphys = true;
> >> +			continue;
> >> +		}
> >> +
> >> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
> >> +		if (rc)
> >> +			continue;
> >> +	}
> >> +
> >> +	if (!scanphys)
> >> +		return 0;
> >> +
> >> +	/* auto scan for PHYs with empty reg property */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		/* Skip PHYs with reg property set */
> >> +		if (!fwnode_property_present(child, "reg"))
> >> +			continue;
> >> +
> >> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
> >> +			/* skip already registered PHYs */
> >> +			if (mdio->phy_map[addr])
> >> +				continue;
> >> +
> >> +			/* be noisy to encourage people to set reg property */
> >> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
> >> +				 acpi_dev_name(to_acpi_device_node(child)),
> >> +				 addr);
> >> +
> >> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +			if (rc)
> >> +				continue;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdiobus_register);
> >> +
> >> +/* Helper function for acpi_phy_find_device */
> >> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
> >> +{
> >> +	return dev->fwnode == phy_fwnode;
> >> +}
> >> +
> >> +/**
> >> + * acpi_phy_find_device - Give a PHY node, find the phy_device
> >> + * @phy_fwnode: Pointer to the phy's framework node
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure.
> >> + */
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	struct device *d;
> >> +
> >> +	if (!phy_fwnode)
> >> +		return NULL;
> >> +
> >> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
> >> +
> >> +	return d ? to_phy_device(d) : NULL;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_find_device);
> >> +
> >> +/**
> >> + * acpi_phy_attach - Attach to a PHY without starting the state machine
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: framework Node pointer for the PHY
> >> + * @flags: flags to pass to the PHY
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	ret = phy_attach_direct(dev, phy, flags, iface);
> >> +
> >> +	/* refcount is held by phy_attach_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_attach);
> >> +
> >> +/**
> >> + * acpi_phy_connect - Connect to the phy described
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: Pointer to framework node for the PHY
> >> + * @hndlr: Link state callback for the network device
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	phy->dev_flags = flags;
> >> +
> >> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
> >> +
> >> +	/* refcount is held by phy_connect_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_connect);
> >> +
> >> +MODULE_LICENSE("GPL");
> >> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
> >> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
> >> new file mode 100644
> >> index 0000000..82b5be5
> >> --- /dev/null
> >> +++ b/include/linux/acpi_mdio.h
> >> @@ -0,0 +1,68 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#ifndef __LINUX_ACPI_MDIO_H
> >> +#define __LINUX_ACPI_MDIO_H
> >> +
> >> +#include <linux/phy.h>
> >> +
> >> +#ifdef CONFIG_ACPI
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface);
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface);
> >> +
> >> +#else
> >> +static inline int acpi_mdio_parse_addr(struct device *dev,
> >> +				       struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
> >> +					struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +#endif
> >> +
> >> +#endif /* __LINUX_ACPI_MDIO_H */
> >> -- 
> >> 1.9.1
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > .
> >
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
  2016-01-12 12:39       ` Graeme Gregory
@ 2016-01-13  3:03         ` Yankejian (Hackim Yim)
  -1 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2016-01-13  3:03 UTC (permalink / raw)
  To: Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm


On 2016/1/12 20:39, Graeme Gregory wrote:
> Thanks for the detailed explanation, I see now why you wish to do this
> dynamically.
>
> Then I guess the job is to make sure that the PHY stuff is well defined
> in _DSD. I know Redhat submitted a document.
>
> Thanks
>
> Graeme
Thank you.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ACPI: Add phylib support code for mdio
@ 2016-01-13  3:03         ` Yankejian (Hackim Yim)
  0 siblings, 0 replies; 18+ messages in thread
From: Yankejian (Hackim Yim) @ 2016-01-13  3:03 UTC (permalink / raw)
  To: Graeme Gregory
  Cc: rjw, lenb, davem, liguozhu, yisen.zhuang, huangdaode, lipeng321,
	linux-kernel, linux-acpi, linuxarm


On 2016/1/12 20:39, Graeme Gregory wrote:
> Thanks for the detailed explanation, I see now why you wish to do this
> dynamically.
>
> Then I guess the job is to make sure that the PHY stuff is well defined
> in _DSD. I know Redhat submitted a document.
>
> Thanks
>
> Graeme
Thank you.


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2016-01-13  3:05 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-03  1:54 [PATCH] ACPI: Add phylib support code for mdio yankejian
2015-12-03  1:54 ` yankejian
2015-12-03  4:45 ` kbuild test robot
2015-12-03  4:45   ` kbuild test robot
2015-12-03  4:55 ` kbuild test robot
2015-12-03  4:55   ` kbuild test robot
2015-12-03 10:47 ` Graeme Gregory
2015-12-08 19:55   ` Al Stone
2015-12-09 10:31     ` Yankejian (Hackim Yim)
2015-12-09 10:31       ` Yankejian (Hackim Yim)
2015-12-10  1:27       ` Yankejian (Hackim Yim)
2015-12-10  1:27         ` Yankejian (Hackim Yim)
2016-01-12 12:12   ` Yankejian (Hackim Yim)
2016-01-12 12:12     ` Yankejian (Hackim Yim)
2016-01-12 12:39     ` Graeme Gregory
2016-01-12 12:39       ` Graeme Gregory
2016-01-13  3:03       ` Yankejian (Hackim Yim)
2016-01-13  3:03         ` Yankejian (Hackim Yim)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.