[PATCH v4 net-next 11/13] net: hns: register phy device in each mac initial sequence

2016-06-02 Thread Yisen Zhuang
From: Kejian Yan 

In ACPI case, there is no interface to register phy device to mdio-bus.
Phy device has to be registered itself to mdio-bus, and then enet can
get the phy device's info so that it can config the phy-device to help
to trasmit and receive data.
HNS hardware topology is as below. The MDIO controller may control several
PHY-devices, and each PHY-device connects to a MAC device. PHY-devices
will register when each mac find PHY device in initial sequence.

   cpu
|
|
 ---
|   |   |
|   |   |
|  dsaf |
   MDIO |  MDIO
|  ---  |
| | | |   | |
| | | |   | |
|MAC   MAC   MAC MAC|
| | | |   | |
  | | |   | 
 ||||||   ||
 PHY   PHY   PHY PHY

Signed-off-by: Kejian Yan 
Signed-off-by: Yisen Zhuang 
---
change log:
 v2: fix the build error by kbuild test robot

 v1: first submit
  link: https://lkml.org/lkml/2016/5/13/97
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 133 --
 1 file changed, 126 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c 
b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 3ef0c9b..c526558 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -7,6 +7,7 @@
  * (at your option) any later version.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -638,6 +639,115 @@ free_mac_drv:
return ret;
 }
 
+static int
+hns_mac_phy_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
+{
+   u32 addr;
+   int ret;
+
+   ret = fwnode_property_read_u32(fwnode, "phy-addr", );
+   if (ret) {
+   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;
+}
+
+static int hns_mac_phydev_match(struct device *dev, void *fwnode)
+{
+   return dev->fwnode == fwnode;
+}
+
+static struct
+platform_device *hns_mac_find_platform_device(struct fwnode_handle *fwnode)
+{
+   struct device *dev;
+
+   dev = bus_find_device(_bus_type, NULL,
+ fwnode, hns_mac_phydev_match);
+   return dev ? to_platform_device(dev) : NULL;
+}
+
+static int
+hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb,
+   u32 addr)
+{
+   struct phy_device *phy;
+   const char *phy_type;
+   bool is_c45;
+   int rc;
+
+   rc = fwnode_property_read_string(mac_cb->fw_port,
+"phy-mode", _type);
+   if (rc < 0)
+   return rc;
+
+   if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_XGMII)))
+   is_c45 = 1;
+   else if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_SGMII)))
+   is_c45 = 0;
+   else
+   return -ENODATA;
+
+   phy = get_phy_device(mdio, addr, is_c45);
+   if (!phy || IS_ERR(phy))
+   return -EIO;
+
+   if (mdio->irq)
+   phy->irq = mdio->irq[addr];
+
+   /* All data is now stored in the phy struct;
+* register it
+*/
+   rc = phy_device_register(phy);
+   if (rc) {
+   phy_device_free(phy);
+   return -ENODEV;
+   }
+
+   mac_cb->phy_dev = phy;
+
+   dev_dbg(>dev, "registered phy at address %i\n", addr);
+
+   return 0;
+}
+
+static void hns_mac_register_phy(struct hns_mac_cb *mac_cb)
+{
+   struct acpi_reference_args args;
+   struct platform_device *pdev;
+   struct mii_bus *mii_bus;
+   int rc;
+   int addr;
+
+   /* Loop over the child nodes and register a phy_device for each one */
+   if (!to_acpi_device_node(mac_cb->fw_port))
+   return;
+
+   rc = acpi_node_get_property_reference(
+   mac_cb->fw_port, "mdio-node", 0, );
+   if (rc)
+   return;
+
+   addr = hns_mac_phy_parse_addr(mac_cb->dev, mac_cb->fw_port);
+   if (addr < 0)
+   return;
+
+   /* dev address in adev */
+   pdev = hns_mac_find_platform_device(acpi_fwnode_handle(args.adev));
+   mii_bus = platform_get_drvdata(pdev);
+   rc = hns_mac_register_phydev(mii_bus, mac_cb, addr);
+   if (!rc)
+   dev_dbg(mac_cb->dev, "mac%d register phy addr:%d\n",

[PATCH v4 net-next 11/13] net: hns: register phy device in each mac initial sequence

2016-06-02 Thread Yisen Zhuang
From: Kejian Yan 

In ACPI case, there is no interface to register phy device to mdio-bus.
Phy device has to be registered itself to mdio-bus, and then enet can
get the phy device's info so that it can config the phy-device to help
to trasmit and receive data.
HNS hardware topology is as below. The MDIO controller may control several
PHY-devices, and each PHY-device connects to a MAC device. PHY-devices
will register when each mac find PHY device in initial sequence.

   cpu
|
|
 ---
|   |   |
|   |   |
|  dsaf |
   MDIO |  MDIO
|  ---  |
| | | |   | |
| | | |   | |
|MAC   MAC   MAC MAC|
| | | |   | |
  | | |   | 
 ||||||   ||
 PHY   PHY   PHY PHY

Signed-off-by: Kejian Yan 
Signed-off-by: Yisen Zhuang 
---
change log:
 v2: fix the build error by kbuild test robot

 v1: first submit
  link: https://lkml.org/lkml/2016/5/13/97
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 133 --
 1 file changed, 126 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c 
b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 3ef0c9b..c526558 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -7,6 +7,7 @@
  * (at your option) any later version.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -638,6 +639,115 @@ free_mac_drv:
return ret;
 }
 
+static int
+hns_mac_phy_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
+{
+   u32 addr;
+   int ret;
+
+   ret = fwnode_property_read_u32(fwnode, "phy-addr", );
+   if (ret) {
+   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;
+}
+
+static int hns_mac_phydev_match(struct device *dev, void *fwnode)
+{
+   return dev->fwnode == fwnode;
+}
+
+static struct
+platform_device *hns_mac_find_platform_device(struct fwnode_handle *fwnode)
+{
+   struct device *dev;
+
+   dev = bus_find_device(_bus_type, NULL,
+ fwnode, hns_mac_phydev_match);
+   return dev ? to_platform_device(dev) : NULL;
+}
+
+static int
+hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb,
+   u32 addr)
+{
+   struct phy_device *phy;
+   const char *phy_type;
+   bool is_c45;
+   int rc;
+
+   rc = fwnode_property_read_string(mac_cb->fw_port,
+"phy-mode", _type);
+   if (rc < 0)
+   return rc;
+
+   if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_XGMII)))
+   is_c45 = 1;
+   else if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_SGMII)))
+   is_c45 = 0;
+   else
+   return -ENODATA;
+
+   phy = get_phy_device(mdio, addr, is_c45);
+   if (!phy || IS_ERR(phy))
+   return -EIO;
+
+   if (mdio->irq)
+   phy->irq = mdio->irq[addr];
+
+   /* All data is now stored in the phy struct;
+* register it
+*/
+   rc = phy_device_register(phy);
+   if (rc) {
+   phy_device_free(phy);
+   return -ENODEV;
+   }
+
+   mac_cb->phy_dev = phy;
+
+   dev_dbg(>dev, "registered phy at address %i\n", addr);
+
+   return 0;
+}
+
+static void hns_mac_register_phy(struct hns_mac_cb *mac_cb)
+{
+   struct acpi_reference_args args;
+   struct platform_device *pdev;
+   struct mii_bus *mii_bus;
+   int rc;
+   int addr;
+
+   /* Loop over the child nodes and register a phy_device for each one */
+   if (!to_acpi_device_node(mac_cb->fw_port))
+   return;
+
+   rc = acpi_node_get_property_reference(
+   mac_cb->fw_port, "mdio-node", 0, );
+   if (rc)
+   return;
+
+   addr = hns_mac_phy_parse_addr(mac_cb->dev, mac_cb->fw_port);
+   if (addr < 0)
+   return;
+
+   /* dev address in adev */
+   pdev = hns_mac_find_platform_device(acpi_fwnode_handle(args.adev));
+   mii_bus = platform_get_drvdata(pdev);
+   rc = hns_mac_register_phydev(mii_bus, mac_cb, addr);
+   if (!rc)
+   dev_dbg(mac_cb->dev, "mac%d register phy addr:%d\n",
+   mac_cb->mac_id, addr);
+}
+
 /**