ocelot_stats.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /* Statistics for Ocelot switch family
  3. *
  4. * Copyright (c) 2017 Microsemi Corporation
  5. * Copyright 2022 NXP
  6. */
  7. #include <linux/spinlock.h>
  8. #include <linux/mutex.h>
  9. #include <linux/workqueue.h>
  10. #include "ocelot.h"
  11. /* Read the counters from hardware and keep them in region->buf.
  12. * Caller must hold &ocelot->stat_view_lock.
  13. */
  14. static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
  15. {
  16. struct ocelot_stats_region *region;
  17. int err;
  18. /* Configure the port to read the stats from */
  19. ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
  20. list_for_each_entry(region, &ocelot->stats_regions, node) {
  21. err = ocelot_bulk_read(ocelot, region->base, region->buf,
  22. region->count);
  23. if (err)
  24. return err;
  25. }
  26. return 0;
  27. }
  28. /* Transfer the counters from region->buf to ocelot->stats.
  29. * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
  30. */
  31. static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
  32. {
  33. unsigned int idx = port * OCELOT_NUM_STATS;
  34. struct ocelot_stats_region *region;
  35. int j;
  36. list_for_each_entry(region, &ocelot->stats_regions, node) {
  37. for (j = 0; j < region->count; j++) {
  38. u64 *stat = &ocelot->stats[idx + j];
  39. u64 val = region->buf[j];
  40. if (val < (*stat & U32_MAX))
  41. *stat += (u64)1 << 32;
  42. *stat = (*stat & ~(u64)U32_MAX) + val;
  43. }
  44. idx += region->count;
  45. }
  46. }
  47. static void ocelot_check_stats_work(struct work_struct *work)
  48. {
  49. struct delayed_work *del_work = to_delayed_work(work);
  50. struct ocelot *ocelot = container_of(del_work, struct ocelot,
  51. stats_work);
  52. int port, err;
  53. mutex_lock(&ocelot->stat_view_lock);
  54. for (port = 0; port < ocelot->num_phys_ports; port++) {
  55. err = ocelot_port_update_stats(ocelot, port);
  56. if (err)
  57. break;
  58. spin_lock(&ocelot->stats_lock);
  59. ocelot_port_transfer_stats(ocelot, port);
  60. spin_unlock(&ocelot->stats_lock);
  61. }
  62. if (!err && ocelot->ops->update_stats)
  63. ocelot->ops->update_stats(ocelot);
  64. mutex_unlock(&ocelot->stat_view_lock);
  65. if (err)
  66. dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
  67. queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
  68. OCELOT_STATS_CHECK_DELAY);
  69. }
  70. void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
  71. {
  72. int i;
  73. if (sset != ETH_SS_STATS)
  74. return;
  75. for (i = 0; i < OCELOT_NUM_STATS; i++) {
  76. if (ocelot->stats_layout[i].name[0] == '\0')
  77. continue;
  78. memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name,
  79. ETH_GSTRING_LEN);
  80. }
  81. }
  82. EXPORT_SYMBOL(ocelot_get_strings);
  83. /* Update ocelot->stats for the given port and run the given callback */
  84. static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
  85. void (*cb)(struct ocelot *ocelot, int port,
  86. void *priv))
  87. {
  88. int err;
  89. mutex_lock(&ocelot->stat_view_lock);
  90. err = ocelot_port_update_stats(ocelot, port);
  91. if (err) {
  92. dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
  93. port, ERR_PTR(err));
  94. goto out_unlock;
  95. }
  96. spin_lock(&ocelot->stats_lock);
  97. ocelot_port_transfer_stats(ocelot, port);
  98. cb(ocelot, port, priv);
  99. spin_unlock(&ocelot->stats_lock);
  100. out_unlock:
  101. mutex_unlock(&ocelot->stat_view_lock);
  102. }
  103. int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
  104. {
  105. int i, num_stats = 0;
  106. if (sset != ETH_SS_STATS)
  107. return -EOPNOTSUPP;
  108. for (i = 0; i < OCELOT_NUM_STATS; i++)
  109. if (ocelot->stats_layout[i].name[0] != '\0')
  110. num_stats++;
  111. return num_stats;
  112. }
  113. EXPORT_SYMBOL(ocelot_get_sset_count);
  114. static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
  115. void *priv)
  116. {
  117. u64 *data = priv;
  118. int i;
  119. /* Copy all supported counters */
  120. for (i = 0; i < OCELOT_NUM_STATS; i++) {
  121. int index = port * OCELOT_NUM_STATS + i;
  122. if (ocelot->stats_layout[i].name[0] == '\0')
  123. continue;
  124. *data++ = ocelot->stats[index];
  125. }
  126. }
  127. void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
  128. {
  129. ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
  130. }
  131. EXPORT_SYMBOL(ocelot_get_ethtool_stats);
  132. static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
  133. {
  134. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  135. struct ethtool_pause_stats *pause_stats = priv;
  136. pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
  137. pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
  138. }
  139. void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
  140. struct ethtool_pause_stats *pause_stats)
  141. {
  142. ocelot_port_stats_run(ocelot, port, pause_stats,
  143. ocelot_port_pause_stats_cb);
  144. }
  145. EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
  146. static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
  147. { 64, 64 },
  148. { 65, 127 },
  149. { 128, 255 },
  150. { 256, 511 },
  151. { 512, 1023 },
  152. { 1024, 1526 },
  153. { 1527, 65535 },
  154. {},
  155. };
  156. static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
  157. {
  158. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  159. struct ethtool_rmon_stats *rmon_stats = priv;
  160. rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
  161. rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
  162. rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
  163. rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
  164. rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
  165. rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
  166. rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
  167. rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
  168. rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
  169. rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
  170. rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
  171. rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
  172. rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
  173. rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
  174. rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_128_255];
  175. rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_256_511];
  176. rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_512_1023];
  177. rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1024_1526];
  178. }
  179. void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
  180. struct ethtool_rmon_stats *rmon_stats,
  181. const struct ethtool_rmon_hist_range **ranges)
  182. {
  183. *ranges = ocelot_rmon_ranges;
  184. ocelot_port_stats_run(ocelot, port, rmon_stats,
  185. ocelot_port_rmon_stats_cb);
  186. }
  187. EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
  188. static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
  189. {
  190. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  191. struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
  192. ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
  193. }
  194. void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
  195. struct ethtool_eth_ctrl_stats *ctrl_stats)
  196. {
  197. ocelot_port_stats_run(ocelot, port, ctrl_stats,
  198. ocelot_port_ctrl_stats_cb);
  199. }
  200. EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
  201. static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
  202. {
  203. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  204. struct ethtool_eth_mac_stats *mac_stats = priv;
  205. mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
  206. mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
  207. s[OCELOT_STAT_TX_65_127] +
  208. s[OCELOT_STAT_TX_128_255] +
  209. s[OCELOT_STAT_TX_256_511] +
  210. s[OCELOT_STAT_TX_512_1023] +
  211. s[OCELOT_STAT_TX_1024_1526] +
  212. s[OCELOT_STAT_TX_1527_MAX];
  213. mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
  214. mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
  215. s[OCELOT_STAT_RX_GREEN_PRIO_1] +
  216. s[OCELOT_STAT_RX_GREEN_PRIO_2] +
  217. s[OCELOT_STAT_RX_GREEN_PRIO_3] +
  218. s[OCELOT_STAT_RX_GREEN_PRIO_4] +
  219. s[OCELOT_STAT_RX_GREEN_PRIO_5] +
  220. s[OCELOT_STAT_RX_GREEN_PRIO_6] +
  221. s[OCELOT_STAT_RX_GREEN_PRIO_7] +
  222. s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
  223. s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
  224. s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
  225. s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
  226. s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
  227. s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
  228. s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
  229. s[OCELOT_STAT_RX_YELLOW_PRIO_7];
  230. mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
  231. mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
  232. mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
  233. mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
  234. mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
  235. /* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
  236. * counted individually.
  237. */
  238. mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
  239. mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
  240. }
  241. void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
  242. struct ethtool_eth_mac_stats *mac_stats)
  243. {
  244. ocelot_port_stats_run(ocelot, port, mac_stats,
  245. ocelot_port_mac_stats_cb);
  246. }
  247. EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
  248. static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
  249. {
  250. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  251. struct ethtool_eth_phy_stats *phy_stats = priv;
  252. phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
  253. }
  254. void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
  255. struct ethtool_eth_phy_stats *phy_stats)
  256. {
  257. ocelot_port_stats_run(ocelot, port, phy_stats,
  258. ocelot_port_phy_stats_cb);
  259. }
  260. EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
  261. void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
  262. struct rtnl_link_stats64 *stats)
  263. {
  264. u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
  265. spin_lock(&ocelot->stats_lock);
  266. /* Get Rx stats */
  267. stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
  268. stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
  269. s[OCELOT_STAT_RX_FRAGMENTS] +
  270. s[OCELOT_STAT_RX_JABBERS] +
  271. s[OCELOT_STAT_RX_LONGS] +
  272. s[OCELOT_STAT_RX_64] +
  273. s[OCELOT_STAT_RX_65_127] +
  274. s[OCELOT_STAT_RX_128_255] +
  275. s[OCELOT_STAT_RX_256_511] +
  276. s[OCELOT_STAT_RX_512_1023] +
  277. s[OCELOT_STAT_RX_1024_1526] +
  278. s[OCELOT_STAT_RX_1527_MAX];
  279. stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
  280. stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
  281. stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
  282. s[OCELOT_STAT_RX_RED_PRIO_1] +
  283. s[OCELOT_STAT_RX_RED_PRIO_2] +
  284. s[OCELOT_STAT_RX_RED_PRIO_3] +
  285. s[OCELOT_STAT_RX_RED_PRIO_4] +
  286. s[OCELOT_STAT_RX_RED_PRIO_5] +
  287. s[OCELOT_STAT_RX_RED_PRIO_6] +
  288. s[OCELOT_STAT_RX_RED_PRIO_7] +
  289. s[OCELOT_STAT_DROP_LOCAL] +
  290. s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
  291. s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
  292. s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
  293. s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
  294. s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
  295. s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
  296. s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
  297. s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
  298. s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
  299. s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
  300. s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
  301. s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
  302. s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
  303. s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
  304. s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
  305. s[OCELOT_STAT_DROP_GREEN_PRIO_7];
  306. /* Get Tx stats */
  307. stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
  308. stats->tx_packets = s[OCELOT_STAT_TX_64] +
  309. s[OCELOT_STAT_TX_65_127] +
  310. s[OCELOT_STAT_TX_128_255] +
  311. s[OCELOT_STAT_TX_256_511] +
  312. s[OCELOT_STAT_TX_512_1023] +
  313. s[OCELOT_STAT_TX_1024_1526] +
  314. s[OCELOT_STAT_TX_1527_MAX];
  315. stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
  316. s[OCELOT_STAT_TX_AGED];
  317. stats->collisions = s[OCELOT_STAT_TX_COLLISION];
  318. spin_unlock(&ocelot->stats_lock);
  319. }
  320. EXPORT_SYMBOL(ocelot_port_get_stats64);
  321. static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
  322. {
  323. struct ocelot_stats_region *region = NULL;
  324. unsigned int last;
  325. int i;
  326. INIT_LIST_HEAD(&ocelot->stats_regions);
  327. for (i = 0; i < OCELOT_NUM_STATS; i++) {
  328. if (!ocelot->stats_layout[i].reg)
  329. continue;
  330. if (region && ocelot->map[SYS][ocelot->stats_layout[i].reg & REG_MASK] ==
  331. ocelot->map[SYS][last & REG_MASK] + 4) {
  332. region->count++;
  333. } else {
  334. region = devm_kzalloc(ocelot->dev, sizeof(*region),
  335. GFP_KERNEL);
  336. if (!region)
  337. return -ENOMEM;
  338. region->base = ocelot->stats_layout[i].reg;
  339. region->count = 1;
  340. list_add_tail(&region->node, &ocelot->stats_regions);
  341. }
  342. last = ocelot->stats_layout[i].reg;
  343. }
  344. list_for_each_entry(region, &ocelot->stats_regions, node) {
  345. region->buf = devm_kcalloc(ocelot->dev, region->count,
  346. sizeof(*region->buf), GFP_KERNEL);
  347. if (!region->buf)
  348. return -ENOMEM;
  349. }
  350. return 0;
  351. }
  352. int ocelot_stats_init(struct ocelot *ocelot)
  353. {
  354. char queue_name[32];
  355. int ret;
  356. ocelot->stats = devm_kcalloc(ocelot->dev,
  357. ocelot->num_phys_ports * OCELOT_NUM_STATS,
  358. sizeof(u64), GFP_KERNEL);
  359. if (!ocelot->stats)
  360. return -ENOMEM;
  361. snprintf(queue_name, sizeof(queue_name), "%s-stats",
  362. dev_name(ocelot->dev));
  363. ocelot->stats_queue = create_singlethread_workqueue(queue_name);
  364. if (!ocelot->stats_queue)
  365. return -ENOMEM;
  366. spin_lock_init(&ocelot->stats_lock);
  367. mutex_init(&ocelot->stat_view_lock);
  368. ret = ocelot_prepare_stats_regions(ocelot);
  369. if (ret) {
  370. destroy_workqueue(ocelot->stats_queue);
  371. return ret;
  372. }
  373. INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
  374. queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
  375. OCELOT_STATS_CHECK_DELAY);
  376. return 0;
  377. }
  378. void ocelot_stats_deinit(struct ocelot *ocelot)
  379. {
  380. cancel_delayed_work(&ocelot->stats_work);
  381. destroy_workqueue(ocelot->stats_queue);
  382. }