mcp251xfd-ethtool.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
  4. //
  5. // Copyright (c) 2021, 2022 Pengutronix,
  6. // Marc Kleine-Budde <[email protected]>
  7. //
  8. #include <linux/ethtool.h>
  9. #include "mcp251xfd.h"
  10. #include "mcp251xfd-ram.h"
  11. static void
  12. mcp251xfd_ring_get_ringparam(struct net_device *ndev,
  13. struct ethtool_ringparam *ring,
  14. struct kernel_ethtool_ringparam *kernel_ring,
  15. struct netlink_ext_ack *extack)
  16. {
  17. const struct mcp251xfd_priv *priv = netdev_priv(ndev);
  18. const bool fd_mode = mcp251xfd_is_fd_mode(priv);
  19. struct can_ram_layout layout;
  20. can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode);
  21. ring->rx_max_pending = layout.max_rx;
  22. ring->tx_max_pending = layout.max_tx;
  23. ring->rx_pending = priv->rx_obj_num;
  24. ring->tx_pending = priv->tx->obj_num;
  25. }
  26. static int
  27. mcp251xfd_ring_set_ringparam(struct net_device *ndev,
  28. struct ethtool_ringparam *ring,
  29. struct kernel_ethtool_ringparam *kernel_ring,
  30. struct netlink_ext_ack *extack)
  31. {
  32. struct mcp251xfd_priv *priv = netdev_priv(ndev);
  33. const bool fd_mode = mcp251xfd_is_fd_mode(priv);
  34. struct can_ram_layout layout;
  35. can_ram_get_layout(&layout, &mcp251xfd_ram_config, ring, NULL, fd_mode);
  36. if ((layout.cur_rx != priv->rx_obj_num ||
  37. layout.cur_tx != priv->tx->obj_num) &&
  38. netif_running(ndev))
  39. return -EBUSY;
  40. priv->rx_obj_num = layout.cur_rx;
  41. priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
  42. priv->tx->obj_num = layout.cur_tx;
  43. priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;
  44. return 0;
  45. }
  46. static int mcp251xfd_ring_get_coalesce(struct net_device *ndev,
  47. struct ethtool_coalesce *ec,
  48. struct kernel_ethtool_coalesce *kec,
  49. struct netlink_ext_ack *ext_ack)
  50. {
  51. struct mcp251xfd_priv *priv = netdev_priv(ndev);
  52. u32 rx_max_frames, tx_max_frames;
  53. /* The ethtool doc says:
  54. * To disable coalescing, set usecs = 0 and max_frames = 1.
  55. */
  56. if (priv->rx_obj_num_coalesce_irq == 0)
  57. rx_max_frames = 1;
  58. else
  59. rx_max_frames = priv->rx_obj_num_coalesce_irq;
  60. ec->rx_max_coalesced_frames_irq = rx_max_frames;
  61. ec->rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq;
  62. if (priv->tx_obj_num_coalesce_irq == 0)
  63. tx_max_frames = 1;
  64. else
  65. tx_max_frames = priv->tx_obj_num_coalesce_irq;
  66. ec->tx_max_coalesced_frames_irq = tx_max_frames;
  67. ec->tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq;
  68. return 0;
  69. }
  70. static int mcp251xfd_ring_set_coalesce(struct net_device *ndev,
  71. struct ethtool_coalesce *ec,
  72. struct kernel_ethtool_coalesce *kec,
  73. struct netlink_ext_ack *ext_ack)
  74. {
  75. struct mcp251xfd_priv *priv = netdev_priv(ndev);
  76. const bool fd_mode = mcp251xfd_is_fd_mode(priv);
  77. const struct ethtool_ringparam ring = {
  78. .rx_pending = priv->rx_obj_num,
  79. .tx_pending = priv->tx->obj_num,
  80. };
  81. struct can_ram_layout layout;
  82. can_ram_get_layout(&layout, &mcp251xfd_ram_config, &ring, ec, fd_mode);
  83. if ((layout.rx_coalesce != priv->rx_obj_num_coalesce_irq ||
  84. ec->rx_coalesce_usecs_irq != priv->rx_coalesce_usecs_irq ||
  85. layout.tx_coalesce != priv->tx_obj_num_coalesce_irq ||
  86. ec->tx_coalesce_usecs_irq != priv->tx_coalesce_usecs_irq) &&
  87. netif_running(ndev))
  88. return -EBUSY;
  89. priv->rx_obj_num = layout.cur_rx;
  90. priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
  91. priv->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq;
  92. priv->tx->obj_num = layout.cur_tx;
  93. priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;
  94. priv->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq;
  95. return 0;
  96. }
  97. static const struct ethtool_ops mcp251xfd_ethtool_ops = {
  98. .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ |
  99. ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ |
  100. ETHTOOL_COALESCE_TX_USECS_IRQ |
  101. ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
  102. .get_ringparam = mcp251xfd_ring_get_ringparam,
  103. .set_ringparam = mcp251xfd_ring_set_ringparam,
  104. .get_coalesce = mcp251xfd_ring_get_coalesce,
  105. .set_coalesce = mcp251xfd_ring_set_coalesce,
  106. .get_ts_info = can_ethtool_op_get_ts_info_hwts,
  107. };
  108. void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv)
  109. {
  110. struct can_ram_layout layout;
  111. priv->ndev->ethtool_ops = &mcp251xfd_ethtool_ops;
  112. can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, false);
  113. priv->rx_obj_num = layout.default_rx;
  114. priv->tx->obj_num = layout.default_tx;
  115. priv->rx_obj_num_coalesce_irq = 0;
  116. priv->tx_obj_num_coalesce_irq = 0;
  117. priv->rx_coalesce_usecs_irq = 0;
  118. priv->tx_coalesce_usecs_irq = 0;
  119. }