ethernet-mdio.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * This file is based on code from OCTEON SDK by Cavium Networks.
  4. *
  5. * Copyright (c) 2003-2007 Cavium Networks
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/ethtool.h>
  9. #include <linux/phy.h>
  10. #include <linux/ratelimit.h>
  11. #include <linux/of_mdio.h>
  12. #include <generated/utsrelease.h>
  13. #include <net/dst.h>
  14. #include <asm/octeon/octeon.h>
  15. #include "ethernet-defines.h"
  16. #include "octeon-ethernet.h"
  17. #include "ethernet-mdio.h"
  18. #include "ethernet-util.h"
  19. #include <asm/octeon/cvmx-gmxx-defs.h>
  20. #include <asm/octeon/cvmx-smix-defs.h>
  21. static void cvm_oct_get_drvinfo(struct net_device *dev,
  22. struct ethtool_drvinfo *info)
  23. {
  24. strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
  25. strlcpy(info->version, UTS_RELEASE, sizeof(info->version));
  26. strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info));
  27. }
  28. static int cvm_oct_nway_reset(struct net_device *dev)
  29. {
  30. if (!capable(CAP_NET_ADMIN))
  31. return -EPERM;
  32. if (dev->phydev)
  33. return phy_start_aneg(dev->phydev);
  34. return -EINVAL;
  35. }
  36. const struct ethtool_ops cvm_oct_ethtool_ops = {
  37. .get_drvinfo = cvm_oct_get_drvinfo,
  38. .nway_reset = cvm_oct_nway_reset,
  39. .get_link = ethtool_op_get_link,
  40. .get_link_ksettings = phy_ethtool_get_link_ksettings,
  41. .set_link_ksettings = phy_ethtool_set_link_ksettings,
  42. };
  43. /**
  44. * cvm_oct_ioctl - IOCTL support for PHY control
  45. * @dev: Device to change
  46. * @rq: the request
  47. * @cmd: the command
  48. *
  49. * Returns Zero on success
  50. */
  51. int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  52. {
  53. if (!netif_running(dev))
  54. return -EINVAL;
  55. if (!dev->phydev)
  56. return -EINVAL;
  57. return phy_mii_ioctl(dev->phydev, rq, cmd);
  58. }
  59. void cvm_oct_note_carrier(struct octeon_ethernet *priv,
  60. cvmx_helper_link_info_t li)
  61. {
  62. if (li.s.link_up) {
  63. pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d, queue %d\n",
  64. netdev_name(priv->netdev), li.s.speed,
  65. (li.s.full_duplex) ? "Full" : "Half",
  66. priv->port, priv->queue);
  67. } else {
  68. pr_notice_ratelimited("%s: Link down\n",
  69. netdev_name(priv->netdev));
  70. }
  71. }
  72. void cvm_oct_adjust_link(struct net_device *dev)
  73. {
  74. struct octeon_ethernet *priv = netdev_priv(dev);
  75. cvmx_helper_link_info_t link_info;
  76. link_info.u64 = 0;
  77. link_info.s.link_up = dev->phydev->link ? 1 : 0;
  78. link_info.s.full_duplex = dev->phydev->duplex ? 1 : 0;
  79. link_info.s.speed = dev->phydev->speed;
  80. priv->link_info = link_info.u64;
  81. /*
  82. * The polling task need to know about link status changes.
  83. */
  84. if (priv->poll)
  85. priv->poll(dev);
  86. if (priv->last_link != dev->phydev->link) {
  87. priv->last_link = dev->phydev->link;
  88. cvmx_helper_link_set(priv->port, link_info);
  89. cvm_oct_note_carrier(priv, link_info);
  90. }
  91. }
  92. int cvm_oct_common_stop(struct net_device *dev)
  93. {
  94. struct octeon_ethernet *priv = netdev_priv(dev);
  95. int interface = INTERFACE(priv->port);
  96. cvmx_helper_link_info_t link_info;
  97. union cvmx_gmxx_prtx_cfg gmx_cfg;
  98. int index = INDEX(priv->port);
  99. gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  100. gmx_cfg.s.en = 0;
  101. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
  102. priv->poll = NULL;
  103. if (dev->phydev)
  104. phy_disconnect(dev->phydev);
  105. if (priv->last_link) {
  106. link_info.u64 = 0;
  107. priv->last_link = 0;
  108. cvmx_helper_link_set(priv->port, link_info);
  109. cvm_oct_note_carrier(priv, link_info);
  110. }
  111. return 0;
  112. }
  113. /**
  114. * cvm_oct_phy_setup_device - setup the PHY
  115. *
  116. * @dev: Device to setup
  117. *
  118. * Returns Zero on success, negative on failure
  119. */
  120. int cvm_oct_phy_setup_device(struct net_device *dev)
  121. {
  122. struct octeon_ethernet *priv = netdev_priv(dev);
  123. struct device_node *phy_node;
  124. struct phy_device *phydev = NULL;
  125. if (!priv->of_node)
  126. goto no_phy;
  127. phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
  128. if (!phy_node && of_phy_is_fixed_link(priv->of_node)) {
  129. int rc;
  130. rc = of_phy_register_fixed_link(priv->of_node);
  131. if (rc)
  132. return rc;
  133. phy_node = of_node_get(priv->of_node);
  134. }
  135. if (!phy_node)
  136. goto no_phy;
  137. phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
  138. PHY_INTERFACE_MODE_GMII);
  139. of_node_put(phy_node);
  140. if (!phydev)
  141. return -ENODEV;
  142. priv->last_link = 0;
  143. phy_start_aneg(phydev);
  144. return 0;
  145. no_phy:
  146. /* If there is no phy, assume a direct MAC connection and that
  147. * the link is up.
  148. */
  149. netif_carrier_on(dev);
  150. return 0;
  151. }