Commit | Line | Data |
---|---|---|
56ade8fe JP |
1 | /* |
2 | * drivers/net/ethernet/mellanox/mlxsw/spectrum.h | |
3 | * Copyright (c) 2015 Mellanox Technologies. All rights reserved. | |
4 | * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com> | |
5 | * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com> | |
6 | * Copyright (c) 2015 Elad Raz <eladr@mellanox.com> | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions are met: | |
10 | * | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. Neither the names of the copyright holders nor the names of its | |
17 | * contributors may be used to endorse or promote products derived from | |
18 | * this software without specific prior written permission. | |
19 | * | |
20 | * Alternatively, this software may be distributed under the terms of the | |
21 | * GNU General Public License ("GPL") version 2 as published by the Free | |
22 | * Software Foundation. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
34 | * POSSIBILITY OF SUCH DAMAGE. | |
35 | */ | |
36 | ||
37 | #ifndef _MLXSW_SPECTRUM_H | |
38 | #define _MLXSW_SPECTRUM_H | |
39 | ||
40 | #include <linux/types.h> | |
41 | #include <linux/netdevice.h> | |
42 | #include <linux/bitops.h> | |
43 | #include <linux/if_vlan.h> | |
7f71eb46 | 44 | #include <linux/list.h> |
8e8dfe9f | 45 | #include <linux/dcbnl.h> |
56ade8fe JP |
46 | #include <net/switchdev.h> |
47 | ||
3a49b4fd | 48 | #include "port.h" |
56ade8fe JP |
49 | #include "core.h" |
50 | ||
51 | #define MLXSW_SP_VFID_BASE VLAN_N_VID | |
7f71eb46 | 52 | #define MLXSW_SP_VFID_PORT_MAX 512 /* Non-bridged VLAN interfaces */ |
b555cf4a | 53 | #define MLXSW_SP_VFID_BR_MAX 6144 /* Bridged VLAN interfaces */ |
7f71eb46 IS |
54 | #define MLXSW_SP_VFID_MAX (MLXSW_SP_VFID_PORT_MAX + MLXSW_SP_VFID_BR_MAX) |
55 | ||
0d65fc13 JP |
56 | #define MLXSW_SP_LAG_MAX 64 |
57 | #define MLXSW_SP_PORT_PER_LAG_MAX 16 | |
56ade8fe | 58 | |
53ae6283 ER |
59 | #define MLXSW_SP_MID_MAX 7000 |
60 | ||
18f1e70c IS |
61 | #define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4 |
62 | ||
63 | #define MLXSW_SP_PORT_BASE_SPEED 25000 /* Mb/s */ | |
64 | ||
1a198449 IS |
65 | #define MLXSW_SP_BYTES_PER_CELL 96 |
66 | ||
67 | #define MLXSW_SP_BYTES_TO_CELLS(b) DIV_ROUND_UP(b, MLXSW_SP_BYTES_PER_CELL) | |
0f433fa0 | 68 | #define MLXSW_SP_CELLS_TO_BYTES(c) (c * MLXSW_SP_BYTES_PER_CELL) |
1a198449 | 69 | |
9f7ec052 IS |
70 | /* Maximum delay buffer needed in case of PAUSE frames, in cells. |
71 | * Assumes 100m cable and maximum MTU. | |
72 | */ | |
73 | #define MLXSW_SP_PAUSE_DELAY 612 | |
74 | ||
d81a6bdb IS |
75 | #define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */ |
76 | ||
77 | static inline u16 mlxsw_sp_pfc_delay_get(int mtu, u16 delay) | |
78 | { | |
79 | delay = MLXSW_SP_BYTES_TO_CELLS(DIV_ROUND_UP(delay, BITS_PER_BYTE)); | |
80 | return MLXSW_SP_CELL_FACTOR * delay + MLXSW_SP_BYTES_TO_CELLS(mtu); | |
81 | } | |
82 | ||
56ade8fe JP |
83 | struct mlxsw_sp_port; |
84 | ||
0d65fc13 JP |
85 | struct mlxsw_sp_upper { |
86 | struct net_device *dev; | |
87 | unsigned int ref_count; | |
88 | }; | |
89 | ||
7f71eb46 IS |
90 | struct mlxsw_sp_vfid { |
91 | struct list_head list; | |
92 | u16 nr_vports; | |
93 | u16 vfid; /* Starting at 0 */ | |
26f0e7fb | 94 | struct net_device *br_dev; |
7f71eb46 IS |
95 | u16 vid; |
96 | }; | |
97 | ||
3a49b4fd ER |
98 | struct mlxsw_sp_mid { |
99 | struct list_head list; | |
100 | unsigned char addr[ETH_ALEN]; | |
101 | u16 vid; | |
102 | u16 mid; | |
103 | unsigned int ref_count; | |
104 | }; | |
105 | ||
7f71eb46 IS |
106 | static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid) |
107 | { | |
108 | return MLXSW_SP_VFID_BASE + vfid; | |
109 | } | |
110 | ||
aac78a44 IS |
111 | static inline u16 mlxsw_sp_fid_to_vfid(u16 fid) |
112 | { | |
113 | return fid - MLXSW_SP_VFID_BASE; | |
114 | } | |
115 | ||
116 | static inline bool mlxsw_sp_fid_is_vfid(u16 fid) | |
117 | { | |
118 | return fid >= MLXSW_SP_VFID_BASE; | |
119 | } | |
120 | ||
078f9c71 JP |
121 | struct mlxsw_sp_sb_pr { |
122 | enum mlxsw_reg_sbpr_mode mode; | |
123 | u32 size; | |
124 | }; | |
125 | ||
2d0ed39f JP |
126 | struct mlxsw_cp_sb_occ { |
127 | u32 cur; | |
128 | u32 max; | |
129 | }; | |
130 | ||
078f9c71 JP |
131 | struct mlxsw_sp_sb_cm { |
132 | u32 min_buff; | |
133 | u32 max_buff; | |
134 | u8 pool; | |
2d0ed39f | 135 | struct mlxsw_cp_sb_occ occ; |
078f9c71 JP |
136 | }; |
137 | ||
138 | struct mlxsw_sp_sb_pm { | |
139 | u32 min_buff; | |
140 | u32 max_buff; | |
2d0ed39f | 141 | struct mlxsw_cp_sb_occ occ; |
078f9c71 JP |
142 | }; |
143 | ||
144 | #define MLXSW_SP_SB_POOL_COUNT 4 | |
145 | #define MLXSW_SP_SB_TC_COUNT 8 | |
146 | ||
147 | struct mlxsw_sp_sb { | |
148 | struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; | |
149 | struct { | |
150 | struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; | |
151 | struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; | |
152 | } ports[MLXSW_PORT_MAX_PORTS]; | |
153 | }; | |
154 | ||
56ade8fe | 155 | struct mlxsw_sp { |
7f71eb46 IS |
156 | struct { |
157 | struct list_head list; | |
158 | unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_PORT_MAX)]; | |
159 | } port_vfids; | |
26f0e7fb IS |
160 | struct { |
161 | struct list_head list; | |
162 | unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_BR_MAX)]; | |
163 | } br_vfids; | |
3a49b4fd ER |
164 | struct { |
165 | struct list_head list; | |
166 | unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_MID_MAX)]; | |
167 | } br_mids; | |
56ade8fe JP |
168 | unsigned long active_fids[BITS_TO_LONGS(VLAN_N_VID)]; |
169 | struct mlxsw_sp_port **ports; | |
170 | struct mlxsw_core *core; | |
171 | const struct mlxsw_bus_info *bus_info; | |
172 | unsigned char base_mac[ETH_ALEN]; | |
173 | struct { | |
174 | struct delayed_work dw; | |
175 | #define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100 | |
176 | unsigned int interval; /* ms */ | |
177 | } fdb_notify; | |
869f63a4 IS |
178 | #define MLXSW_SP_MIN_AGEING_TIME 10 |
179 | #define MLXSW_SP_MAX_AGEING_TIME 1000000 | |
56ade8fe JP |
180 | #define MLXSW_SP_DEFAULT_AGEING_TIME 300 |
181 | u32 ageing_time; | |
0d65fc13 JP |
182 | struct mlxsw_sp_upper master_bridge; |
183 | struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX]; | |
558c2d5e | 184 | u8 port_to_module[MLXSW_PORT_MAX_PORTS]; |
078f9c71 | 185 | struct mlxsw_sp_sb sb; |
56ade8fe JP |
186 | }; |
187 | ||
0d65fc13 JP |
188 | static inline struct mlxsw_sp_upper * |
189 | mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) | |
190 | { | |
191 | return &mlxsw_sp->lags[lag_id]; | |
192 | } | |
193 | ||
56ade8fe JP |
194 | struct mlxsw_sp_port_pcpu_stats { |
195 | u64 rx_packets; | |
196 | u64 rx_bytes; | |
197 | u64 tx_packets; | |
198 | u64 tx_bytes; | |
199 | struct u64_stats_sync syncp; | |
200 | u32 tx_dropped; | |
201 | }; | |
202 | ||
203 | struct mlxsw_sp_port { | |
932762b6 | 204 | struct mlxsw_core_port core_port; /* must be first */ |
56ade8fe JP |
205 | struct net_device *dev; |
206 | struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats; | |
207 | struct mlxsw_sp *mlxsw_sp; | |
208 | u8 local_port; | |
209 | u8 stp_state; | |
0d9b970c JP |
210 | u8 learning:1, |
211 | learning_sync:1, | |
0293038e | 212 | uc_flood:1, |
0d65fc13 | 213 | bridged:1, |
18f1e70c IS |
214 | lagged:1, |
215 | split:1; | |
56ade8fe | 216 | u16 pvid; |
0d65fc13 | 217 | u16 lag_id; |
7f71eb46 IS |
218 | struct { |
219 | struct list_head list; | |
220 | struct mlxsw_sp_vfid *vfid; | |
221 | u16 vid; | |
222 | } vport; | |
9f7ec052 IS |
223 | struct { |
224 | u8 tx_pause:1, | |
225 | rx_pause:1; | |
226 | } link; | |
8e8dfe9f IS |
227 | struct { |
228 | struct ieee_ets *ets; | |
cc7cf517 | 229 | struct ieee_maxrate *maxrate; |
d81a6bdb | 230 | struct ieee_pfc *pfc; |
8e8dfe9f | 231 | } dcb; |
d664b41e IS |
232 | struct { |
233 | u8 module; | |
234 | u8 width; | |
235 | u8 lane; | |
236 | } mapping; | |
56ade8fe | 237 | /* 802.1Q bridge VLANs */ |
bd40e9d6 | 238 | unsigned long *active_vlans; |
fc1273af | 239 | unsigned long *untagged_vlans; |
56ade8fe | 240 | /* VLAN interfaces */ |
7f71eb46 | 241 | struct list_head vports_list; |
56ade8fe JP |
242 | }; |
243 | ||
9f7ec052 IS |
244 | static inline bool |
245 | mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) | |
246 | { | |
247 | return mlxsw_sp_port->link.tx_pause || mlxsw_sp_port->link.rx_pause; | |
248 | } | |
249 | ||
0d65fc13 JP |
250 | static inline struct mlxsw_sp_port * |
251 | mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index) | |
252 | { | |
253 | struct mlxsw_sp_port *mlxsw_sp_port; | |
254 | u8 local_port; | |
255 | ||
256 | local_port = mlxsw_core_lag_mapping_get(mlxsw_sp->core, | |
257 | lag_id, port_index); | |
258 | mlxsw_sp_port = mlxsw_sp->ports[local_port]; | |
259 | return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL; | |
260 | } | |
261 | ||
7f71eb46 IS |
262 | static inline bool |
263 | mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port) | |
264 | { | |
265 | return mlxsw_sp_port->vport.vfid; | |
266 | } | |
267 | ||
26f0e7fb IS |
268 | static inline struct net_device * |
269 | mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport) | |
270 | { | |
271 | return mlxsw_sp_vport->vport.vfid->br_dev; | |
272 | } | |
273 | ||
7f71eb46 IS |
274 | static inline u16 |
275 | mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) | |
276 | { | |
277 | return mlxsw_sp_vport->vport.vid; | |
278 | } | |
279 | ||
280 | static inline u16 | |
281 | mlxsw_sp_vport_vfid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) | |
282 | { | |
283 | return mlxsw_sp_vport->vport.vfid->vfid; | |
284 | } | |
285 | ||
286 | static inline struct mlxsw_sp_port * | |
287 | mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) | |
288 | { | |
289 | struct mlxsw_sp_port *mlxsw_sp_vport; | |
290 | ||
291 | list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, | |
292 | vport.list) { | |
293 | if (mlxsw_sp_vport_vid_get(mlxsw_sp_vport) == vid) | |
294 | return mlxsw_sp_vport; | |
295 | } | |
296 | ||
297 | return NULL; | |
298 | } | |
299 | ||
aac78a44 IS |
300 | static inline struct mlxsw_sp_port * |
301 | mlxsw_sp_port_vport_find_by_vfid(const struct mlxsw_sp_port *mlxsw_sp_port, | |
302 | u16 vfid) | |
303 | { | |
304 | struct mlxsw_sp_port *mlxsw_sp_vport; | |
305 | ||
306 | list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, | |
307 | vport.list) { | |
308 | if (mlxsw_sp_vport_vfid_get(mlxsw_sp_vport) == vfid) | |
309 | return mlxsw_sp_vport; | |
310 | } | |
311 | ||
312 | return NULL; | |
313 | } | |
314 | ||
56ade8fe JP |
315 | enum mlxsw_sp_flood_table { |
316 | MLXSW_SP_FLOOD_TABLE_UC, | |
317 | MLXSW_SP_FLOOD_TABLE_BM, | |
318 | }; | |
319 | ||
320 | int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp); | |
0f433fa0 | 321 | void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp); |
56ade8fe | 322 | int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port); |
0f433fa0 JP |
323 | int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core, |
324 | unsigned int sb_index, u16 pool_index, | |
325 | struct devlink_sb_pool_info *pool_info); | |
326 | int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, | |
327 | unsigned int sb_index, u16 pool_index, u32 size, | |
328 | enum devlink_sb_threshold_type threshold_type); | |
329 | int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, | |
330 | unsigned int sb_index, u16 pool_index, | |
331 | u32 *p_threshold); | |
332 | int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port, | |
333 | unsigned int sb_index, u16 pool_index, | |
334 | u32 threshold); | |
335 | int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port, | |
336 | unsigned int sb_index, u16 tc_index, | |
337 | enum devlink_sb_pool_type pool_type, | |
338 | u16 *p_pool_index, u32 *p_threshold); | |
339 | int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, | |
340 | unsigned int sb_index, u16 tc_index, | |
341 | enum devlink_sb_pool_type pool_type, | |
342 | u16 pool_index, u32 threshold); | |
2d0ed39f JP |
343 | int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core, |
344 | unsigned int sb_index); | |
345 | int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core, | |
346 | unsigned int sb_index); | |
347 | int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, | |
348 | unsigned int sb_index, u16 pool_index, | |
349 | u32 *p_cur, u32 *p_max); | |
350 | int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, | |
351 | unsigned int sb_index, u16 tc_index, | |
352 | enum devlink_sb_pool_type pool_type, | |
353 | u32 *p_cur, u32 *p_max); | |
56ade8fe JP |
354 | |
355 | int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); | |
356 | void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); | |
357 | int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port); | |
358 | void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); | |
359 | void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); | |
360 | int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, | |
361 | enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, | |
362 | u16 vid); | |
363 | int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, | |
364 | u16 vid_end, bool is_member, bool untagged); | |
365 | int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, | |
366 | u16 vid); | |
367 | int mlxsw_sp_port_kill_vid(struct net_device *dev, | |
368 | __be16 __always_unused proto, u16 vid); | |
7f71eb46 | 369 | int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid, |
19ae6124 | 370 | bool set, bool only_uc); |
4dc236c3 | 371 | void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); |
28a01d2d | 372 | int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); |
8e8dfe9f IS |
373 | int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, |
374 | enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, | |
375 | bool dwrr, u8 dwrr_weight); | |
376 | int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port, | |
377 | u8 switch_prio, u8 tclass); | |
378 | int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu, | |
d81a6bdb IS |
379 | u8 *prio_tc, bool pause_en, |
380 | struct ieee_pfc *my_pfc); | |
cc7cf517 IS |
381 | int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, |
382 | enum mlxsw_reg_qeec_hr hr, u8 index, | |
383 | u8 next_index, u32 maxrate); | |
56ade8fe | 384 | |
f00817df IS |
385 | #ifdef CONFIG_MLXSW_SPECTRUM_DCB |
386 | ||
387 | int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port); | |
388 | void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port); | |
389 | ||
390 | #else | |
391 | ||
392 | static inline int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port) | |
393 | { | |
394 | return 0; | |
395 | } | |
396 | ||
397 | static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port) | |
398 | {} | |
399 | ||
400 | #endif | |
401 | ||
56ade8fe | 402 | #endif |