ethtool.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /* This program is free software; you can redistribute it and/or modify
  2. * it under the terms of the GNU General Public License as published by
  3. * the Free Software Foundation; version 2 of the License
  4. *
  5. * This program is distributed in the hope that it will be useful,
  6. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. * GNU General Public License for more details.
  9. *
  10. * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
  11. * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
  12. * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
  13. */
  14. #include "mtk_eth_soc.h"
  15. #include "ethtool.h"
  16. struct mtk_stat {
  17. char name[ETH_GSTRING_LEN];
  18. unsigned int idx;
  19. };
  20. #define MTK_HW_STAT(stat) { \
  21. .name = #stat, \
  22. .idx = offsetof(struct mtk_hw_stats, stat) / sizeof(u64) \
  23. }
  24. static const struct mtk_stat mtk_ethtool_hw_stats[] = {
  25. MTK_HW_STAT(tx_bytes),
  26. MTK_HW_STAT(tx_packets),
  27. MTK_HW_STAT(tx_skip),
  28. MTK_HW_STAT(tx_collisions),
  29. MTK_HW_STAT(rx_bytes),
  30. MTK_HW_STAT(rx_packets),
  31. MTK_HW_STAT(rx_overflow),
  32. MTK_HW_STAT(rx_fcs_errors),
  33. MTK_HW_STAT(rx_short_errors),
  34. MTK_HW_STAT(rx_long_errors),
  35. MTK_HW_STAT(rx_checksum_errors),
  36. MTK_HW_STAT(rx_flow_control_packets),
  37. };
  38. #define MTK_HW_STATS_LEN ARRAY_SIZE(mtk_ethtool_hw_stats)
  39. static int mtk_get_link_ksettings(struct net_device *dev,
  40. struct ethtool_link_ksettings *cmd)
  41. {
  42. struct mtk_mac *mac = netdev_priv(dev);
  43. int err;
  44. if (!mac->phy_dev)
  45. return -ENODEV;
  46. if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
  47. err = phy_read_status(mac->phy_dev);
  48. if (err)
  49. return -ENODEV;
  50. }
  51. phy_ethtool_ksettings_get(mac->phy_dev, cmd);
  52. return 0;
  53. }
  54. static int mtk_set_link_ksettings(struct net_device *dev,
  55. const struct ethtool_link_ksettings *cmd)
  56. {
  57. struct mtk_mac *mac = netdev_priv(dev);
  58. if (!mac->phy_dev)
  59. return -ENODEV;
  60. if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
  61. if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
  62. mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
  63. mac->phy_flags = MTK_PHY_FLAG_PORT;
  64. } else if (mac->hw->mii_bus) {
  65. mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
  66. cmd->base.phy_address);
  67. if (!mac->phy_dev)
  68. return -ENODEV;
  69. mac->phy_flags = MTK_PHY_FLAG_ATTACH;
  70. } else {
  71. return -ENODEV;
  72. }
  73. }
  74. return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
  75. }
  76. static void mtk_get_drvinfo(struct net_device *dev,
  77. struct ethtool_drvinfo *info)
  78. {
  79. struct mtk_mac *mac = netdev_priv(dev);
  80. struct mtk_soc_data *soc = mac->hw->soc;
  81. strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
  82. strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
  83. if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
  84. info->n_stats = MTK_HW_STATS_LEN;
  85. }
  86. static u32 mtk_get_msglevel(struct net_device *dev)
  87. {
  88. struct mtk_mac *mac = netdev_priv(dev);
  89. return mac->hw->msg_enable;
  90. }
  91. static void mtk_set_msglevel(struct net_device *dev, u32 value)
  92. {
  93. struct mtk_mac *mac = netdev_priv(dev);
  94. mac->hw->msg_enable = value;
  95. }
  96. static int mtk_nway_reset(struct net_device *dev)
  97. {
  98. struct mtk_mac *mac = netdev_priv(dev);
  99. if (!mac->phy_dev)
  100. return -EOPNOTSUPP;
  101. return genphy_restart_aneg(mac->phy_dev);
  102. }
  103. static u32 mtk_get_link(struct net_device *dev)
  104. {
  105. struct mtk_mac *mac = netdev_priv(dev);
  106. int err;
  107. if (!mac->phy_dev)
  108. goto out_get_link;
  109. if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
  110. err = genphy_update_link(mac->phy_dev);
  111. if (err)
  112. goto out_get_link;
  113. }
  114. return mac->phy_dev->link;
  115. out_get_link:
  116. return ethtool_op_get_link(dev);
  117. }
  118. static int mtk_set_ringparam(struct net_device *dev,
  119. struct ethtool_ringparam *ring)
  120. {
  121. struct mtk_mac *mac = netdev_priv(dev);
  122. if ((ring->tx_pending < 2) ||
  123. (ring->rx_pending < 2) ||
  124. (ring->rx_pending > mac->hw->soc->dma_ring_size) ||
  125. (ring->tx_pending > mac->hw->soc->dma_ring_size))
  126. return -EINVAL;
  127. dev->netdev_ops->ndo_stop(dev);
  128. mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
  129. mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
  130. return dev->netdev_ops->ndo_open(dev);
  131. }
  132. static void mtk_get_ringparam(struct net_device *dev,
  133. struct ethtool_ringparam *ring)
  134. {
  135. struct mtk_mac *mac = netdev_priv(dev);
  136. ring->rx_max_pending = mac->hw->soc->dma_ring_size;
  137. ring->tx_max_pending = mac->hw->soc->dma_ring_size;
  138. ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
  139. ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
  140. }
  141. static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
  142. {
  143. int i;
  144. switch (stringset) {
  145. case ETH_SS_STATS:
  146. for (i = 0; i < MTK_HW_STATS_LEN; i++) {
  147. memcpy(data, mtk_ethtool_hw_stats[i].name,
  148. ETH_GSTRING_LEN);
  149. data += ETH_GSTRING_LEN;
  150. }
  151. break;
  152. }
  153. }
  154. static int mtk_get_sset_count(struct net_device *dev, int sset)
  155. {
  156. switch (sset) {
  157. case ETH_SS_STATS:
  158. return MTK_HW_STATS_LEN;
  159. default:
  160. return -EOPNOTSUPP;
  161. }
  162. }
  163. static void mtk_get_ethtool_stats(struct net_device *dev,
  164. struct ethtool_stats *stats, u64 *data)
  165. {
  166. struct mtk_mac *mac = netdev_priv(dev);
  167. struct mtk_hw_stats *hwstats = mac->hw_stats;
  168. unsigned int start;
  169. int i;
  170. if (netif_running(dev) && netif_device_present(dev)) {
  171. if (spin_trylock(&hwstats->stats_lock)) {
  172. mtk_stats_update_mac(mac);
  173. spin_unlock(&hwstats->stats_lock);
  174. }
  175. }
  176. do {
  177. start = u64_stats_fetch_begin_irq(&hwstats->syncp);
  178. for (i = 0; i < MTK_HW_STATS_LEN; i++)
  179. data[i] = ((u64 *)hwstats)[mtk_ethtool_hw_stats[i].idx];
  180. } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
  181. }
  182. static struct ethtool_ops mtk_ethtool_ops = {
  183. .get_link_ksettings = mtk_get_link_ksettings,
  184. .set_link_ksettings = mtk_set_link_ksettings,
  185. .get_drvinfo = mtk_get_drvinfo,
  186. .get_msglevel = mtk_get_msglevel,
  187. .set_msglevel = mtk_set_msglevel,
  188. .nway_reset = mtk_nway_reset,
  189. .get_link = mtk_get_link,
  190. .set_ringparam = mtk_set_ringparam,
  191. .get_ringparam = mtk_get_ringparam,
  192. };
  193. void mtk_set_ethtool_ops(struct net_device *netdev)
  194. {
  195. struct mtk_mac *mac = netdev_priv(netdev);
  196. struct mtk_soc_data *soc = mac->hw->soc;
  197. if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
  198. mtk_ethtool_ops.get_strings = mtk_get_strings;
  199. mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
  200. mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
  201. }
  202. netdev->ethtool_ops = &mtk_ethtool_ops;
  203. }