xgene_enet_ethtool.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /* Applied Micro X-Gene SoC Ethernet Driver
  2. *
  3. * Copyright (c) 2014, Applied Micro Circuits Corporation
  4. * Authors: Iyappan Subramanian <isubramanian@apm.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <linux/ethtool.h>
  20. #include "xgene_enet_main.h"
  21. struct xgene_gstrings_stats {
  22. char name[ETH_GSTRING_LEN];
  23. int offset;
  24. u32 addr;
  25. u32 mask;
  26. };
  27. #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
  28. #define XGENE_EXTD_STAT(s, a, m) \
  29. { \
  30. .name = #s, \
  31. .addr = a ## _ADDR, \
  32. .mask = m \
  33. }
  34. static const struct xgene_gstrings_stats gstrings_stats[] = {
  35. XGENE_STAT(rx_packets),
  36. XGENE_STAT(tx_packets),
  37. XGENE_STAT(rx_bytes),
  38. XGENE_STAT(tx_bytes),
  39. XGENE_STAT(rx_errors),
  40. XGENE_STAT(tx_errors),
  41. XGENE_STAT(rx_length_errors),
  42. XGENE_STAT(rx_crc_errors),
  43. XGENE_STAT(rx_frame_errors),
  44. XGENE_STAT(rx_fifo_errors)
  45. };
  46. static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
  47. XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
  48. XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
  49. XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
  50. XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
  51. XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
  52. XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
  53. XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
  54. XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
  55. XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
  56. XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
  57. XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
  58. XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
  59. XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
  60. XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
  61. XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
  62. XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),
  63. XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
  64. XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
  65. XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
  66. XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
  67. XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
  68. XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
  69. XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
  70. XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
  71. XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
  72. XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
  73. XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
  74. XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
  75. XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
  76. XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
  77. XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
  78. XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
  79. XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
  80. XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
  81. XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
  82. XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
  83. XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
  84. XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
  85. XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
  86. XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
  87. XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
  88. XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
  89. XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),
  90. XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)
  91. };
  92. #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)
  93. #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats)
  94. #define RFCS_IDX 7
  95. #define RALN_IDX 13
  96. #define RFLR_IDX 14
  97. #define FALSE_RFLR_IDX 15
  98. #define RUND_IDX 18
  99. #define FALSE_RJBR_IDX 22
  100. #define RX_OVERRUN_IDX 24
  101. #define TFCS_IDX 38
  102. #define TFRG_IDX 42
  103. #define TX_UNDERRUN_IDX 43
  104. static void xgene_get_drvinfo(struct net_device *ndev,
  105. struct ethtool_drvinfo *info)
  106. {
  107. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  108. struct platform_device *pdev = pdata->pdev;
  109. strcpy(info->driver, "xgene_enet");
  110. strcpy(info->version, XGENE_DRV_VERSION);
  111. snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A");
  112. sprintf(info->bus_info, "%s", pdev->name);
  113. }
  114. static int xgene_get_link_ksettings(struct net_device *ndev,
  115. struct ethtool_link_ksettings *cmd)
  116. {
  117. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  118. struct phy_device *phydev = ndev->phydev;
  119. u32 supported;
  120. if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
  121. if (phydev == NULL)
  122. return -ENODEV;
  123. phy_ethtool_ksettings_get(phydev, cmd);
  124. return 0;
  125. } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
  126. if (pdata->mdio_driver) {
  127. if (!phydev)
  128. return -ENODEV;
  129. phy_ethtool_ksettings_get(phydev, cmd);
  130. return 0;
  131. }
  132. supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
  133. SUPPORTED_MII;
  134. ethtool_convert_legacy_u32_to_link_mode(
  135. cmd->link_modes.supported,
  136. supported);
  137. ethtool_convert_legacy_u32_to_link_mode(
  138. cmd->link_modes.advertising,
  139. supported);
  140. cmd->base.speed = SPEED_1000;
  141. cmd->base.duplex = DUPLEX_FULL;
  142. cmd->base.port = PORT_MII;
  143. cmd->base.autoneg = AUTONEG_ENABLE;
  144. } else {
  145. supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
  146. ethtool_convert_legacy_u32_to_link_mode(
  147. cmd->link_modes.supported,
  148. supported);
  149. ethtool_convert_legacy_u32_to_link_mode(
  150. cmd->link_modes.advertising,
  151. supported);
  152. cmd->base.speed = SPEED_10000;
  153. cmd->base.duplex = DUPLEX_FULL;
  154. cmd->base.port = PORT_FIBRE;
  155. cmd->base.autoneg = AUTONEG_DISABLE;
  156. }
  157. return 0;
  158. }
  159. static int xgene_set_link_ksettings(struct net_device *ndev,
  160. const struct ethtool_link_ksettings *cmd)
  161. {
  162. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  163. struct phy_device *phydev = ndev->phydev;
  164. if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
  165. if (!phydev)
  166. return -ENODEV;
  167. return phy_ethtool_ksettings_set(phydev, cmd);
  168. }
  169. if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
  170. if (pdata->mdio_driver) {
  171. if (!phydev)
  172. return -ENODEV;
  173. return phy_ethtool_ksettings_set(phydev, cmd);
  174. }
  175. }
  176. return -EINVAL;
  177. }
  178. static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
  179. {
  180. int i;
  181. u8 *p = data;
  182. if (stringset != ETH_SS_STATS)
  183. return;
  184. for (i = 0; i < XGENE_STATS_LEN; i++) {
  185. memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
  186. p += ETH_GSTRING_LEN;
  187. }
  188. for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
  189. memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
  190. p += ETH_GSTRING_LEN;
  191. }
  192. }
  193. static int xgene_get_sset_count(struct net_device *ndev, int sset)
  194. {
  195. if (sset != ETH_SS_STATS)
  196. return -EINVAL;
  197. return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
  198. }
  199. static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
  200. {
  201. u32 rx_drop, tx_drop;
  202. u32 mask, tmp;
  203. int i;
  204. for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
  205. tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
  206. if (gstrings_extd_stats[i].mask) {
  207. mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
  208. pdata->extd_stats[i] += (tmp & mask);
  209. }
  210. }
  211. if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
  212. /* Errata 10GE_10 - SW should intepret RALN as 0 */
  213. pdata->extd_stats[RALN_IDX] = 0;
  214. } else {
  215. /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
  216. pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
  217. pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
  218. pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
  219. }
  220. pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
  221. pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;
  222. pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;
  223. /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */
  224. pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
  225. /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
  226. pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
  227. }
  228. int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
  229. {
  230. pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
  231. XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
  232. if (!pdata->extd_stats)
  233. return -ENOMEM;
  234. xgene_get_extd_stats(pdata);
  235. memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));
  236. return 0;
  237. }
  238. static void xgene_get_ethtool_stats(struct net_device *ndev,
  239. struct ethtool_stats *dummy,
  240. u64 *data)
  241. {
  242. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  243. struct rtnl_link_stats64 stats;
  244. int i;
  245. dev_get_stats(ndev, &stats);
  246. for (i = 0; i < XGENE_STATS_LEN; i++)
  247. data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);
  248. xgene_get_extd_stats(pdata);
  249. for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
  250. data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
  251. }
  252. static void xgene_get_pauseparam(struct net_device *ndev,
  253. struct ethtool_pauseparam *pp)
  254. {
  255. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  256. pp->autoneg = pdata->pause_autoneg;
  257. pp->tx_pause = pdata->tx_pause;
  258. pp->rx_pause = pdata->rx_pause;
  259. }
  260. static int xgene_set_pauseparam(struct net_device *ndev,
  261. struct ethtool_pauseparam *pp)
  262. {
  263. struct xgene_enet_pdata *pdata = netdev_priv(ndev);
  264. struct phy_device *phydev = ndev->phydev;
  265. u32 oldadv, newadv;
  266. if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||
  267. pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
  268. if (!phydev)
  269. return -EINVAL;
  270. if (!(phydev->supported & SUPPORTED_Pause) ||
  271. (!(phydev->supported & SUPPORTED_Asym_Pause) &&
  272. pp->rx_pause != pp->tx_pause))
  273. return -EINVAL;
  274. pdata->pause_autoneg = pp->autoneg;
  275. pdata->tx_pause = pp->tx_pause;
  276. pdata->rx_pause = pp->rx_pause;
  277. oldadv = phydev->advertising;
  278. newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
  279. if (pp->rx_pause)
  280. newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
  281. if (pp->tx_pause)
  282. newadv ^= ADVERTISED_Asym_Pause;
  283. if (oldadv ^ newadv) {
  284. phydev->advertising = newadv;
  285. if (phydev->autoneg)
  286. return phy_start_aneg(phydev);
  287. if (!pp->autoneg) {
  288. pdata->mac_ops->flowctl_tx(pdata,
  289. pdata->tx_pause);
  290. pdata->mac_ops->flowctl_rx(pdata,
  291. pdata->rx_pause);
  292. }
  293. }
  294. } else {
  295. if (pp->autoneg)
  296. return -EINVAL;
  297. pdata->tx_pause = pp->tx_pause;
  298. pdata->rx_pause = pp->rx_pause;
  299. pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
  300. pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
  301. }
  302. return 0;
  303. }
  304. static const struct ethtool_ops xgene_ethtool_ops = {
  305. .get_drvinfo = xgene_get_drvinfo,
  306. .get_link = ethtool_op_get_link,
  307. .get_strings = xgene_get_strings,
  308. .get_sset_count = xgene_get_sset_count,
  309. .get_ethtool_stats = xgene_get_ethtool_stats,
  310. .get_link_ksettings = xgene_get_link_ksettings,
  311. .set_link_ksettings = xgene_set_link_ksettings,
  312. .get_pauseparam = xgene_get_pauseparam,
  313. .set_pauseparam = xgene_set_pauseparam
  314. };
  315. void xgene_enet_set_ethtool_ops(struct net_device *ndev)
  316. {
  317. ndev->ethtool_ops = &xgene_ethtool_ops;
  318. }