diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum.c')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 735 |
1 files changed, 593 insertions, 142 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index adc6ab2cf429..f84b9c02fcc5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c | |||
| @@ -1,38 +1,5 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
| 2 | * drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 | /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ |
| 3 | * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved. | ||
| 4 | * Copyright (c) 2015-2017 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 | 3 | ||
| 37 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
| 38 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| @@ -54,6 +21,7 @@ | |||
| 54 | #include <linux/dcbnl.h> | 21 | #include <linux/dcbnl.h> |
| 55 | #include <linux/inetdevice.h> | 22 | #include <linux/inetdevice.h> |
| 56 | #include <linux/netlink.h> | 23 | #include <linux/netlink.h> |
| 24 | #include <linux/random.h> | ||
| 57 | #include <net/switchdev.h> | 25 | #include <net/switchdev.h> |
| 58 | #include <net/pkt_cls.h> | 26 | #include <net/pkt_cls.h> |
| 59 | #include <net/tc_act/tc_mirred.h> | 27 | #include <net/tc_act/tc_mirred.h> |
| @@ -74,17 +42,27 @@ | |||
| 74 | #include "spectrum_span.h" | 42 | #include "spectrum_span.h" |
| 75 | #include "../mlxfw/mlxfw.h" | 43 | #include "../mlxfw/mlxfw.h" |
| 76 | 44 | ||
| 77 | #define MLXSW_FWREV_MAJOR 13 | 45 | #define MLXSW_SP_FWREV_MINOR_TO_BRANCH(minor) ((minor) / 100) |
| 78 | #define MLXSW_FWREV_MINOR 1620 | ||
| 79 | #define MLXSW_FWREV_SUBMINOR 192 | ||
| 80 | #define MLXSW_FWREV_MINOR_TO_BRANCH(minor) ((minor) / 100) | ||
| 81 | 46 | ||
| 82 | #define MLXSW_SP_FW_FILENAME \ | 47 | #define MLXSW_SP1_FWREV_MAJOR 13 |
| 83 | "mellanox/mlxsw_spectrum-" __stringify(MLXSW_FWREV_MAJOR) \ | 48 | #define MLXSW_SP1_FWREV_MINOR 1703 |
| 84 | "." __stringify(MLXSW_FWREV_MINOR) \ | 49 | #define MLXSW_SP1_FWREV_SUBMINOR 4 |
| 85 | "." __stringify(MLXSW_FWREV_SUBMINOR) ".mfa2" | 50 | #define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702 |
| 86 | 51 | ||
| 87 | static const char mlxsw_sp_driver_name[] = "mlxsw_spectrum"; | 52 | static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { |
| 53 | .major = MLXSW_SP1_FWREV_MAJOR, | ||
| 54 | .minor = MLXSW_SP1_FWREV_MINOR, | ||
| 55 | .subminor = MLXSW_SP1_FWREV_SUBMINOR, | ||
| 56 | .can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR, | ||
| 57 | }; | ||
| 58 | |||
| 59 | #define MLXSW_SP1_FW_FILENAME \ | ||
| 60 | "mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \ | ||
| 61 | "." __stringify(MLXSW_SP1_FWREV_MINOR) \ | ||
| 62 | "." __stringify(MLXSW_SP1_FWREV_SUBMINOR) ".mfa2" | ||
| 63 | |||
| 64 | static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum"; | ||
| 65 | static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2"; | ||
| 88 | static const char mlxsw_sp_driver_version[] = "1.0"; | 66 | static const char mlxsw_sp_driver_version[] = "1.0"; |
| 89 | 67 | ||
| 90 | /* tx_hdr_version | 68 | /* tx_hdr_version |
| @@ -331,42 +309,65 @@ static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, | |||
| 331 | }, | 309 | }, |
| 332 | .mlxsw_sp = mlxsw_sp | 310 | .mlxsw_sp = mlxsw_sp |
| 333 | }; | 311 | }; |
| 312 | int err; | ||
| 313 | |||
| 314 | mlxsw_core_fw_flash_start(mlxsw_sp->core); | ||
| 315 | err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); | ||
| 316 | mlxsw_core_fw_flash_end(mlxsw_sp->core); | ||
| 334 | 317 | ||
| 335 | return mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); | 318 | return err; |
| 336 | } | 319 | } |
| 337 | 320 | ||
| 338 | static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) | 321 | static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) |
| 339 | { | 322 | { |
| 340 | const struct mlxsw_fw_rev *rev = &mlxsw_sp->bus_info->fw_rev; | 323 | const struct mlxsw_fw_rev *rev = &mlxsw_sp->bus_info->fw_rev; |
| 324 | const struct mlxsw_fw_rev *req_rev = mlxsw_sp->req_rev; | ||
| 325 | const char *fw_filename = mlxsw_sp->fw_filename; | ||
| 341 | const struct firmware *firmware; | 326 | const struct firmware *firmware; |
| 342 | int err; | 327 | int err; |
| 343 | 328 | ||
| 329 | /* Don't check if driver does not require it */ | ||
| 330 | if (!req_rev || !fw_filename) | ||
| 331 | return 0; | ||
| 332 | |||
| 344 | /* Validate driver & FW are compatible */ | 333 | /* Validate driver & FW are compatible */ |
| 345 | if (rev->major != MLXSW_FWREV_MAJOR) { | 334 | if (rev->major != req_rev->major) { |
| 346 | WARN(1, "Mismatch in major FW version [%d:%d] is never expected; Please contact support\n", | 335 | WARN(1, "Mismatch in major FW version [%d:%d] is never expected; Please contact support\n", |
| 347 | rev->major, MLXSW_FWREV_MAJOR); | 336 | rev->major, req_rev->major); |
| 348 | return -EINVAL; | 337 | return -EINVAL; |
| 349 | } | 338 | } |
| 350 | if (MLXSW_FWREV_MINOR_TO_BRANCH(rev->minor) == | 339 | if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) == |
| 351 | MLXSW_FWREV_MINOR_TO_BRANCH(MLXSW_FWREV_MINOR)) | 340 | MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) && |
| 341 | (rev->minor > req_rev->minor || | ||
| 342 | (rev->minor == req_rev->minor && | ||
| 343 | rev->subminor >= req_rev->subminor))) | ||
| 352 | return 0; | 344 | return 0; |
| 353 | 345 | ||
| 354 | dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n", | 346 | dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n", |
| 355 | rev->major, rev->minor, rev->subminor); | 347 | rev->major, rev->minor, rev->subminor); |
| 356 | dev_info(mlxsw_sp->bus_info->dev, "Flashing firmware using file %s\n", | 348 | dev_info(mlxsw_sp->bus_info->dev, "Flashing firmware using file %s\n", |
| 357 | MLXSW_SP_FW_FILENAME); | 349 | fw_filename); |
| 358 | 350 | ||
| 359 | err = request_firmware_direct(&firmware, MLXSW_SP_FW_FILENAME, | 351 | err = request_firmware_direct(&firmware, fw_filename, |
| 360 | mlxsw_sp->bus_info->dev); | 352 | mlxsw_sp->bus_info->dev); |
| 361 | if (err) { | 353 | if (err) { |
| 362 | dev_err(mlxsw_sp->bus_info->dev, "Could not request firmware file %s\n", | 354 | dev_err(mlxsw_sp->bus_info->dev, "Could not request firmware file %s\n", |
| 363 | MLXSW_SP_FW_FILENAME); | 355 | fw_filename); |
| 364 | return err; | 356 | return err; |
| 365 | } | 357 | } |
| 366 | 358 | ||
| 367 | err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); | 359 | err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); |
| 368 | release_firmware(firmware); | 360 | release_firmware(firmware); |
| 369 | return err; | 361 | if (err) |
| 362 | dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n"); | ||
| 363 | |||
| 364 | /* On FW flash success, tell the caller FW reset is needed | ||
| 365 | * if current FW supports it. | ||
| 366 | */ | ||
| 367 | if (rev->minor >= req_rev->can_reset_minor) | ||
| 368 | return err ? err : -EAGAIN; | ||
| 369 | else | ||
| 370 | return 0; | ||
| 370 | } | 371 | } |
| 371 | 372 | ||
| 372 | int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, | 373 | int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, |
| @@ -441,29 +442,29 @@ static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, | |||
| 441 | mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); | 442 | mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); |
| 442 | } | 443 | } |
| 443 | 444 | ||
| 444 | int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, | 445 | enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state) |
| 445 | u8 state) | ||
| 446 | { | 446 | { |
| 447 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | ||
| 448 | enum mlxsw_reg_spms_state spms_state; | ||
| 449 | char *spms_pl; | ||
| 450 | int err; | ||
| 451 | |||
| 452 | switch (state) { | 447 | switch (state) { |
| 453 | case BR_STATE_FORWARDING: | 448 | case BR_STATE_FORWARDING: |
| 454 | spms_state = MLXSW_REG_SPMS_STATE_FORWARDING; | 449 | return MLXSW_REG_SPMS_STATE_FORWARDING; |
| 455 | break; | ||
| 456 | case BR_STATE_LEARNING: | 450 | case BR_STATE_LEARNING: |
| 457 | spms_state = MLXSW_REG_SPMS_STATE_LEARNING; | 451 | return MLXSW_REG_SPMS_STATE_LEARNING; |
| 458 | break; | ||
| 459 | case BR_STATE_LISTENING: /* fall-through */ | 452 | case BR_STATE_LISTENING: /* fall-through */ |
| 460 | case BR_STATE_DISABLED: /* fall-through */ | 453 | case BR_STATE_DISABLED: /* fall-through */ |
| 461 | case BR_STATE_BLOCKING: | 454 | case BR_STATE_BLOCKING: |
| 462 | spms_state = MLXSW_REG_SPMS_STATE_DISCARDING; | 455 | return MLXSW_REG_SPMS_STATE_DISCARDING; |
| 463 | break; | ||
| 464 | default: | 456 | default: |
| 465 | BUG(); | 457 | BUG(); |
| 466 | } | 458 | } |
| 459 | } | ||
| 460 | |||
| 461 | int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, | ||
| 462 | u8 state) | ||
| 463 | { | ||
| 464 | enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state); | ||
| 465 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | ||
| 466 | char *spms_pl; | ||
| 467 | int err; | ||
| 467 | 468 | ||
| 468 | spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); | 469 | spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); |
| 469 | if (!spms_pl) | 470 | if (!spms_pl) |
| @@ -1238,21 +1239,10 @@ static int mlxsw_sp_port_get_phys_port_name(struct net_device *dev, char *name, | |||
| 1238 | size_t len) | 1239 | size_t len) |
| 1239 | { | 1240 | { |
| 1240 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); | 1241 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
| 1241 | u8 module = mlxsw_sp_port->mapping.module; | ||
| 1242 | u8 width = mlxsw_sp_port->mapping.width; | ||
| 1243 | u8 lane = mlxsw_sp_port->mapping.lane; | ||
| 1244 | int err; | ||
| 1245 | |||
| 1246 | if (!mlxsw_sp_port->split) | ||
| 1247 | err = snprintf(name, len, "p%d", module + 1); | ||
| 1248 | else | ||
| 1249 | err = snprintf(name, len, "p%ds%d", module + 1, | ||
| 1250 | lane / width); | ||
| 1251 | |||
| 1252 | if (err >= len) | ||
| 1253 | return -EINVAL; | ||
| 1254 | 1242 | ||
| 1255 | return 0; | 1243 | return mlxsw_core_port_get_phys_port_name(mlxsw_sp_port->mlxsw_sp->core, |
| 1244 | mlxsw_sp_port->local_port, | ||
| 1245 | name, len); | ||
| 1256 | } | 1246 | } |
| 1257 | 1247 | ||
| 1258 | static struct mlxsw_sp_port_mall_tc_entry * | 1248 | static struct mlxsw_sp_port_mall_tc_entry * |
| @@ -1365,8 +1355,7 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 1365 | return -ENOMEM; | 1355 | return -ENOMEM; |
| 1366 | mall_tc_entry->cookie = f->cookie; | 1356 | mall_tc_entry->cookie = f->cookie; |
| 1367 | 1357 | ||
| 1368 | tcf_exts_to_list(f->exts, &actions); | 1358 | a = tcf_exts_first_action(f->exts); |
| 1369 | a = list_first_entry(&actions, struct tc_action, list); | ||
| 1370 | 1359 | ||
| 1371 | if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) { | 1360 | if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) { |
| 1372 | struct mlxsw_sp_port_mall_mirror_tc_entry *mirror; | 1361 | struct mlxsw_sp_port_mall_mirror_tc_entry *mirror; |
| @@ -1452,6 +1441,11 @@ mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_acl_block *acl_block, | |||
| 1452 | return 0; | 1441 | return 0; |
| 1453 | case TC_CLSFLOWER_STATS: | 1442 | case TC_CLSFLOWER_STATS: |
| 1454 | return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f); | 1443 | return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f); |
| 1444 | case TC_CLSFLOWER_TMPLT_CREATE: | ||
| 1445 | return mlxsw_sp_flower_tmplt_create(mlxsw_sp, acl_block, f); | ||
| 1446 | case TC_CLSFLOWER_TMPLT_DESTROY: | ||
| 1447 | mlxsw_sp_flower_tmplt_destroy(mlxsw_sp, acl_block, f); | ||
| 1448 | return 0; | ||
| 1455 | default: | 1449 | default: |
| 1456 | return -EOPNOTSUPP; | 1450 | return -EOPNOTSUPP; |
| 1457 | } | 1451 | } |
| @@ -1514,7 +1508,8 @@ static int mlxsw_sp_setup_tc_block_cb_flower(enum tc_setup_type type, | |||
| 1514 | 1508 | ||
| 1515 | static int | 1509 | static int |
| 1516 | mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port, | 1510 | mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port, |
| 1517 | struct tcf_block *block, bool ingress) | 1511 | struct tcf_block *block, bool ingress, |
| 1512 | struct netlink_ext_ack *extack) | ||
| 1518 | { | 1513 | { |
| 1519 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 1514 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
| 1520 | struct mlxsw_sp_acl_block *acl_block; | 1515 | struct mlxsw_sp_acl_block *acl_block; |
| @@ -1529,7 +1524,7 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 1529 | return -ENOMEM; | 1524 | return -ENOMEM; |
| 1530 | block_cb = __tcf_block_cb_register(block, | 1525 | block_cb = __tcf_block_cb_register(block, |
| 1531 | mlxsw_sp_setup_tc_block_cb_flower, | 1526 | mlxsw_sp_setup_tc_block_cb_flower, |
| 1532 | mlxsw_sp, acl_block); | 1527 | mlxsw_sp, acl_block, extack); |
| 1533 | if (IS_ERR(block_cb)) { | 1528 | if (IS_ERR(block_cb)) { |
| 1534 | err = PTR_ERR(block_cb); | 1529 | err = PTR_ERR(block_cb); |
| 1535 | goto err_cb_register; | 1530 | goto err_cb_register; |
| @@ -1552,7 +1547,7 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 1552 | 1547 | ||
| 1553 | err_block_bind: | 1548 | err_block_bind: |
| 1554 | if (!tcf_block_cb_decref(block_cb)) { | 1549 | if (!tcf_block_cb_decref(block_cb)) { |
| 1555 | __tcf_block_cb_unregister(block_cb); | 1550 | __tcf_block_cb_unregister(block, block_cb); |
| 1556 | err_cb_register: | 1551 | err_cb_register: |
| 1557 | mlxsw_sp_acl_block_destroy(acl_block); | 1552 | mlxsw_sp_acl_block_destroy(acl_block); |
| 1558 | } | 1553 | } |
| @@ -1582,7 +1577,7 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 1582 | err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block, | 1577 | err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block, |
| 1583 | mlxsw_sp_port, ingress); | 1578 | mlxsw_sp_port, ingress); |
| 1584 | if (!err && !tcf_block_cb_decref(block_cb)) { | 1579 | if (!err && !tcf_block_cb_decref(block_cb)) { |
| 1585 | __tcf_block_cb_unregister(block_cb); | 1580 | __tcf_block_cb_unregister(block, block_cb); |
| 1586 | mlxsw_sp_acl_block_destroy(acl_block); | 1581 | mlxsw_sp_acl_block_destroy(acl_block); |
| 1587 | } | 1582 | } |
| 1588 | } | 1583 | } |
| @@ -1607,11 +1602,12 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 1607 | switch (f->command) { | 1602 | switch (f->command) { |
| 1608 | case TC_BLOCK_BIND: | 1603 | case TC_BLOCK_BIND: |
| 1609 | err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port, | 1604 | err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port, |
| 1610 | mlxsw_sp_port); | 1605 | mlxsw_sp_port, f->extack); |
| 1611 | if (err) | 1606 | if (err) |
| 1612 | return err; | 1607 | return err; |
| 1613 | err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, | 1608 | err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, |
| 1614 | f->block, ingress); | 1609 | f->block, ingress, |
| 1610 | f->extack); | ||
| 1615 | if (err) { | 1611 | if (err) { |
| 1616 | tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port); | 1612 | tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port); |
| 1617 | return err; | 1613 | return err; |
| @@ -1723,7 +1719,8 @@ static void mlxsw_sp_port_get_drvinfo(struct net_device *dev, | |||
| 1723 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); | 1719 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
| 1724 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 1720 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
| 1725 | 1721 | ||
| 1726 | strlcpy(drvinfo->driver, mlxsw_sp_driver_name, sizeof(drvinfo->driver)); | 1722 | strlcpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind, |
| 1723 | sizeof(drvinfo->driver)); | ||
| 1727 | strlcpy(drvinfo->version, mlxsw_sp_driver_version, | 1724 | strlcpy(drvinfo->version, mlxsw_sp_driver_version, |
| 1728 | sizeof(drvinfo->version)); | 1725 | sizeof(drvinfo->version)); |
| 1729 | snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), | 1726 | snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), |
| @@ -1884,6 +1881,52 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_stats[] = { | |||
| 1884 | 1881 | ||
| 1885 | #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats) | 1882 | #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats) |
| 1886 | 1883 | ||
| 1884 | static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2819_stats[] = { | ||
| 1885 | { | ||
| 1886 | .str = "ether_pkts64octets", | ||
| 1887 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get, | ||
| 1888 | }, | ||
| 1889 | { | ||
| 1890 | .str = "ether_pkts65to127octets", | ||
| 1891 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get, | ||
| 1892 | }, | ||
| 1893 | { | ||
| 1894 | .str = "ether_pkts128to255octets", | ||
| 1895 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get, | ||
| 1896 | }, | ||
| 1897 | { | ||
| 1898 | .str = "ether_pkts256to511octets", | ||
| 1899 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get, | ||
| 1900 | }, | ||
| 1901 | { | ||
| 1902 | .str = "ether_pkts512to1023octets", | ||
| 1903 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get, | ||
| 1904 | }, | ||
| 1905 | { | ||
| 1906 | .str = "ether_pkts1024to1518octets", | ||
| 1907 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get, | ||
| 1908 | }, | ||
| 1909 | { | ||
| 1910 | .str = "ether_pkts1519to2047octets", | ||
| 1911 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get, | ||
| 1912 | }, | ||
| 1913 | { | ||
| 1914 | .str = "ether_pkts2048to4095octets", | ||
| 1915 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get, | ||
| 1916 | }, | ||
| 1917 | { | ||
| 1918 | .str = "ether_pkts4096to8191octets", | ||
| 1919 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get, | ||
| 1920 | }, | ||
| 1921 | { | ||
| 1922 | .str = "ether_pkts8192to10239octets", | ||
| 1923 | .getter = mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get, | ||
| 1924 | }, | ||
| 1925 | }; | ||
| 1926 | |||
| 1927 | #define MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN \ | ||
| 1928 | ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2819_stats) | ||
| 1929 | |||
| 1887 | static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = { | 1930 | static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = { |
| 1888 | { | 1931 | { |
| 1889 | .str = "rx_octets_prio", | 1932 | .str = "rx_octets_prio", |
| @@ -1936,9 +1979,11 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = { | |||
| 1936 | #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats) | 1979 | #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats) |
| 1937 | 1980 | ||
| 1938 | #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \ | 1981 | #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \ |
| 1939 | (MLXSW_SP_PORT_HW_PRIO_STATS_LEN + \ | 1982 | MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \ |
| 1940 | MLXSW_SP_PORT_HW_TC_STATS_LEN) * \ | 1983 | (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \ |
| 1941 | IEEE_8021QAZ_MAX_TCS) | 1984 | IEEE_8021QAZ_MAX_TCS) + \ |
| 1985 | (MLXSW_SP_PORT_HW_TC_STATS_LEN * \ | ||
| 1986 | TC_MAX_QUEUE)) | ||
| 1942 | 1987 | ||
| 1943 | static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio) | 1988 | static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio) |
| 1944 | { | 1989 | { |
| @@ -1975,11 +2020,16 @@ static void mlxsw_sp_port_get_strings(struct net_device *dev, | |||
| 1975 | ETH_GSTRING_LEN); | 2020 | ETH_GSTRING_LEN); |
| 1976 | p += ETH_GSTRING_LEN; | 2021 | p += ETH_GSTRING_LEN; |
| 1977 | } | 2022 | } |
| 2023 | for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; i++) { | ||
| 2024 | memcpy(p, mlxsw_sp_port_hw_rfc_2819_stats[i].str, | ||
| 2025 | ETH_GSTRING_LEN); | ||
| 2026 | p += ETH_GSTRING_LEN; | ||
| 2027 | } | ||
| 1978 | 2028 | ||
| 1979 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | 2029 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) |
| 1980 | mlxsw_sp_port_get_prio_strings(&p, i); | 2030 | mlxsw_sp_port_get_prio_strings(&p, i); |
| 1981 | 2031 | ||
| 1982 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | 2032 | for (i = 0; i < TC_MAX_QUEUE; i++) |
| 1983 | mlxsw_sp_port_get_tc_strings(&p, i); | 2033 | mlxsw_sp_port_get_tc_strings(&p, i); |
| 1984 | 2034 | ||
| 1985 | break; | 2035 | break; |
| @@ -2014,10 +2064,14 @@ mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats, | |||
| 2014 | int *p_len, enum mlxsw_reg_ppcnt_grp grp) | 2064 | int *p_len, enum mlxsw_reg_ppcnt_grp grp) |
| 2015 | { | 2065 | { |
| 2016 | switch (grp) { | 2066 | switch (grp) { |
| 2017 | case MLXSW_REG_PPCNT_IEEE_8023_CNT: | 2067 | case MLXSW_REG_PPCNT_IEEE_8023_CNT: |
| 2018 | *p_hw_stats = mlxsw_sp_port_hw_stats; | 2068 | *p_hw_stats = mlxsw_sp_port_hw_stats; |
| 2019 | *p_len = MLXSW_SP_PORT_HW_STATS_LEN; | 2069 | *p_len = MLXSW_SP_PORT_HW_STATS_LEN; |
| 2020 | break; | 2070 | break; |
| 2071 | case MLXSW_REG_PPCNT_RFC_2819_CNT: | ||
| 2072 | *p_hw_stats = mlxsw_sp_port_hw_rfc_2819_stats; | ||
| 2073 | *p_len = MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; | ||
| 2074 | break; | ||
| 2021 | case MLXSW_REG_PPCNT_PRIO_CNT: | 2075 | case MLXSW_REG_PPCNT_PRIO_CNT: |
| 2022 | *p_hw_stats = mlxsw_sp_port_hw_prio_stats; | 2076 | *p_hw_stats = mlxsw_sp_port_hw_prio_stats; |
| 2023 | *p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN; | 2077 | *p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN; |
| @@ -2067,6 +2121,11 @@ static void mlxsw_sp_port_get_stats(struct net_device *dev, | |||
| 2067 | data, data_index); | 2121 | data, data_index); |
| 2068 | data_index = MLXSW_SP_PORT_HW_STATS_LEN; | 2122 | data_index = MLXSW_SP_PORT_HW_STATS_LEN; |
| 2069 | 2123 | ||
| 2124 | /* RFC 2819 Counters */ | ||
| 2125 | __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0, | ||
| 2126 | data, data_index); | ||
| 2127 | data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; | ||
| 2128 | |||
| 2070 | /* Per-Priority Counters */ | 2129 | /* Per-Priority Counters */ |
| 2071 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | 2130 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
| 2072 | __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i, | 2131 | __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i, |
| @@ -2075,7 +2134,7 @@ static void mlxsw_sp_port_get_stats(struct net_device *dev, | |||
| 2075 | } | 2134 | } |
| 2076 | 2135 | ||
| 2077 | /* Per-TC Counters */ | 2136 | /* Per-TC Counters */ |
| 2078 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | 2137 | for (i = 0; i < TC_MAX_QUEUE; i++) { |
| 2079 | __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i, | 2138 | __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i, |
| 2080 | data, data_index); | 2139 | data, data_index); |
| 2081 | data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN; | 2140 | data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN; |
| @@ -2686,6 +2745,21 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, | |||
| 2686 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); | 2745 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); |
| 2687 | } | 2746 | } |
| 2688 | 2747 | ||
| 2748 | static int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
| 2749 | enum mlxsw_reg_qeec_hr hr, u8 index, | ||
| 2750 | u8 next_index, u32 minrate) | ||
| 2751 | { | ||
| 2752 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | ||
| 2753 | char qeec_pl[MLXSW_REG_QEEC_LEN]; | ||
| 2754 | |||
| 2755 | mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, | ||
| 2756 | next_index); | ||
| 2757 | mlxsw_reg_qeec_mise_set(qeec_pl, true); | ||
| 2758 | mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate); | ||
| 2759 | |||
| 2760 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); | ||
| 2761 | } | ||
| 2762 | |||
| 2689 | int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port, | 2763 | int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port, |
| 2690 | u8 switch_prio, u8 tclass) | 2764 | u8 switch_prio, u8 tclass) |
| 2691 | { | 2765 | { |
| @@ -2722,9 +2796,16 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) | |||
| 2722 | false, 0); | 2796 | false, 0); |
| 2723 | if (err) | 2797 | if (err) |
| 2724 | return err; | 2798 | return err; |
| 2799 | |||
| 2800 | err = mlxsw_sp_port_ets_set(mlxsw_sp_port, | ||
| 2801 | MLXSW_REG_QEEC_HIERARCY_TC, | ||
| 2802 | i + 8, i, | ||
| 2803 | false, 0); | ||
| 2804 | if (err) | ||
| 2805 | return err; | ||
| 2725 | } | 2806 | } |
| 2726 | 2807 | ||
| 2727 | /* Make sure the max shaper is disabled in all hierarcies that | 2808 | /* Make sure the max shaper is disabled in all hierarchies that |
| 2728 | * support it. | 2809 | * support it. |
| 2729 | */ | 2810 | */ |
| 2730 | err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, | 2811 | err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, |
| @@ -2747,6 +2828,23 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) | |||
| 2747 | MLXSW_REG_QEEC_MAS_DIS); | 2828 | MLXSW_REG_QEEC_MAS_DIS); |
| 2748 | if (err) | 2829 | if (err) |
| 2749 | return err; | 2830 | return err; |
| 2831 | |||
| 2832 | err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, | ||
| 2833 | MLXSW_REG_QEEC_HIERARCY_TC, | ||
| 2834 | i + 8, i, | ||
| 2835 | MLXSW_REG_QEEC_MAS_DIS); | ||
| 2836 | if (err) | ||
| 2837 | return err; | ||
| 2838 | } | ||
| 2839 | |||
| 2840 | /* Configure the min shaper for multicast TCs. */ | ||
| 2841 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | ||
| 2842 | err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port, | ||
| 2843 | MLXSW_REG_QEEC_HIERARCY_TC, | ||
| 2844 | i + 8, i, | ||
| 2845 | MLXSW_REG_QEEC_MIS_MIN); | ||
| 2846 | if (err) | ||
| 2847 | return err; | ||
| 2750 | } | 2848 | } |
| 2751 | 2849 | ||
| 2752 | /* Map all priorities to traffic class 0. */ | 2850 | /* Map all priorities to traffic class 0. */ |
| @@ -2759,6 +2857,16 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) | |||
| 2759 | return 0; | 2857 | return 0; |
| 2760 | } | 2858 | } |
| 2761 | 2859 | ||
| 2860 | static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
| 2861 | bool enable) | ||
| 2862 | { | ||
| 2863 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | ||
| 2864 | char qtctm_pl[MLXSW_REG_QTCTM_LEN]; | ||
| 2865 | |||
| 2866 | mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable); | ||
| 2867 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl); | ||
| 2868 | } | ||
| 2869 | |||
| 2762 | static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, | 2870 | static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, |
| 2763 | bool split, u8 module, u8 width, u8 lane) | 2871 | bool split, u8 module, u8 width, u8 lane) |
| 2764 | { | 2872 | { |
| @@ -2887,6 +2995,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |||
| 2887 | goto err_port_ets_init; | 2995 | goto err_port_ets_init; |
| 2888 | } | 2996 | } |
| 2889 | 2997 | ||
| 2998 | err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true); | ||
| 2999 | if (err) { | ||
| 3000 | dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n", | ||
| 3001 | mlxsw_sp_port->local_port); | ||
| 3002 | goto err_port_tc_mc_mode; | ||
| 3003 | } | ||
| 3004 | |||
| 2890 | /* ETS and buffers must be initialized before DCB. */ | 3005 | /* ETS and buffers must be initialized before DCB. */ |
| 2891 | err = mlxsw_sp_port_dcb_init(mlxsw_sp_port); | 3006 | err = mlxsw_sp_port_dcb_init(mlxsw_sp_port); |
| 2892 | if (err) { | 3007 | if (err) { |
| @@ -2909,6 +3024,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |||
| 2909 | goto err_port_qdiscs_init; | 3024 | goto err_port_qdiscs_init; |
| 2910 | } | 3025 | } |
| 2911 | 3026 | ||
| 3027 | err = mlxsw_sp_port_nve_init(mlxsw_sp_port); | ||
| 3028 | if (err) { | ||
| 3029 | dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n", | ||
| 3030 | mlxsw_sp_port->local_port); | ||
| 3031 | goto err_port_nve_init; | ||
| 3032 | } | ||
| 3033 | |||
| 2912 | mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); | 3034 | mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); |
| 2913 | if (IS_ERR(mlxsw_sp_port_vlan)) { | 3035 | if (IS_ERR(mlxsw_sp_port_vlan)) { |
| 2914 | dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", | 3036 | dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", |
| @@ -2927,8 +3049,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |||
| 2927 | } | 3049 | } |
| 2928 | 3050 | ||
| 2929 | mlxsw_core_port_eth_set(mlxsw_sp->core, mlxsw_sp_port->local_port, | 3051 | mlxsw_core_port_eth_set(mlxsw_sp->core, mlxsw_sp_port->local_port, |
| 2930 | mlxsw_sp_port, dev, mlxsw_sp_port->split, | 3052 | mlxsw_sp_port, dev, module + 1, |
| 2931 | module); | 3053 | mlxsw_sp_port->split, lane / width); |
| 2932 | mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0); | 3054 | mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0); |
| 2933 | return 0; | 3055 | return 0; |
| 2934 | 3056 | ||
| @@ -2937,12 +3059,16 @@ err_register_netdev: | |||
| 2937 | mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); | 3059 | mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); |
| 2938 | mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); | 3060 | mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); |
| 2939 | err_port_vlan_get: | 3061 | err_port_vlan_get: |
| 3062 | mlxsw_sp_port_nve_fini(mlxsw_sp_port); | ||
| 3063 | err_port_nve_init: | ||
| 2940 | mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); | 3064 | mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); |
| 2941 | err_port_qdiscs_init: | 3065 | err_port_qdiscs_init: |
| 2942 | mlxsw_sp_port_fids_fini(mlxsw_sp_port); | 3066 | mlxsw_sp_port_fids_fini(mlxsw_sp_port); |
| 2943 | err_port_fids_init: | 3067 | err_port_fids_init: |
| 2944 | mlxsw_sp_port_dcb_fini(mlxsw_sp_port); | 3068 | mlxsw_sp_port_dcb_fini(mlxsw_sp_port); |
| 2945 | err_port_dcb_init: | 3069 | err_port_dcb_init: |
| 3070 | mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); | ||
| 3071 | err_port_tc_mc_mode: | ||
| 2946 | err_port_ets_init: | 3072 | err_port_ets_init: |
| 2947 | err_port_buffers_init: | 3073 | err_port_buffers_init: |
| 2948 | err_port_admin_status_set: | 3074 | err_port_admin_status_set: |
| @@ -2974,9 +3100,11 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) | |||
| 2974 | mlxsw_sp->ports[local_port] = NULL; | 3100 | mlxsw_sp->ports[local_port] = NULL; |
| 2975 | mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); | 3101 | mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); |
| 2976 | mlxsw_sp_port_vlan_flush(mlxsw_sp_port); | 3102 | mlxsw_sp_port_vlan_flush(mlxsw_sp_port); |
| 3103 | mlxsw_sp_port_nve_fini(mlxsw_sp_port); | ||
| 2977 | mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); | 3104 | mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); |
| 2978 | mlxsw_sp_port_fids_fini(mlxsw_sp_port); | 3105 | mlxsw_sp_port_fids_fini(mlxsw_sp_port); |
| 2979 | mlxsw_sp_port_dcb_fini(mlxsw_sp_port); | 3106 | mlxsw_sp_port_dcb_fini(mlxsw_sp_port); |
| 3107 | mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); | ||
| 2980 | mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); | 3108 | mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); |
| 2981 | mlxsw_sp_port_module_unmap(mlxsw_sp_port); | 3109 | mlxsw_sp_port_module_unmap(mlxsw_sp_port); |
| 2982 | kfree(mlxsw_sp_port->sample); | 3110 | kfree(mlxsw_sp_port->sample); |
| @@ -3103,7 +3231,8 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, | |||
| 3103 | } | 3231 | } |
| 3104 | 3232 | ||
| 3105 | static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, | 3233 | static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, |
| 3106 | unsigned int count) | 3234 | unsigned int count, |
| 3235 | struct netlink_ext_ack *extack) | ||
| 3107 | { | 3236 | { |
| 3108 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | 3237 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); |
| 3109 | struct mlxsw_sp_port *mlxsw_sp_port; | 3238 | struct mlxsw_sp_port *mlxsw_sp_port; |
| @@ -3115,6 +3244,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, | |||
| 3115 | if (!mlxsw_sp_port) { | 3244 | if (!mlxsw_sp_port) { |
| 3116 | dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", | 3245 | dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", |
| 3117 | local_port); | 3246 | local_port); |
| 3247 | NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); | ||
| 3118 | return -EINVAL; | 3248 | return -EINVAL; |
| 3119 | } | 3249 | } |
| 3120 | 3250 | ||
| @@ -3123,11 +3253,13 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, | |||
| 3123 | 3253 | ||
| 3124 | if (count != 2 && count != 4) { | 3254 | if (count != 2 && count != 4) { |
| 3125 | netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); | 3255 | netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); |
| 3256 | NL_SET_ERR_MSG_MOD(extack, "Port can only be split into 2 or 4 ports"); | ||
| 3126 | return -EINVAL; | 3257 | return -EINVAL; |
| 3127 | } | 3258 | } |
| 3128 | 3259 | ||
| 3129 | if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) { | 3260 | if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) { |
| 3130 | netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); | 3261 | netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); |
| 3262 | NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); | ||
| 3131 | return -EINVAL; | 3263 | return -EINVAL; |
| 3132 | } | 3264 | } |
| 3133 | 3265 | ||
| @@ -3136,6 +3268,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, | |||
| 3136 | base_port = local_port; | 3268 | base_port = local_port; |
| 3137 | if (mlxsw_sp->ports[base_port + 1]) { | 3269 | if (mlxsw_sp->ports[base_port + 1]) { |
| 3138 | netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); | 3270 | netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); |
| 3271 | NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); | ||
| 3139 | return -EINVAL; | 3272 | return -EINVAL; |
| 3140 | } | 3273 | } |
| 3141 | } else { | 3274 | } else { |
| @@ -3143,6 +3276,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, | |||
| 3143 | if (mlxsw_sp->ports[base_port + 1] || | 3276 | if (mlxsw_sp->ports[base_port + 1] || |
| 3144 | mlxsw_sp->ports[base_port + 3]) { | 3277 | mlxsw_sp->ports[base_port + 3]) { |
| 3145 | netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); | 3278 | netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); |
| 3279 | NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); | ||
| 3146 | return -EINVAL; | 3280 | return -EINVAL; |
| 3147 | } | 3281 | } |
| 3148 | } | 3282 | } |
| @@ -3164,7 +3298,8 @@ err_port_split_create: | |||
| 3164 | return err; | 3298 | return err; |
| 3165 | } | 3299 | } |
| 3166 | 3300 | ||
| 3167 | static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port) | 3301 | static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, |
| 3302 | struct netlink_ext_ack *extack) | ||
| 3168 | { | 3303 | { |
| 3169 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | 3304 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); |
| 3170 | struct mlxsw_sp_port *mlxsw_sp_port; | 3305 | struct mlxsw_sp_port *mlxsw_sp_port; |
| @@ -3176,11 +3311,13 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port) | |||
| 3176 | if (!mlxsw_sp_port) { | 3311 | if (!mlxsw_sp_port) { |
| 3177 | dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", | 3312 | dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", |
| 3178 | local_port); | 3313 | local_port); |
| 3314 | NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); | ||
| 3179 | return -EINVAL; | 3315 | return -EINVAL; |
| 3180 | } | 3316 | } |
| 3181 | 3317 | ||
| 3182 | if (!mlxsw_sp_port->split) { | 3318 | if (!mlxsw_sp_port->split) { |
| 3183 | netdev_err(mlxsw_sp_port->dev, "Port wasn't split\n"); | 3319 | netdev_err(mlxsw_sp_port->dev, "Port was not split\n"); |
| 3320 | NL_SET_ERR_MSG_MOD(extack, "Port was not split"); | ||
| 3184 | return -EINVAL; | 3321 | return -EINVAL; |
| 3185 | } | 3322 | } |
| 3186 | 3323 | ||
| @@ -3373,6 +3510,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { | |||
| 3373 | MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false), | 3510 | MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false), |
| 3374 | MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false), | 3511 | MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false), |
| 3375 | MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false), | 3512 | MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false), |
| 3513 | MLXSW_SP_RXL_MARK(DECAP_ECN0, TRAP_TO_CPU, ROUTER_EXP, false), | ||
| 3514 | MLXSW_SP_RXL_MARK(IPV4_VRRP, TRAP_TO_CPU, ROUTER_EXP, false), | ||
| 3515 | MLXSW_SP_RXL_MARK(IPV6_VRRP, TRAP_TO_CPU, ROUTER_EXP, false), | ||
| 3376 | /* PKT Sample trap */ | 3516 | /* PKT Sample trap */ |
| 3377 | MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU, | 3517 | MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU, |
| 3378 | false, SP_IP2ME, DISCARD), | 3518 | false, SP_IP2ME, DISCARD), |
| @@ -3384,6 +3524,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { | |||
| 3384 | MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false), | 3524 | MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false), |
| 3385 | MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), | 3525 | MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), |
| 3386 | MLXSW_SP_RXL_MR_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), | 3526 | MLXSW_SP_RXL_MR_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), |
| 3527 | /* NVE traps */ | ||
| 3528 | MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false), | ||
| 3529 | MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, TRAP_TO_CPU, ARP, false), | ||
| 3387 | }; | 3530 | }; |
| 3388 | 3531 | ||
| 3389 | static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) | 3532 | static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) |
| @@ -3431,7 +3574,6 @@ static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) | |||
| 3431 | burst_size = 7; | 3574 | burst_size = 7; |
| 3432 | break; | 3575 | break; |
| 3433 | case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME: | 3576 | case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME: |
| 3434 | is_bytes = true; | ||
| 3435 | rate = 4 * 1024; | 3577 | rate = 4 * 1024; |
| 3436 | burst_size = 4; | 3578 | burst_size = 4; |
| 3437 | break; | 3579 | break; |
| @@ -3568,8 +3710,10 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) | |||
| 3568 | static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) | 3710 | static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) |
| 3569 | { | 3711 | { |
| 3570 | char slcr_pl[MLXSW_REG_SLCR_LEN]; | 3712 | char slcr_pl[MLXSW_REG_SLCR_LEN]; |
| 3713 | u32 seed; | ||
| 3571 | int err; | 3714 | int err; |
| 3572 | 3715 | ||
| 3716 | get_random_bytes(&seed, sizeof(seed)); | ||
| 3573 | mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | | 3717 | mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | |
| 3574 | MLXSW_REG_SLCR_LAG_HASH_DMAC | | 3718 | MLXSW_REG_SLCR_LAG_HASH_DMAC | |
| 3575 | MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | | 3719 | MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | |
| @@ -3578,7 +3722,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) | |||
| 3578 | MLXSW_REG_SLCR_LAG_HASH_DIP | | 3722 | MLXSW_REG_SLCR_LAG_HASH_DIP | |
| 3579 | MLXSW_REG_SLCR_LAG_HASH_SPORT | | 3723 | MLXSW_REG_SLCR_LAG_HASH_SPORT | |
| 3580 | MLXSW_REG_SLCR_LAG_HASH_DPORT | | 3724 | MLXSW_REG_SLCR_LAG_HASH_DPORT | |
| 3581 | MLXSW_REG_SLCR_LAG_HASH_IPPROTO); | 3725 | MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed); |
| 3582 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl); | 3726 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl); |
| 3583 | if (err) | 3727 | if (err) |
| 3584 | return err; | 3728 | return err; |
| @@ -3625,10 +3769,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, | |||
| 3625 | mlxsw_sp->bus_info = mlxsw_bus_info; | 3769 | mlxsw_sp->bus_info = mlxsw_bus_info; |
| 3626 | 3770 | ||
| 3627 | err = mlxsw_sp_fw_rev_validate(mlxsw_sp); | 3771 | err = mlxsw_sp_fw_rev_validate(mlxsw_sp); |
| 3628 | if (err) { | 3772 | if (err) |
| 3629 | dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n"); | ||
| 3630 | return err; | 3773 | return err; |
| 3631 | } | ||
| 3632 | 3774 | ||
| 3633 | err = mlxsw_sp_base_mac_get(mlxsw_sp); | 3775 | err = mlxsw_sp_base_mac_get(mlxsw_sp); |
| 3634 | if (err) { | 3776 | if (err) { |
| @@ -3666,6 +3808,15 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, | |||
| 3666 | goto err_lag_init; | 3808 | goto err_lag_init; |
| 3667 | } | 3809 | } |
| 3668 | 3810 | ||
| 3811 | /* Initialize SPAN before router and switchdev, so that those components | ||
| 3812 | * can call mlxsw_sp_span_respin(). | ||
| 3813 | */ | ||
| 3814 | err = mlxsw_sp_span_init(mlxsw_sp); | ||
| 3815 | if (err) { | ||
| 3816 | dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n"); | ||
| 3817 | goto err_span_init; | ||
| 3818 | } | ||
| 3819 | |||
| 3669 | err = mlxsw_sp_switchdev_init(mlxsw_sp); | 3820 | err = mlxsw_sp_switchdev_init(mlxsw_sp); |
| 3670 | if (err) { | 3821 | if (err) { |
| 3671 | dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n"); | 3822 | dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n"); |
| @@ -3684,15 +3835,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, | |||
| 3684 | goto err_afa_init; | 3835 | goto err_afa_init; |
| 3685 | } | 3836 | } |
| 3686 | 3837 | ||
| 3687 | err = mlxsw_sp_span_init(mlxsw_sp); | 3838 | err = mlxsw_sp_nve_init(mlxsw_sp); |
| 3688 | if (err) { | 3839 | if (err) { |
| 3689 | dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n"); | 3840 | dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n"); |
| 3690 | goto err_span_init; | 3841 | goto err_nve_init; |
| 3691 | } | 3842 | } |
| 3692 | 3843 | ||
| 3693 | /* Initialize router after SPAN is initialized, so that the FIB and | ||
| 3694 | * neighbor event handlers can issue SPAN respin. | ||
| 3695 | */ | ||
| 3696 | err = mlxsw_sp_router_init(mlxsw_sp); | 3844 | err = mlxsw_sp_router_init(mlxsw_sp); |
| 3697 | if (err) { | 3845 | if (err) { |
| 3698 | dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); | 3846 | dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); |
| @@ -3739,14 +3887,16 @@ err_acl_init: | |||
| 3739 | err_netdev_notifier: | 3887 | err_netdev_notifier: |
| 3740 | mlxsw_sp_router_fini(mlxsw_sp); | 3888 | mlxsw_sp_router_fini(mlxsw_sp); |
| 3741 | err_router_init: | 3889 | err_router_init: |
| 3742 | mlxsw_sp_span_fini(mlxsw_sp); | 3890 | mlxsw_sp_nve_fini(mlxsw_sp); |
| 3743 | err_span_init: | 3891 | err_nve_init: |
| 3744 | mlxsw_sp_afa_fini(mlxsw_sp); | 3892 | mlxsw_sp_afa_fini(mlxsw_sp); |
| 3745 | err_afa_init: | 3893 | err_afa_init: |
| 3746 | mlxsw_sp_counter_pool_fini(mlxsw_sp); | 3894 | mlxsw_sp_counter_pool_fini(mlxsw_sp); |
| 3747 | err_counter_pool_init: | 3895 | err_counter_pool_init: |
| 3748 | mlxsw_sp_switchdev_fini(mlxsw_sp); | 3896 | mlxsw_sp_switchdev_fini(mlxsw_sp); |
| 3749 | err_switchdev_init: | 3897 | err_switchdev_init: |
| 3898 | mlxsw_sp_span_fini(mlxsw_sp); | ||
| 3899 | err_span_init: | ||
| 3750 | mlxsw_sp_lag_fini(mlxsw_sp); | 3900 | mlxsw_sp_lag_fini(mlxsw_sp); |
| 3751 | err_lag_init: | 3901 | err_lag_init: |
| 3752 | mlxsw_sp_buffers_fini(mlxsw_sp); | 3902 | mlxsw_sp_buffers_fini(mlxsw_sp); |
| @@ -3759,6 +3909,38 @@ err_fids_init: | |||
| 3759 | return err; | 3909 | return err; |
| 3760 | } | 3910 | } |
| 3761 | 3911 | ||
| 3912 | static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, | ||
| 3913 | const struct mlxsw_bus_info *mlxsw_bus_info) | ||
| 3914 | { | ||
| 3915 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | ||
| 3916 | |||
| 3917 | mlxsw_sp->req_rev = &mlxsw_sp1_fw_rev; | ||
| 3918 | mlxsw_sp->fw_filename = MLXSW_SP1_FW_FILENAME; | ||
| 3919 | mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops; | ||
| 3920 | mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops; | ||
| 3921 | mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops; | ||
| 3922 | mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops; | ||
| 3923 | mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops; | ||
| 3924 | mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr; | ||
| 3925 | |||
| 3926 | return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); | ||
| 3927 | } | ||
| 3928 | |||
| 3929 | static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, | ||
| 3930 | const struct mlxsw_bus_info *mlxsw_bus_info) | ||
| 3931 | { | ||
| 3932 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | ||
| 3933 | |||
| 3934 | mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; | ||
| 3935 | mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; | ||
| 3936 | mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; | ||
| 3937 | mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; | ||
| 3938 | mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; | ||
| 3939 | mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; | ||
| 3940 | |||
| 3941 | return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); | ||
| 3942 | } | ||
| 3943 | |||
| 3762 | static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) | 3944 | static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) |
| 3763 | { | 3945 | { |
| 3764 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | 3946 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); |
| @@ -3768,10 +3950,11 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) | |||
| 3768 | mlxsw_sp_acl_fini(mlxsw_sp); | 3950 | mlxsw_sp_acl_fini(mlxsw_sp); |
| 3769 | unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); | 3951 | unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); |
| 3770 | mlxsw_sp_router_fini(mlxsw_sp); | 3952 | mlxsw_sp_router_fini(mlxsw_sp); |
| 3771 | mlxsw_sp_span_fini(mlxsw_sp); | 3953 | mlxsw_sp_nve_fini(mlxsw_sp); |
| 3772 | mlxsw_sp_afa_fini(mlxsw_sp); | 3954 | mlxsw_sp_afa_fini(mlxsw_sp); |
| 3773 | mlxsw_sp_counter_pool_fini(mlxsw_sp); | 3955 | mlxsw_sp_counter_pool_fini(mlxsw_sp); |
| 3774 | mlxsw_sp_switchdev_fini(mlxsw_sp); | 3956 | mlxsw_sp_switchdev_fini(mlxsw_sp); |
| 3957 | mlxsw_sp_span_fini(mlxsw_sp); | ||
| 3775 | mlxsw_sp_lag_fini(mlxsw_sp); | 3958 | mlxsw_sp_lag_fini(mlxsw_sp); |
| 3776 | mlxsw_sp_buffers_fini(mlxsw_sp); | 3959 | mlxsw_sp_buffers_fini(mlxsw_sp); |
| 3777 | mlxsw_sp_traps_fini(mlxsw_sp); | 3960 | mlxsw_sp_traps_fini(mlxsw_sp); |
| @@ -3779,7 +3962,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) | |||
| 3779 | mlxsw_sp_kvdl_fini(mlxsw_sp); | 3962 | mlxsw_sp_kvdl_fini(mlxsw_sp); |
| 3780 | } | 3963 | } |
| 3781 | 3964 | ||
| 3782 | static const struct mlxsw_config_profile mlxsw_sp_config_profile = { | 3965 | static const struct mlxsw_config_profile mlxsw_sp1_config_profile = { |
| 3783 | .used_max_mid = 1, | 3966 | .used_max_mid = 1, |
| 3784 | .max_mid = MLXSW_SP_MID_MAX, | 3967 | .max_mid = MLXSW_SP_MID_MAX, |
| 3785 | .used_flood_tables = 1, | 3968 | .used_flood_tables = 1, |
| @@ -3805,6 +3988,28 @@ static const struct mlxsw_config_profile mlxsw_sp_config_profile = { | |||
| 3805 | }, | 3988 | }, |
| 3806 | }; | 3989 | }; |
| 3807 | 3990 | ||
| 3991 | static const struct mlxsw_config_profile mlxsw_sp2_config_profile = { | ||
| 3992 | .used_max_mid = 1, | ||
| 3993 | .max_mid = MLXSW_SP_MID_MAX, | ||
| 3994 | .used_flood_tables = 1, | ||
| 3995 | .used_flood_mode = 1, | ||
| 3996 | .flood_mode = 3, | ||
| 3997 | .max_fid_offset_flood_tables = 3, | ||
| 3998 | .fid_offset_flood_table_size = VLAN_N_VID - 1, | ||
| 3999 | .max_fid_flood_tables = 3, | ||
| 4000 | .fid_flood_table_size = MLXSW_SP_FID_8021D_MAX, | ||
| 4001 | .used_max_ib_mc = 1, | ||
| 4002 | .max_ib_mc = 0, | ||
| 4003 | .used_max_pkey = 1, | ||
| 4004 | .max_pkey = 0, | ||
| 4005 | .swid_config = { | ||
| 4006 | { | ||
| 4007 | .used_type = 1, | ||
| 4008 | .type = MLXSW_PORT_SWID_TYPE_ETH, | ||
| 4009 | } | ||
| 4010 | }, | ||
| 4011 | }; | ||
| 4012 | |||
| 3808 | static void | 4013 | static void |
| 3809 | mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, | 4014 | mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, |
| 3810 | struct devlink_resource_size_params *kvd_size_params, | 4015 | struct devlink_resource_size_params *kvd_size_params, |
| @@ -3841,7 +4046,7 @@ mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, | |||
| 3841 | DEVLINK_RESOURCE_UNIT_ENTRY); | 4046 | DEVLINK_RESOURCE_UNIT_ENTRY); |
| 3842 | } | 4047 | } |
| 3843 | 4048 | ||
| 3844 | static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | 4049 | static int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core) |
| 3845 | { | 4050 | { |
| 3846 | struct devlink *devlink = priv_to_devlink(mlxsw_core); | 4051 | struct devlink *devlink = priv_to_devlink(mlxsw_core); |
| 3847 | struct devlink_resource_size_params hash_single_size_params; | 4052 | struct devlink_resource_size_params hash_single_size_params; |
| @@ -3852,7 +4057,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
| 3852 | const struct mlxsw_config_profile *profile; | 4057 | const struct mlxsw_config_profile *profile; |
| 3853 | int err; | 4058 | int err; |
| 3854 | 4059 | ||
| 3855 | profile = &mlxsw_sp_config_profile; | 4060 | profile = &mlxsw_sp1_config_profile; |
| 3856 | if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) | 4061 | if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) |
| 3857 | return -EIO; | 4062 | return -EIO; |
| 3858 | 4063 | ||
| @@ -3878,7 +4083,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
| 3878 | if (err) | 4083 | if (err) |
| 3879 | return err; | 4084 | return err; |
| 3880 | 4085 | ||
| 3881 | err = mlxsw_sp_kvdl_resources_register(mlxsw_core); | 4086 | err = mlxsw_sp1_kvdl_resources_register(mlxsw_core); |
| 3882 | if (err) | 4087 | if (err) |
| 3883 | return err; | 4088 | return err; |
| 3884 | 4089 | ||
| @@ -3907,6 +4112,16 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
| 3907 | return 0; | 4112 | return 0; |
| 3908 | } | 4113 | } |
| 3909 | 4114 | ||
| 4115 | static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) | ||
| 4116 | { | ||
| 4117 | return mlxsw_sp1_resources_kvd_register(mlxsw_core); | ||
| 4118 | } | ||
| 4119 | |||
| 4120 | static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) | ||
| 4121 | { | ||
| 4122 | return 0; | ||
| 4123 | } | ||
| 4124 | |||
| 3910 | static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, | 4125 | static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, |
| 3911 | const struct mlxsw_config_profile *profile, | 4126 | const struct mlxsw_config_profile *profile, |
| 3912 | u64 *p_single_size, u64 *p_double_size, | 4127 | u64 *p_single_size, u64 *p_double_size, |
| @@ -3962,10 +4177,10 @@ static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, | |||
| 3962 | return 0; | 4177 | return 0; |
| 3963 | } | 4178 | } |
| 3964 | 4179 | ||
| 3965 | static struct mlxsw_driver mlxsw_sp_driver = { | 4180 | static struct mlxsw_driver mlxsw_sp1_driver = { |
| 3966 | .kind = mlxsw_sp_driver_name, | 4181 | .kind = mlxsw_sp1_driver_name, |
| 3967 | .priv_size = sizeof(struct mlxsw_sp), | 4182 | .priv_size = sizeof(struct mlxsw_sp), |
| 3968 | .init = mlxsw_sp_init, | 4183 | .init = mlxsw_sp1_init, |
| 3969 | .fini = mlxsw_sp_fini, | 4184 | .fini = mlxsw_sp_fini, |
| 3970 | .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, | 4185 | .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, |
| 3971 | .port_split = mlxsw_sp_port_split, | 4186 | .port_split = mlxsw_sp_port_split, |
| @@ -3981,10 +4196,35 @@ static struct mlxsw_driver mlxsw_sp_driver = { | |||
| 3981 | .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, | 4196 | .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, |
| 3982 | .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, | 4197 | .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, |
| 3983 | .txhdr_construct = mlxsw_sp_txhdr_construct, | 4198 | .txhdr_construct = mlxsw_sp_txhdr_construct, |
| 3984 | .resources_register = mlxsw_sp_resources_register, | 4199 | .resources_register = mlxsw_sp1_resources_register, |
| 3985 | .kvd_sizes_get = mlxsw_sp_kvd_sizes_get, | 4200 | .kvd_sizes_get = mlxsw_sp_kvd_sizes_get, |
| 3986 | .txhdr_len = MLXSW_TXHDR_LEN, | 4201 | .txhdr_len = MLXSW_TXHDR_LEN, |
| 3987 | .profile = &mlxsw_sp_config_profile, | 4202 | .profile = &mlxsw_sp1_config_profile, |
| 4203 | .res_query_enabled = true, | ||
| 4204 | }; | ||
| 4205 | |||
| 4206 | static struct mlxsw_driver mlxsw_sp2_driver = { | ||
| 4207 | .kind = mlxsw_sp2_driver_name, | ||
| 4208 | .priv_size = sizeof(struct mlxsw_sp), | ||
| 4209 | .init = mlxsw_sp2_init, | ||
| 4210 | .fini = mlxsw_sp_fini, | ||
| 4211 | .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, | ||
| 4212 | .port_split = mlxsw_sp_port_split, | ||
| 4213 | .port_unsplit = mlxsw_sp_port_unsplit, | ||
| 4214 | .sb_pool_get = mlxsw_sp_sb_pool_get, | ||
| 4215 | .sb_pool_set = mlxsw_sp_sb_pool_set, | ||
| 4216 | .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, | ||
| 4217 | .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, | ||
| 4218 | .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, | ||
| 4219 | .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, | ||
| 4220 | .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, | ||
| 4221 | .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, | ||
| 4222 | .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, | ||
| 4223 | .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, | ||
| 4224 | .txhdr_construct = mlxsw_sp_txhdr_construct, | ||
| 4225 | .resources_register = mlxsw_sp2_resources_register, | ||
| 4226 | .txhdr_len = MLXSW_TXHDR_LEN, | ||
| 4227 | .profile = &mlxsw_sp2_config_profile, | ||
| 3988 | .res_query_enabled = true, | 4228 | .res_query_enabled = true, |
| 3989 | }; | 4229 | }; |
| 3990 | 4230 | ||
| @@ -4377,6 +4617,41 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) | |||
| 4377 | mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); | 4617 | mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); |
| 4378 | } | 4618 | } |
| 4379 | 4619 | ||
| 4620 | static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev) | ||
| 4621 | { | ||
| 4622 | unsigned int num_vxlans = 0; | ||
| 4623 | struct net_device *dev; | ||
| 4624 | struct list_head *iter; | ||
| 4625 | |||
| 4626 | netdev_for_each_lower_dev(br_dev, dev, iter) { | ||
| 4627 | if (netif_is_vxlan(dev)) | ||
| 4628 | num_vxlans++; | ||
| 4629 | } | ||
| 4630 | |||
| 4631 | return num_vxlans > 1; | ||
| 4632 | } | ||
| 4633 | |||
| 4634 | static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev, | ||
| 4635 | struct netlink_ext_ack *extack) | ||
| 4636 | { | ||
| 4637 | if (br_multicast_enabled(br_dev)) { | ||
| 4638 | NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device"); | ||
| 4639 | return false; | ||
| 4640 | } | ||
| 4641 | |||
| 4642 | if (br_vlan_enabled(br_dev)) { | ||
| 4643 | NL_SET_ERR_MSG_MOD(extack, "VLAN filtering can not be enabled on a bridge with a VxLAN device"); | ||
| 4644 | return false; | ||
| 4645 | } | ||
| 4646 | |||
| 4647 | if (mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { | ||
| 4648 | NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); | ||
| 4649 | return false; | ||
| 4650 | } | ||
| 4651 | |||
| 4652 | return true; | ||
| 4653 | } | ||
| 4654 | |||
| 4380 | static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, | 4655 | static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, |
| 4381 | struct net_device *dev, | 4656 | struct net_device *dev, |
| 4382 | unsigned long event, void *ptr) | 4657 | unsigned long event, void *ptr) |
| @@ -4399,12 +4674,18 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, | |||
| 4399 | if (!is_vlan_dev(upper_dev) && | 4674 | if (!is_vlan_dev(upper_dev) && |
| 4400 | !netif_is_lag_master(upper_dev) && | 4675 | !netif_is_lag_master(upper_dev) && |
| 4401 | !netif_is_bridge_master(upper_dev) && | 4676 | !netif_is_bridge_master(upper_dev) && |
| 4402 | !netif_is_ovs_master(upper_dev)) { | 4677 | !netif_is_ovs_master(upper_dev) && |
| 4678 | !netif_is_macvlan(upper_dev)) { | ||
| 4403 | NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); | 4679 | NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); |
| 4404 | return -EINVAL; | 4680 | return -EINVAL; |
| 4405 | } | 4681 | } |
| 4406 | if (!info->linking) | 4682 | if (!info->linking) |
| 4407 | break; | 4683 | break; |
| 4684 | if (netif_is_bridge_master(upper_dev) && | ||
| 4685 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && | ||
| 4686 | mlxsw_sp_bridge_has_vxlan(upper_dev) && | ||
| 4687 | !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) | ||
| 4688 | return -EOPNOTSUPP; | ||
| 4408 | if (netdev_has_any_upper_dev(upper_dev) && | 4689 | if (netdev_has_any_upper_dev(upper_dev) && |
| 4409 | (!netif_is_bridge_master(upper_dev) || | 4690 | (!netif_is_bridge_master(upper_dev) || |
| 4410 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, | 4691 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, |
| @@ -4425,6 +4706,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, | |||
| 4425 | NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port"); | 4706 | NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port"); |
| 4426 | return -EINVAL; | 4707 | return -EINVAL; |
| 4427 | } | 4708 | } |
| 4709 | if (netif_is_macvlan(upper_dev) && | ||
| 4710 | !mlxsw_sp_rif_find_by_dev(mlxsw_sp, lower_dev)) { | ||
| 4711 | NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); | ||
| 4712 | return -EOPNOTSUPP; | ||
| 4713 | } | ||
| 4428 | if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) { | 4714 | if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) { |
| 4429 | NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN"); | 4715 | NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN"); |
| 4430 | return -EINVAL; | 4716 | return -EINVAL; |
| @@ -4463,6 +4749,9 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, | |||
| 4463 | err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); | 4749 | err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); |
| 4464 | else | 4750 | else |
| 4465 | mlxsw_sp_port_ovs_leave(mlxsw_sp_port); | 4751 | mlxsw_sp_port_ovs_leave(mlxsw_sp_port); |
| 4752 | } else if (netif_is_macvlan(upper_dev)) { | ||
| 4753 | if (!info->linking) | ||
| 4754 | mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); | ||
| 4466 | } | 4755 | } |
| 4467 | break; | 4756 | break; |
| 4468 | } | 4757 | } |
| @@ -4547,12 +4836,18 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, | |||
| 4547 | switch (event) { | 4836 | switch (event) { |
| 4548 | case NETDEV_PRECHANGEUPPER: | 4837 | case NETDEV_PRECHANGEUPPER: |
| 4549 | upper_dev = info->upper_dev; | 4838 | upper_dev = info->upper_dev; |
| 4550 | if (!netif_is_bridge_master(upper_dev)) { | 4839 | if (!netif_is_bridge_master(upper_dev) && |
| 4551 | NL_SET_ERR_MSG_MOD(extack, "VLAN devices only support bridge and VRF uppers"); | 4840 | !netif_is_macvlan(upper_dev)) { |
| 4841 | NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); | ||
| 4552 | return -EINVAL; | 4842 | return -EINVAL; |
| 4553 | } | 4843 | } |
| 4554 | if (!info->linking) | 4844 | if (!info->linking) |
| 4555 | break; | 4845 | break; |
| 4846 | if (netif_is_bridge_master(upper_dev) && | ||
| 4847 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && | ||
| 4848 | mlxsw_sp_bridge_has_vxlan(upper_dev) && | ||
| 4849 | !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) | ||
| 4850 | return -EOPNOTSUPP; | ||
| 4556 | if (netdev_has_any_upper_dev(upper_dev) && | 4851 | if (netdev_has_any_upper_dev(upper_dev) && |
| 4557 | (!netif_is_bridge_master(upper_dev) || | 4852 | (!netif_is_bridge_master(upper_dev) || |
| 4558 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, | 4853 | !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, |
| @@ -4560,6 +4855,11 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, | |||
| 4560 | NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported"); | 4855 | NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported"); |
| 4561 | return -EINVAL; | 4856 | return -EINVAL; |
| 4562 | } | 4857 | } |
| 4858 | if (netif_is_macvlan(upper_dev) && | ||
| 4859 | !mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) { | ||
| 4860 | NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); | ||
| 4861 | return -EOPNOTSUPP; | ||
| 4862 | } | ||
| 4563 | break; | 4863 | break; |
| 4564 | case NETDEV_CHANGEUPPER: | 4864 | case NETDEV_CHANGEUPPER: |
| 4565 | upper_dev = info->upper_dev; | 4865 | upper_dev = info->upper_dev; |
| @@ -4573,6 +4873,9 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, | |||
| 4573 | mlxsw_sp_port_bridge_leave(mlxsw_sp_port, | 4873 | mlxsw_sp_port_bridge_leave(mlxsw_sp_port, |
| 4574 | vlan_dev, | 4874 | vlan_dev, |
| 4575 | upper_dev); | 4875 | upper_dev); |
| 4876 | } else if (netif_is_macvlan(upper_dev)) { | ||
| 4877 | if (!info->linking) | ||
| 4878 | mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); | ||
| 4576 | } else { | 4879 | } else { |
| 4577 | err = -EINVAL; | 4880 | err = -EINVAL; |
| 4578 | WARN_ON(1); | 4881 | WARN_ON(1); |
| @@ -4622,6 +4925,66 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev, | |||
| 4622 | return 0; | 4925 | return 0; |
| 4623 | } | 4926 | } |
| 4624 | 4927 | ||
| 4928 | static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, | ||
| 4929 | unsigned long event, void *ptr) | ||
| 4930 | { | ||
| 4931 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(br_dev); | ||
| 4932 | struct netdev_notifier_changeupper_info *info = ptr; | ||
| 4933 | struct netlink_ext_ack *extack; | ||
| 4934 | struct net_device *upper_dev; | ||
| 4935 | |||
| 4936 | if (!mlxsw_sp) | ||
| 4937 | return 0; | ||
| 4938 | |||
| 4939 | extack = netdev_notifier_info_to_extack(&info->info); | ||
| 4940 | |||
| 4941 | switch (event) { | ||
| 4942 | case NETDEV_PRECHANGEUPPER: | ||
| 4943 | upper_dev = info->upper_dev; | ||
| 4944 | if (!is_vlan_dev(upper_dev) && !netif_is_macvlan(upper_dev)) { | ||
| 4945 | NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); | ||
| 4946 | return -EOPNOTSUPP; | ||
| 4947 | } | ||
| 4948 | if (!info->linking) | ||
| 4949 | break; | ||
| 4950 | if (netif_is_macvlan(upper_dev) && | ||
| 4951 | !mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev)) { | ||
| 4952 | NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); | ||
| 4953 | return -EOPNOTSUPP; | ||
| 4954 | } | ||
| 4955 | break; | ||
| 4956 | case NETDEV_CHANGEUPPER: | ||
| 4957 | upper_dev = info->upper_dev; | ||
| 4958 | if (info->linking) | ||
| 4959 | break; | ||
| 4960 | if (is_vlan_dev(upper_dev)) | ||
| 4961 | mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev); | ||
| 4962 | if (netif_is_macvlan(upper_dev)) | ||
| 4963 | mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); | ||
| 4964 | break; | ||
| 4965 | } | ||
| 4966 | |||
| 4967 | return 0; | ||
| 4968 | } | ||
| 4969 | |||
| 4970 | static int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev, | ||
| 4971 | unsigned long event, void *ptr) | ||
| 4972 | { | ||
| 4973 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev); | ||
| 4974 | struct netdev_notifier_changeupper_info *info = ptr; | ||
| 4975 | struct netlink_ext_ack *extack; | ||
| 4976 | |||
| 4977 | if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER) | ||
| 4978 | return 0; | ||
| 4979 | |||
| 4980 | extack = netdev_notifier_info_to_extack(&info->info); | ||
| 4981 | |||
| 4982 | /* VRF enslavement is handled in mlxsw_sp_netdevice_vrf_event() */ | ||
| 4983 | NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); | ||
| 4984 | |||
| 4985 | return -EOPNOTSUPP; | ||
| 4986 | } | ||
| 4987 | |||
| 4625 | static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr) | 4988 | static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr) |
| 4626 | { | 4989 | { |
| 4627 | struct netdev_notifier_changeupper_info *info = ptr; | 4990 | struct netdev_notifier_changeupper_info *info = ptr; |
| @@ -4631,6 +4994,63 @@ static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr) | |||
| 4631 | return netif_is_l3_master(info->upper_dev); | 4994 | return netif_is_l3_master(info->upper_dev); |
| 4632 | } | 4995 | } |
| 4633 | 4996 | ||
| 4997 | static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp, | ||
| 4998 | struct net_device *dev, | ||
| 4999 | unsigned long event, void *ptr) | ||
| 5000 | { | ||
| 5001 | struct netdev_notifier_changeupper_info *cu_info; | ||
| 5002 | struct netdev_notifier_info *info = ptr; | ||
| 5003 | struct netlink_ext_ack *extack; | ||
| 5004 | struct net_device *upper_dev; | ||
| 5005 | |||
| 5006 | extack = netdev_notifier_info_to_extack(info); | ||
| 5007 | |||
| 5008 | switch (event) { | ||
| 5009 | case NETDEV_CHANGEUPPER: | ||
| 5010 | cu_info = container_of(info, | ||
| 5011 | struct netdev_notifier_changeupper_info, | ||
| 5012 | info); | ||
| 5013 | upper_dev = cu_info->upper_dev; | ||
| 5014 | if (!netif_is_bridge_master(upper_dev)) | ||
| 5015 | return 0; | ||
| 5016 | if (!mlxsw_sp_lower_get(upper_dev)) | ||
| 5017 | return 0; | ||
| 5018 | if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) | ||
| 5019 | return -EOPNOTSUPP; | ||
| 5020 | if (cu_info->linking) { | ||
| 5021 | if (!netif_running(dev)) | ||
| 5022 | return 0; | ||
| 5023 | return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, | ||
| 5024 | dev, extack); | ||
| 5025 | } else { | ||
| 5026 | mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); | ||
| 5027 | } | ||
| 5028 | break; | ||
| 5029 | case NETDEV_PRE_UP: | ||
| 5030 | upper_dev = netdev_master_upper_dev_get(dev); | ||
| 5031 | if (!upper_dev) | ||
| 5032 | return 0; | ||
| 5033 | if (!netif_is_bridge_master(upper_dev)) | ||
| 5034 | return 0; | ||
| 5035 | if (!mlxsw_sp_lower_get(upper_dev)) | ||
| 5036 | return 0; | ||
| 5037 | return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, | ||
| 5038 | extack); | ||
| 5039 | case NETDEV_DOWN: | ||
| 5040 | upper_dev = netdev_master_upper_dev_get(dev); | ||
| 5041 | if (!upper_dev) | ||
| 5042 | return 0; | ||
| 5043 | if (!netif_is_bridge_master(upper_dev)) | ||
| 5044 | return 0; | ||
| 5045 | if (!mlxsw_sp_lower_get(upper_dev)) | ||
| 5046 | return 0; | ||
| 5047 | mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); | ||
| 5048 | break; | ||
| 5049 | } | ||
| 5050 | |||
| 5051 | return 0; | ||
| 5052 | } | ||
| 5053 | |||
| 4634 | static int mlxsw_sp_netdevice_event(struct notifier_block *nb, | 5054 | static int mlxsw_sp_netdevice_event(struct notifier_block *nb, |
| 4635 | unsigned long event, void *ptr) | 5055 | unsigned long event, void *ptr) |
| 4636 | { | 5056 | { |
| @@ -4647,6 +5067,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb, | |||
| 4647 | } | 5067 | } |
| 4648 | mlxsw_sp_span_respin(mlxsw_sp); | 5068 | mlxsw_sp_span_respin(mlxsw_sp); |
| 4649 | 5069 | ||
| 5070 | if (netif_is_vxlan(dev)) | ||
| 5071 | err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr); | ||
| 4650 | if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev)) | 5072 | if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev)) |
| 4651 | err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev, | 5073 | err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev, |
| 4652 | event, ptr); | 5074 | event, ptr); |
| @@ -4663,6 +5085,10 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb, | |||
| 4663 | err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); | 5085 | err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); |
| 4664 | else if (is_vlan_dev(dev)) | 5086 | else if (is_vlan_dev(dev)) |
| 4665 | err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr); | 5087 | err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr); |
| 5088 | else if (netif_is_bridge_master(dev)) | ||
| 5089 | err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr); | ||
| 5090 | else if (netif_is_macvlan(dev)) | ||
| 5091 | err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr); | ||
| 4666 | 5092 | ||
| 4667 | return notifier_from_errno(err); | 5093 | return notifier_from_errno(err); |
| 4668 | } | 5094 | } |
| @@ -4683,14 +5109,24 @@ static struct notifier_block mlxsw_sp_inet6addr_nb __read_mostly = { | |||
| 4683 | .notifier_call = mlxsw_sp_inet6addr_event, | 5109 | .notifier_call = mlxsw_sp_inet6addr_event, |
| 4684 | }; | 5110 | }; |
| 4685 | 5111 | ||
| 4686 | static const struct pci_device_id mlxsw_sp_pci_id_table[] = { | 5112 | static const struct pci_device_id mlxsw_sp1_pci_id_table[] = { |
| 4687 | {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0}, | 5113 | {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0}, |
| 4688 | {0, }, | 5114 | {0, }, |
| 4689 | }; | 5115 | }; |
| 4690 | 5116 | ||
| 4691 | static struct pci_driver mlxsw_sp_pci_driver = { | 5117 | static struct pci_driver mlxsw_sp1_pci_driver = { |
| 4692 | .name = mlxsw_sp_driver_name, | 5118 | .name = mlxsw_sp1_driver_name, |
| 4693 | .id_table = mlxsw_sp_pci_id_table, | 5119 | .id_table = mlxsw_sp1_pci_id_table, |
| 5120 | }; | ||
| 5121 | |||
| 5122 | static const struct pci_device_id mlxsw_sp2_pci_id_table[] = { | ||
| 5123 | {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0}, | ||
| 5124 | {0, }, | ||
| 5125 | }; | ||
| 5126 | |||
| 5127 | static struct pci_driver mlxsw_sp2_pci_driver = { | ||
| 5128 | .name = mlxsw_sp2_driver_name, | ||
| 5129 | .id_table = mlxsw_sp2_pci_id_table, | ||
| 4694 | }; | 5130 | }; |
| 4695 | 5131 | ||
| 4696 | static int __init mlxsw_sp_module_init(void) | 5132 | static int __init mlxsw_sp_module_init(void) |
| @@ -4702,19 +5138,31 @@ static int __init mlxsw_sp_module_init(void) | |||
| 4702 | register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); | 5138 | register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); |
| 4703 | register_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); | 5139 | register_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); |
| 4704 | 5140 | ||
| 4705 | err = mlxsw_core_driver_register(&mlxsw_sp_driver); | 5141 | err = mlxsw_core_driver_register(&mlxsw_sp1_driver); |
| 5142 | if (err) | ||
| 5143 | goto err_sp1_core_driver_register; | ||
| 5144 | |||
| 5145 | err = mlxsw_core_driver_register(&mlxsw_sp2_driver); | ||
| 5146 | if (err) | ||
| 5147 | goto err_sp2_core_driver_register; | ||
| 5148 | |||
| 5149 | err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver); | ||
| 4706 | if (err) | 5150 | if (err) |
| 4707 | goto err_core_driver_register; | 5151 | goto err_sp1_pci_driver_register; |
| 4708 | 5152 | ||
| 4709 | err = mlxsw_pci_driver_register(&mlxsw_sp_pci_driver); | 5153 | err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver); |
| 4710 | if (err) | 5154 | if (err) |
| 4711 | goto err_pci_driver_register; | 5155 | goto err_sp2_pci_driver_register; |
| 4712 | 5156 | ||
| 4713 | return 0; | 5157 | return 0; |
| 4714 | 5158 | ||
| 4715 | err_pci_driver_register: | 5159 | err_sp2_pci_driver_register: |
| 4716 | mlxsw_core_driver_unregister(&mlxsw_sp_driver); | 5160 | mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); |
| 4717 | err_core_driver_register: | 5161 | err_sp1_pci_driver_register: |
| 5162 | mlxsw_core_driver_unregister(&mlxsw_sp2_driver); | ||
| 5163 | err_sp2_core_driver_register: | ||
| 5164 | mlxsw_core_driver_unregister(&mlxsw_sp1_driver); | ||
| 5165 | err_sp1_core_driver_register: | ||
| 4718 | unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); | 5166 | unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); |
| 4719 | unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); | 5167 | unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); |
| 4720 | unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb); | 5168 | unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb); |
| @@ -4724,8 +5172,10 @@ err_core_driver_register: | |||
| 4724 | 5172 | ||
| 4725 | static void __exit mlxsw_sp_module_exit(void) | 5173 | static void __exit mlxsw_sp_module_exit(void) |
| 4726 | { | 5174 | { |
| 4727 | mlxsw_pci_driver_unregister(&mlxsw_sp_pci_driver); | 5175 | mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); |
| 4728 | mlxsw_core_driver_unregister(&mlxsw_sp_driver); | 5176 | mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); |
| 5177 | mlxsw_core_driver_unregister(&mlxsw_sp2_driver); | ||
| 5178 | mlxsw_core_driver_unregister(&mlxsw_sp1_driver); | ||
| 4729 | unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); | 5179 | unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb); |
| 4730 | unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); | 5180 | unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); |
| 4731 | unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb); | 5181 | unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb); |
| @@ -4738,5 +5188,6 @@ module_exit(mlxsw_sp_module_exit); | |||
| 4738 | MODULE_LICENSE("Dual BSD/GPL"); | 5188 | MODULE_LICENSE("Dual BSD/GPL"); |
| 4739 | MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); | 5189 | MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); |
| 4740 | MODULE_DESCRIPTION("Mellanox Spectrum driver"); | 5190 | MODULE_DESCRIPTION("Mellanox Spectrum driver"); |
| 4741 | MODULE_DEVICE_TABLE(pci, mlxsw_sp_pci_id_table); | 5191 | MODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table); |
| 4742 | MODULE_FIRMWARE(MLXSW_SP_FW_FILENAME); | 5192 | MODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table); |
| 5193 | MODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME); | ||
