bcmasp_ethtool.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define pr_fmt(fmt) "bcmasp_ethtool: " fmt
  3. #include <linux/unaligned.h>
  4. #include <linux/ethtool.h>
  5. #include <linux/netdevice.h>
  6. #include <linux/platform_device.h>
  7. #include "bcmasp.h"
  8. #include "bcmasp_intf_defs.h"
  9. enum bcmasp_stat_type {
  10. BCMASP_STAT_RX_EDPKT,
  11. BCMASP_STAT_RX_CTRL,
  12. BCMASP_STAT_RX_CTRL_PER_INTF,
  13. BCMASP_STAT_SOFT,
  14. };
  15. struct bcmasp_stats {
  16. char stat_string[ETH_GSTRING_LEN];
  17. enum bcmasp_stat_type type;
  18. u32 reg_offset;
  19. };
  20. #define STAT_BCMASP_SOFT_MIB(str) { \
  21. .stat_string = str, \
  22. .type = BCMASP_STAT_SOFT, \
  23. }
  24. #define STAT_BCMASP_OFFSET(str, _type, offset) { \
  25. .stat_string = str, \
  26. .type = _type, \
  27. .reg_offset = offset, \
  28. }
  29. #define STAT_BCMASP_RX_EDPKT(str, offset) \
  30. STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_EDPKT, offset)
  31. #define STAT_BCMASP_RX_CTRL(str, offset) \
  32. STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset)
  33. #define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \
  34. STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL_PER_INTF, offset)
  35. /* Must match the order of struct bcmasp_mib_counters */
  36. static const struct bcmasp_stats bcmasp_gstrings_stats[] = {
  37. /* EDPKT counters */
  38. STAT_BCMASP_RX_EDPKT("RX Time Stamp", ASP_EDPKT_RX_TS_COUNTER),
  39. STAT_BCMASP_RX_EDPKT("RX PKT Count", ASP_EDPKT_RX_PKT_CNT),
  40. STAT_BCMASP_RX_EDPKT("RX PKT Buffered", ASP_EDPKT_HDR_EXTR_CNT),
  41. STAT_BCMASP_RX_EDPKT("RX PKT Pushed to DRAM", ASP_EDPKT_HDR_OUT_CNT),
  42. /* ASP RX control */
  43. STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac",
  44. ASP_RX_CTRL_UMAC_0_FRAME_COUNT),
  45. STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Port",
  46. ASP_RX_CTRL_FB_0_FRAME_COUNT),
  47. STAT_BCMASP_RX_CTRL_PER_INTF("RX Buffer FIFO Depth",
  48. ASP_RX_CTRL_FB_RX_FIFO_DEPTH),
  49. STAT_BCMASP_RX_CTRL("Frames Out(Buffer)",
  50. ASP_RX_CTRL_FB_OUT_FRAME_COUNT),
  51. STAT_BCMASP_RX_CTRL("Frames Out(Filters)",
  52. ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT),
  53. /* Software maintained statistics */
  54. STAT_BCMASP_SOFT_MIB("RX SKB Alloc Failed"),
  55. STAT_BCMASP_SOFT_MIB("TX DMA Failed"),
  56. STAT_BCMASP_SOFT_MIB("Multicast Filters Full"),
  57. STAT_BCMASP_SOFT_MIB("Unicast Filters Full"),
  58. STAT_BCMASP_SOFT_MIB("MDA Filters Combined"),
  59. STAT_BCMASP_SOFT_MIB("Promisc Filter Set"),
  60. STAT_BCMASP_SOFT_MIB("TX Realloc For Offload Failed"),
  61. STAT_BCMASP_SOFT_MIB("Tx Timeout Count"),
  62. };
  63. #define BCMASP_STATS_LEN ARRAY_SIZE(bcmasp_gstrings_stats)
  64. static u16 bcmasp_stat_fixup_offset(struct bcmasp_intf *intf,
  65. const struct bcmasp_stats *s)
  66. {
  67. struct bcmasp_priv *priv = intf->parent;
  68. if (!strcmp("Frames Out(Buffer)", s->stat_string))
  69. return priv->hw_info->rx_ctrl_fb_out_frame_count;
  70. if (!strcmp("Frames Out(Filters)", s->stat_string))
  71. return priv->hw_info->rx_ctrl_fb_filt_out_frame_count;
  72. if (!strcmp("RX Buffer FIFO Depth", s->stat_string))
  73. return priv->hw_info->rx_ctrl_fb_rx_fifo_depth;
  74. return s->reg_offset;
  75. }
  76. static int bcmasp_get_sset_count(struct net_device *dev, int string_set)
  77. {
  78. switch (string_set) {
  79. case ETH_SS_STATS:
  80. return BCMASP_STATS_LEN;
  81. default:
  82. return -EOPNOTSUPP;
  83. }
  84. }
  85. static void bcmasp_get_strings(struct net_device *dev, u32 stringset,
  86. u8 *data)
  87. {
  88. unsigned int i;
  89. switch (stringset) {
  90. case ETH_SS_STATS:
  91. for (i = 0; i < BCMASP_STATS_LEN; i++) {
  92. memcpy(data + i * ETH_GSTRING_LEN,
  93. bcmasp_gstrings_stats[i].stat_string,
  94. ETH_GSTRING_LEN);
  95. }
  96. break;
  97. default:
  98. return;
  99. }
  100. }
  101. static void bcmasp_update_mib_counters(struct bcmasp_intf *intf)
  102. {
  103. unsigned int i;
  104. for (i = 0; i < BCMASP_STATS_LEN; i++) {
  105. const struct bcmasp_stats *s;
  106. u32 offset, val;
  107. char *p;
  108. s = &bcmasp_gstrings_stats[i];
  109. offset = bcmasp_stat_fixup_offset(intf, s);
  110. switch (s->type) {
  111. case BCMASP_STAT_SOFT:
  112. continue;
  113. case BCMASP_STAT_RX_EDPKT:
  114. val = rx_edpkt_core_rl(intf->parent, offset);
  115. break;
  116. case BCMASP_STAT_RX_CTRL:
  117. val = rx_ctrl_core_rl(intf->parent, offset);
  118. break;
  119. case BCMASP_STAT_RX_CTRL_PER_INTF:
  120. offset += sizeof(u32) * intf->port;
  121. val = rx_ctrl_core_rl(intf->parent, offset);
  122. break;
  123. default:
  124. continue;
  125. }
  126. p = (char *)(&intf->mib) + (i * sizeof(u32));
  127. put_unaligned(val, (u32 *)p);
  128. }
  129. }
  130. static void bcmasp_get_ethtool_stats(struct net_device *dev,
  131. struct ethtool_stats *stats,
  132. u64 *data)
  133. {
  134. struct bcmasp_intf *intf = netdev_priv(dev);
  135. unsigned int i;
  136. char *p;
  137. if (netif_running(dev))
  138. bcmasp_update_mib_counters(intf);
  139. for (i = 0; i < BCMASP_STATS_LEN; i++) {
  140. p = (char *)(&intf->mib) + (i * sizeof(u32));
  141. data[i] = *(u32 *)p;
  142. }
  143. }
  144. static void bcmasp_get_drvinfo(struct net_device *dev,
  145. struct ethtool_drvinfo *info)
  146. {
  147. strscpy(info->driver, "bcmasp", sizeof(info->driver));
  148. strscpy(info->bus_info, dev_name(dev->dev.parent),
  149. sizeof(info->bus_info));
  150. }
  151. static u32 bcmasp_get_msglevel(struct net_device *dev)
  152. {
  153. struct bcmasp_intf *intf = netdev_priv(dev);
  154. return intf->msg_enable;
  155. }
  156. static void bcmasp_set_msglevel(struct net_device *dev, u32 level)
  157. {
  158. struct bcmasp_intf *intf = netdev_priv(dev);
  159. intf->msg_enable = level;
  160. }
  161. #define BCMASP_SUPPORTED_WAKE (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER)
  162. static void bcmasp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  163. {
  164. struct bcmasp_intf *intf = netdev_priv(dev);
  165. wol->supported = BCMASP_SUPPORTED_WAKE;
  166. wol->wolopts = intf->wolopts;
  167. memset(wol->sopass, 0, sizeof(wol->sopass));
  168. if (wol->wolopts & WAKE_MAGICSECURE)
  169. memcpy(wol->sopass, intf->sopass, sizeof(intf->sopass));
  170. }
  171. static int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  172. {
  173. struct bcmasp_intf *intf = netdev_priv(dev);
  174. struct bcmasp_priv *priv = intf->parent;
  175. struct device *kdev = &priv->pdev->dev;
  176. if (!device_can_wakeup(kdev))
  177. return -EOPNOTSUPP;
  178. /* Interface Specific */
  179. intf->wolopts = wol->wolopts;
  180. if (intf->wolopts & WAKE_MAGICSECURE)
  181. memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass));
  182. mutex_lock(&priv->wol_lock);
  183. priv->enable_wol(intf, !!intf->wolopts);
  184. mutex_unlock(&priv->wol_lock);
  185. return 0;
  186. }
  187. static int bcmasp_flow_insert(struct net_device *dev, struct ethtool_rxnfc *cmd)
  188. {
  189. struct bcmasp_intf *intf = netdev_priv(dev);
  190. struct bcmasp_net_filter *nfilter;
  191. u32 loc = cmd->fs.location;
  192. bool wake = false;
  193. if (cmd->fs.ring_cookie == RX_CLS_FLOW_WAKE)
  194. wake = true;
  195. /* Currently only supports WAKE filters */
  196. if (!wake)
  197. return -EOPNOTSUPP;
  198. switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
  199. case ETHER_FLOW:
  200. case IP_USER_FLOW:
  201. case TCP_V4_FLOW:
  202. case UDP_V4_FLOW:
  203. case TCP_V6_FLOW:
  204. case UDP_V6_FLOW:
  205. break;
  206. default:
  207. return -EOPNOTSUPP;
  208. }
  209. /* Check if filter already exists */
  210. if (bcmasp_netfilt_check_dup(intf, &cmd->fs))
  211. return -EINVAL;
  212. nfilter = bcmasp_netfilt_get_init(intf, loc, wake, true);
  213. if (IS_ERR(nfilter))
  214. return PTR_ERR(nfilter);
  215. /* Return the location where we did insert the filter */
  216. cmd->fs.location = nfilter->hw_index;
  217. memcpy(&nfilter->fs, &cmd->fs, sizeof(struct ethtool_rx_flow_spec));
  218. /* Since we only support wake filters, defer register programming till
  219. * suspend time.
  220. */
  221. return 0;
  222. }
  223. static int bcmasp_flow_delete(struct net_device *dev, struct ethtool_rxnfc *cmd)
  224. {
  225. struct bcmasp_intf *intf = netdev_priv(dev);
  226. struct bcmasp_net_filter *nfilter;
  227. nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
  228. if (IS_ERR(nfilter))
  229. return PTR_ERR(nfilter);
  230. bcmasp_netfilt_release(intf, nfilter);
  231. return 0;
  232. }
  233. static int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd)
  234. {
  235. struct bcmasp_net_filter *nfilter;
  236. nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
  237. if (IS_ERR(nfilter))
  238. return PTR_ERR(nfilter);
  239. memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs));
  240. cmd->data = NUM_NET_FILTERS;
  241. return 0;
  242. }
  243. static int bcmasp_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
  244. {
  245. struct bcmasp_intf *intf = netdev_priv(dev);
  246. int ret = -EOPNOTSUPP;
  247. mutex_lock(&intf->parent->net_lock);
  248. switch (cmd->cmd) {
  249. case ETHTOOL_SRXCLSRLINS:
  250. ret = bcmasp_flow_insert(dev, cmd);
  251. break;
  252. case ETHTOOL_SRXCLSRLDEL:
  253. ret = bcmasp_flow_delete(dev, cmd);
  254. break;
  255. default:
  256. break;
  257. }
  258. mutex_unlock(&intf->parent->net_lock);
  259. return ret;
  260. }
  261. static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
  262. u32 *rule_locs)
  263. {
  264. struct bcmasp_intf *intf = netdev_priv(dev);
  265. int err = 0;
  266. mutex_lock(&intf->parent->net_lock);
  267. switch (cmd->cmd) {
  268. case ETHTOOL_GRXCLSRLCNT:
  269. cmd->rule_cnt = bcmasp_netfilt_get_active(intf);
  270. /* We support specifying rule locations */
  271. cmd->data |= RX_CLS_LOC_SPECIAL;
  272. break;
  273. case ETHTOOL_GRXCLSRULE:
  274. err = bcmasp_flow_get(intf, cmd);
  275. break;
  276. case ETHTOOL_GRXCLSRLALL:
  277. err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt);
  278. cmd->data = NUM_NET_FILTERS;
  279. break;
  280. default:
  281. err = -EOPNOTSUPP;
  282. break;
  283. }
  284. mutex_unlock(&intf->parent->net_lock);
  285. return err;
  286. }
  287. void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable)
  288. {
  289. u32 reg;
  290. reg = umac_rl(intf, UMC_EEE_CTRL);
  291. if (enable)
  292. reg |= EEE_EN;
  293. else
  294. reg &= ~EEE_EN;
  295. umac_wl(intf, reg, UMC_EEE_CTRL);
  296. intf->eee.eee_enabled = enable;
  297. }
  298. static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e)
  299. {
  300. struct bcmasp_intf *intf = netdev_priv(dev);
  301. struct ethtool_keee *p = &intf->eee;
  302. if (!dev->phydev)
  303. return -ENODEV;
  304. e->tx_lpi_enabled = p->tx_lpi_enabled;
  305. e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER);
  306. return phy_ethtool_get_eee(dev->phydev, e);
  307. }
  308. static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e)
  309. {
  310. struct bcmasp_intf *intf = netdev_priv(dev);
  311. struct ethtool_keee *p = &intf->eee;
  312. int ret;
  313. if (!dev->phydev)
  314. return -ENODEV;
  315. if (!p->eee_enabled) {
  316. bcmasp_eee_enable_set(intf, false);
  317. } else {
  318. ret = phy_init_eee(dev->phydev, 0);
  319. if (ret) {
  320. netif_err(intf, hw, dev,
  321. "EEE initialization failed: %d\n", ret);
  322. return ret;
  323. }
  324. umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER);
  325. intf->eee.tx_lpi_enabled = e->tx_lpi_enabled;
  326. bcmasp_eee_enable_set(intf, true);
  327. }
  328. return phy_ethtool_set_eee(dev->phydev, e);
  329. }
  330. static void bcmasp_get_eth_mac_stats(struct net_device *dev,
  331. struct ethtool_eth_mac_stats *mac_stats)
  332. {
  333. struct bcmasp_intf *intf = netdev_priv(dev);
  334. mac_stats->FramesTransmittedOK = umac_rl(intf, UMC_GTPOK);
  335. mac_stats->SingleCollisionFrames = umac_rl(intf, UMC_GTSCL);
  336. mac_stats->MultipleCollisionFrames = umac_rl(intf, UMC_GTMCL);
  337. mac_stats->FramesReceivedOK = umac_rl(intf, UMC_GRPOK);
  338. mac_stats->FrameCheckSequenceErrors = umac_rl(intf, UMC_GRFCS);
  339. mac_stats->AlignmentErrors = umac_rl(intf, UMC_GRALN);
  340. mac_stats->OctetsTransmittedOK = umac_rl(intf, UMC_GTBYT);
  341. mac_stats->FramesWithDeferredXmissions = umac_rl(intf, UMC_GTDRF);
  342. mac_stats->LateCollisions = umac_rl(intf, UMC_GTLCL);
  343. mac_stats->FramesAbortedDueToXSColls = umac_rl(intf, UMC_GTXCL);
  344. mac_stats->OctetsReceivedOK = umac_rl(intf, UMC_GRBYT);
  345. mac_stats->MulticastFramesXmittedOK = umac_rl(intf, UMC_GTMCA);
  346. mac_stats->BroadcastFramesXmittedOK = umac_rl(intf, UMC_GTBCA);
  347. mac_stats->FramesWithExcessiveDeferral = umac_rl(intf, UMC_GTEDF);
  348. mac_stats->MulticastFramesReceivedOK = umac_rl(intf, UMC_GRMCA);
  349. mac_stats->BroadcastFramesReceivedOK = umac_rl(intf, UMC_GRBCA);
  350. }
  351. static const struct ethtool_rmon_hist_range bcmasp_rmon_ranges[] = {
  352. { 0, 64},
  353. { 65, 127},
  354. { 128, 255},
  355. { 256, 511},
  356. { 512, 1023},
  357. { 1024, 1518},
  358. { 1519, 1522},
  359. {}
  360. };
  361. static void bcmasp_get_rmon_stats(struct net_device *dev,
  362. struct ethtool_rmon_stats *rmon_stats,
  363. const struct ethtool_rmon_hist_range **ranges)
  364. {
  365. struct bcmasp_intf *intf = netdev_priv(dev);
  366. *ranges = bcmasp_rmon_ranges;
  367. rmon_stats->undersize_pkts = umac_rl(intf, UMC_RRUND);
  368. rmon_stats->oversize_pkts = umac_rl(intf, UMC_GROVR);
  369. rmon_stats->fragments = umac_rl(intf, UMC_RRFRG);
  370. rmon_stats->jabbers = umac_rl(intf, UMC_GRJBR);
  371. rmon_stats->hist[0] = umac_rl(intf, UMC_GR64);
  372. rmon_stats->hist[1] = umac_rl(intf, UMC_GR127);
  373. rmon_stats->hist[2] = umac_rl(intf, UMC_GR255);
  374. rmon_stats->hist[3] = umac_rl(intf, UMC_GR511);
  375. rmon_stats->hist[4] = umac_rl(intf, UMC_GR1023);
  376. rmon_stats->hist[5] = umac_rl(intf, UMC_GR1518);
  377. rmon_stats->hist[6] = umac_rl(intf, UMC_GRMGV);
  378. rmon_stats->hist_tx[0] = umac_rl(intf, UMC_TR64);
  379. rmon_stats->hist_tx[1] = umac_rl(intf, UMC_TR127);
  380. rmon_stats->hist_tx[2] = umac_rl(intf, UMC_TR255);
  381. rmon_stats->hist_tx[3] = umac_rl(intf, UMC_TR511);
  382. rmon_stats->hist_tx[4] = umac_rl(intf, UMC_TR1023);
  383. rmon_stats->hist_tx[5] = umac_rl(intf, UMC_TR1518);
  384. rmon_stats->hist_tx[6] = umac_rl(intf, UMC_TRMGV);
  385. }
  386. static void bcmasp_get_eth_ctrl_stats(struct net_device *dev,
  387. struct ethtool_eth_ctrl_stats *ctrl_stats)
  388. {
  389. struct bcmasp_intf *intf = netdev_priv(dev);
  390. ctrl_stats->MACControlFramesTransmitted = umac_rl(intf, UMC_GTXCF);
  391. ctrl_stats->MACControlFramesReceived = umac_rl(intf, UMC_GRXCF);
  392. ctrl_stats->UnsupportedOpcodesReceived = umac_rl(intf, UMC_GRXUO);
  393. }
  394. const struct ethtool_ops bcmasp_ethtool_ops = {
  395. .get_drvinfo = bcmasp_get_drvinfo,
  396. .get_link = ethtool_op_get_link,
  397. .get_link_ksettings = phy_ethtool_get_link_ksettings,
  398. .set_link_ksettings = phy_ethtool_set_link_ksettings,
  399. .get_msglevel = bcmasp_get_msglevel,
  400. .set_msglevel = bcmasp_set_msglevel,
  401. .get_wol = bcmasp_get_wol,
  402. .set_wol = bcmasp_set_wol,
  403. .get_rxnfc = bcmasp_get_rxnfc,
  404. .set_rxnfc = bcmasp_set_rxnfc,
  405. .set_eee = bcmasp_set_eee,
  406. .get_eee = bcmasp_get_eee,
  407. .get_eth_mac_stats = bcmasp_get_eth_mac_stats,
  408. .get_rmon_stats = bcmasp_get_rmon_stats,
  409. .get_eth_ctrl_stats = bcmasp_get_eth_ctrl_stats,
  410. .get_strings = bcmasp_get_strings,
  411. .get_ethtool_stats = bcmasp_get_ethtool_stats,
  412. .get_sset_count = bcmasp_get_sset_count,
  413. };