mcp251xfd-ram.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 "mcp251xfd-ram.h"
  9. static inline u8 can_ram_clamp(const struct can_ram_config *config,
  10. const struct can_ram_obj_config *obj,
  11. u8 val)
  12. {
  13. u8 max;
  14. max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
  15. return clamp(val, obj->min, max);
  16. }
  17. static u8
  18. can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
  19. const struct can_ram_obj_config *obj,
  20. const u8 coalesce, u8 val)
  21. {
  22. u8 fifo_num = obj->fifo_num;
  23. u8 ret = 0, i;
  24. val = can_ram_clamp(config, obj, val);
  25. if (coalesce) {
  26. /* Use 1st FIFO for coalescing, if requested.
  27. *
  28. * Either use complete FIFO (and FIFO Full IRQ) for
  29. * coalescing or only half of FIFO (FIFO Half Full
  30. * IRQ) and use remaining half for normal objects.
  31. */
  32. ret = min_t(u8, coalesce * 2, config->fifo_depth);
  33. val -= ret;
  34. fifo_num--;
  35. }
  36. for (i = 0; i < fifo_num && val; i++) {
  37. u8 n;
  38. n = min_t(u8, rounddown_pow_of_two(val),
  39. config->fifo_depth);
  40. /* skip small FIFOs */
  41. if (n < obj->fifo_depth_min)
  42. return ret;
  43. ret += n;
  44. val -= n;
  45. }
  46. return ret;
  47. }
  48. void can_ram_get_layout(struct can_ram_layout *layout,
  49. const struct can_ram_config *config,
  50. const struct ethtool_ringparam *ring,
  51. const struct ethtool_coalesce *ec,
  52. const bool fd_mode)
  53. {
  54. u8 num_rx, num_tx;
  55. u16 ram_free;
  56. /* default CAN */
  57. num_tx = config->tx.def[fd_mode];
  58. num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
  59. ram_free = config->size;
  60. ram_free -= config->tx.size[fd_mode] * num_tx;
  61. num_rx = ram_free / config->rx.size[fd_mode];
  62. layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
  63. layout->default_tx = num_tx;
  64. /* MAX CAN */
  65. ram_free = config->size;
  66. ram_free -= config->tx.size[fd_mode] * config->tx.min;
  67. num_rx = ram_free / config->rx.size[fd_mode];
  68. ram_free = config->size;
  69. ram_free -= config->rx.size[fd_mode] * config->rx.min;
  70. num_tx = ram_free / config->tx.size[fd_mode];
  71. layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
  72. layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
  73. /* cur CAN */
  74. if (ring) {
  75. u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
  76. num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
  77. /* The ethtool doc says:
  78. * To disable coalescing, set usecs = 0 and max_frames = 1.
  79. */
  80. if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
  81. ec->rx_max_coalesced_frames_irq == 1)) {
  82. u8 max;
  83. /* use only max half of available objects for coalescing */
  84. max = min_t(u8, num_rx / 2, config->fifo_depth);
  85. num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
  86. (u32)config->rx.fifo_depth_coalesce_min,
  87. (u32)max);
  88. num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
  89. num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
  90. num_rx_coalesce, num_rx);
  91. }
  92. ram_free = config->size - config->rx.size[fd_mode] * num_rx;
  93. num_tx = ram_free / config->tx.size[fd_mode];
  94. num_tx = min_t(u8, ring->tx_pending, num_tx);
  95. num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
  96. /* The ethtool doc says:
  97. * To disable coalescing, set usecs = 0 and max_frames = 1.
  98. */
  99. if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
  100. ec->tx_max_coalesced_frames_irq == 1)) {
  101. u8 max;
  102. /* use only max half of available objects for coalescing */
  103. max = min_t(u8, num_tx / 2, config->fifo_depth);
  104. num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
  105. (u32)config->tx.fifo_depth_coalesce_min,
  106. (u32)max);
  107. num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
  108. num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
  109. num_tx_coalesce, num_tx);
  110. }
  111. layout->cur_rx = num_rx;
  112. layout->cur_tx = num_tx;
  113. layout->rx_coalesce = num_rx_coalesce;
  114. layout->tx_coalesce = num_tx_coalesce;
  115. } else {
  116. layout->cur_rx = layout->default_rx;
  117. layout->cur_tx = layout->default_tx;
  118. layout->rx_coalesce = 0;
  119. layout->tx_coalesce = 0;
  120. }
  121. }