Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1282638 > unrolled thread

[PATCH] ACPI: Add phylib support code for mdio

Started byyankejian <yankejian@huawei.com>
First post2015-12-03 02:40 +0100
Last post2015-12-10 02:30 +0100
Articles 7 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH] ACPI: Add phylib support code for mdio yankejian <yankejian@huawei.com> - 2015-12-03 02:40 +0100
    Re: [PATCH] ACPI: Add phylib support code for mdio kbuild test robot <lkp@intel.com> - 2015-12-03 05:50 +0100
    Re: [PATCH] ACPI: Add phylib support code for mdio kbuild test robot <lkp@intel.com> - 2015-12-03 06:00 +0100
    Re: [PATCH] ACPI: Add phylib support code for mdio Graeme Gregory <gg@slimlogic.co.uk> - 2015-12-03 11:50 +0100
      Re: [PATCH] ACPI: Add phylib support code for mdio Al Stone <ahs3@redhat.com> - 2015-12-08 21:00 +0100
        Re: [PATCH] ACPI: Add phylib support code for mdio "Yankejian (Hackim Yim)" <yankejian@huawei.com> - 2015-12-09 11:40 +0100
          Re: [PATCH] ACPI: Add phylib support code for mdio "Yankejian (Hackim Yim)" <yankejian@huawei.com> - 2015-12-10 02:30 +0100

#1282638 — [PATCH] ACPI: Add phylib support code for mdio

Fromyankejian <yankejian@huawei.com>
Date2015-12-03 02:40 +0100
Subject[PATCH] ACPI: Add phylib support code for mdio
Message-ID<qBr2i-6Ex-13@gated-at.bofh.it>
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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1282706

Fromkbuild test robot <lkp@intel.com>
Date2015-12-03 05:50 +0100
Message-ID<qBu0a-at-11@gated-at.bofh.it>
In reply to#1282638

[Multipart message — attachments visible in raw view] — view raw

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

[toc] | [prev] | [next] | [standalone]


#1282710

Fromkbuild test robot <lkp@intel.com>
Date2015-12-03 06:00 +0100
Message-ID<qBu9P-eh-3@gated-at.bofh.it>
In reply to#1282638

[Multipart message — attachments visible in raw view] — view raw

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

[toc] | [prev] | [next] | [standalone]


#1282935

FromGraeme Gregory <gg@slimlogic.co.uk>
Date2015-12-03 11:50 +0100
Message-ID<qBzCz-3N9-31@gated-at.bofh.it>
In reply to#1282638
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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1286806

FromAl Stone <ahs3@redhat.com>
Date2015-12-08 21:00 +0100
Message-ID<qDwAx-6Bm-7@gated-at.bofh.it>
In reply to#1282935
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
-----------------------------------
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1287393

From"Yankejian (Hackim Yim)" <yankejian@huawei.com>
Date2015-12-09 11:40 +0100
Message-ID<qDKkb-7aE-49@gated-at.bofh.it>
In reply to#1286806

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


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1288108

From"Yankejian (Hackim Yim)" <yankejian@huawei.com>
Date2015-12-10 02:30 +0100
Message-ID<qDYds-7Hg-13@gated-at.bofh.it>
In reply to#1287393

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



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web