1 // SPDX-License-Identifier: GPL-2.0
3 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
5 // Copyright (c) 2021, 2022 Pengutronix,
6 // Marc Kleine-Budde <kernel@pengutronix.de>
9 #include "mcp251xfd-ram.h"
11 static inline u8
can_ram_clamp(const struct can_ram_config
*config
,
12 const struct can_ram_obj_config
*obj
,
17 max
= min_t(u8
, obj
->max
, obj
->fifo_num
* config
->fifo_depth
);
18 return clamp(val
, obj
->min
, max
);
22 can_ram_rounddown_pow_of_two(const struct can_ram_config
*config
,
23 const struct can_ram_obj_config
*obj
,
24 const u8 coalesce
, u8 val
)
26 u8 fifo_num
= obj
->fifo_num
;
29 val
= can_ram_clamp(config
, obj
, val
);
32 /* Use 1st FIFO for coalescing, if requested.
34 * Either use complete FIFO (and FIFO Full IRQ) for
35 * coalescing or only half of FIFO (FIFO Half Full
36 * IRQ) and use remaining half for normal objects.
38 ret
= min_t(u8
, coalesce
* 2, config
->fifo_depth
);
43 for (i
= 0; i
< fifo_num
&& val
; i
++) {
46 n
= min_t(u8
, rounddown_pow_of_two(val
),
49 /* skip small FIFOs */
50 if (n
< obj
->fifo_depth_min
)
60 void can_ram_get_layout(struct can_ram_layout
*layout
,
61 const struct can_ram_config
*config
,
62 const struct ethtool_ringparam
*ring
,
63 const struct ethtool_coalesce
*ec
,
71 num_tx
= config
->tx
.def
[fd_mode
];
72 num_tx
= can_ram_rounddown_pow_of_two(config
, &config
->tx
, 0, num_tx
);
74 ram_free
= config
->size
;
75 ram_free
-= config
->tx
.size
[fd_mode
] * num_tx
;
77 num_rx
= ram_free
/ config
->rx
.size
[fd_mode
];
79 layout
->default_rx
= can_ram_rounddown_pow_of_two(config
, &config
->rx
, 0, num_rx
);
80 layout
->default_tx
= num_tx
;
84 ram_free
= config
->size
;
85 ram_free
-= config
->tx
.size
[fd_mode
] * config
->tx
.min
;
86 num_rx
= ram_free
/ config
->rx
.size
[fd_mode
];
88 ram_free
= config
->size
;
89 ram_free
-= config
->rx
.size
[fd_mode
] * config
->rx
.min
;
90 num_tx
= ram_free
/ config
->tx
.size
[fd_mode
];
92 layout
->max_rx
= can_ram_rounddown_pow_of_two(config
, &config
->rx
, 0, num_rx
);
93 layout
->max_tx
= can_ram_rounddown_pow_of_two(config
, &config
->tx
, 0, num_tx
);
98 u8 num_rx_coalesce
= 0, num_tx_coalesce
= 0;
100 /* If the ring parameters have been configured in
101 * CAN-CC mode, but and we are in CAN-FD mode now,
102 * they might be to big. Use the default CAN-FD values
105 num_rx
= ring
->rx_pending
;
106 if (num_rx
> layout
->max_rx
)
107 num_rx
= layout
->default_rx
;
109 num_rx
= can_ram_rounddown_pow_of_two(config
, &config
->rx
, 0, num_rx
);
111 /* The ethtool doc says:
112 * To disable coalescing, set usecs = 0 and max_frames = 1.
114 if (ec
&& !(ec
->rx_coalesce_usecs_irq
== 0 &&
115 ec
->rx_max_coalesced_frames_irq
== 1)) {
118 /* use only max half of available objects for coalescing */
119 max
= min_t(u8
, num_rx
/ 2, config
->fifo_depth
);
120 num_rx_coalesce
= clamp(ec
->rx_max_coalesced_frames_irq
,
121 (u32
)config
->rx
.fifo_depth_coalesce_min
,
123 num_rx_coalesce
= rounddown_pow_of_two(num_rx_coalesce
);
125 num_rx
= can_ram_rounddown_pow_of_two(config
, &config
->rx
,
126 num_rx_coalesce
, num_rx
);
129 ram_free
= config
->size
- config
->rx
.size
[fd_mode
] * num_rx
;
130 num_tx
= ram_free
/ config
->tx
.size
[fd_mode
];
131 num_tx
= min_t(u8
, ring
->tx_pending
, num_tx
);
132 num_tx
= can_ram_rounddown_pow_of_two(config
, &config
->tx
, 0, num_tx
);
134 /* The ethtool doc says:
135 * To disable coalescing, set usecs = 0 and max_frames = 1.
137 if (ec
&& !(ec
->tx_coalesce_usecs_irq
== 0 &&
138 ec
->tx_max_coalesced_frames_irq
== 1)) {
141 /* use only max half of available objects for coalescing */
142 max
= min_t(u8
, num_tx
/ 2, config
->fifo_depth
);
143 num_tx_coalesce
= clamp(ec
->tx_max_coalesced_frames_irq
,
144 (u32
)config
->tx
.fifo_depth_coalesce_min
,
146 num_tx_coalesce
= rounddown_pow_of_two(num_tx_coalesce
);
148 num_tx
= can_ram_rounddown_pow_of_two(config
, &config
->tx
,
149 num_tx_coalesce
, num_tx
);
152 layout
->cur_rx
= num_rx
;
153 layout
->cur_tx
= num_tx
;
154 layout
->rx_coalesce
= num_rx_coalesce
;
155 layout
->tx_coalesce
= num_tx_coalesce
;
157 layout
->cur_rx
= layout
->default_rx
;
158 layout
->cur_tx
= layout
->default_tx
;
159 layout
->rx_coalesce
= 0;
160 layout
->tx_coalesce
= 0;