Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ethernet: ti: introduce cpsw switchdev based driver part 2 - switch

CPSW switchdev based driver which is operating in dual-emac mode by
default, thus working as 2 individual network interfaces. The Switch mode
can be enabled by configuring devlink driver parameter "switch_mode" to 1:

devlink dev param set platform/48484000.switch \
name switch_mode value 1 cmode runtime

This can be done regardless of the state of Port's netdevs - UP/DOWN, but
Port's netdev devices have to be UP before joining the bridge to avoid
overwriting of bridge configuration as CPSW switch driver completely
reloads its configuration when first Port changes its state to UP.
When the both interfaces joined the bridge - CPSW switch driver will start
marking packets with offload_fwd_mark flag unless "ale_bypass=0".

All configuration is implemented via switchdev API and notifiers.
Supported:
- SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
- SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: BR_MCAST_FLOOD
- SWITCHDEV_ATTR_ID_PORT_STP_STATE
- SWITCHDEV_OBJ_ID_PORT_VLAN
- SWITCHDEV_OBJ_ID_PORT_MDB
- SWITCHDEV_OBJ_ID_HOST_MDB

Hence CPSW switchdev driver supports:
- FDB offloading
- MDB offloading
- VLAN filtering and offloading
- STP

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ilias Apalodimas and committed by
David S. Miller
111cf1ab ed3525ed

+993 -9
+1 -1
drivers/net/ethernet/ti/Makefile
··· 16 16 obj-$(CONFIG_TI_CPSW) += ti_cpsw.o 17 17 ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o 18 18 obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o 19 - ti_cpsw_new-y := cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o 19 + ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o 20 20 21 21 obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o 22 22 keystone_netcp-y := netcp_core.o cpsw_ale.o
+383 -8
drivers/net/ethernet/ti/cpsw_new.c
··· 35 35 #include "cpsw_ale.h" 36 36 #include "cpsw_priv.h" 37 37 #include "cpsw_sl.h" 38 + #include "cpsw_switchdev.h" 38 39 #include "cpts.h" 39 40 #include "davinci_cpdma.h" 40 41 ··· 52 51 53 52 enum cpsw_devlink_param_id { 54 53 CPSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 54 + CPSW_DL_PARAM_SWITCH_MODE, 55 55 CPSW_DL_PARAM_ALE_BYPASS, 56 56 }; 57 57 ··· 68 66 return priv->emac_port - 1; 69 67 } 70 68 69 + static bool cpsw_is_switch_en(struct cpsw_common *cpsw) 70 + { 71 + return !cpsw->data.dual_emac; 72 + } 73 + 71 74 static void cpsw_set_promiscious(struct net_device *ndev, bool enable) 72 75 { 73 76 struct cpsw_common *cpsw = ndev_to_cpsw(ndev); 74 77 bool enable_uni = false; 75 78 int i; 79 + 80 + if (cpsw_is_switch_en(cpsw)) 81 + return; 76 82 77 83 /* Enabling promiscuous mode for one interface will be 78 84 * common for both the interface as the interface shares ··· 369 359 goto requeue; 370 360 } 371 361 362 + skb->offload_fwd_mark = priv->offload_fwd_mark; 372 363 skb_reserve(skb, headroom); 373 364 skb_put(skb, len); 374 365 skb->dev = ndev; ··· 400 389 } 401 390 } 402 391 403 - static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, 404 - unsigned short vid) 392 + static int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, 393 + unsigned short vid) 405 394 { 406 395 struct cpsw_common *cpsw = priv->cpsw; 407 396 int unreg_mcast_mask = 0; ··· 445 434 struct cpsw_priv *priv = netdev_priv(ndev); 446 435 struct cpsw_common *cpsw = priv->cpsw; 447 436 int ret, i; 437 + 438 + if (cpsw_is_switch_en(cpsw)) { 439 + dev_dbg(cpsw->dev, ".ndo_vlan_rx_add_vid called in switch mode\n"); 440 + return 0; 441 + } 448 442 449 443 if (vid == cpsw->data.default_vlan) 450 444 return 0; ··· 505 489 cpsw_cbs_resume(&cpsw->slaves[priv->emac_port - 1], priv); 506 490 } 507 491 508 - static void cpsw_init_host_port_dual_mac(struct cpsw_priv *priv) 492 + static void cpsw_init_stp_ale_entry(struct cpsw_common *cpsw) 509 493 { 510 - struct cpsw_common *cpsw = priv->cpsw; 494 + char stpa[] = {0x01, 0x80, 0xc2, 0x0, 0x0, 0x0}; 495 + 496 + cpsw_ale_add_mcast(cpsw->ale, stpa, 497 + ALE_PORT_HOST, ALE_SUPER, 0, 498 + ALE_MCAST_BLOCK_LEARN_FWD); 499 + } 500 + 501 + static void cpsw_init_host_port_switch(struct cpsw_common *cpsw) 502 + { 503 + int vlan = cpsw->data.default_vlan; 504 + 505 + writel(CPSW_FIFO_NORMAL_MODE, &cpsw->host_port_regs->tx_in_ctl); 506 + 507 + writel(vlan, &cpsw->host_port_regs->port_vlan); 508 + 509 + cpsw_ale_add_vlan(cpsw->ale, vlan, ALE_ALL_PORTS, 510 + ALE_ALL_PORTS, ALE_ALL_PORTS, 511 + ALE_PORT_1 | ALE_PORT_2); 512 + 513 + cpsw_init_stp_ale_entry(cpsw); 514 + 515 + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 1); 516 + dev_dbg(cpsw->dev, "Set P0_UNI_FLOOD\n"); 517 + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 0); 518 + } 519 + 520 + static void cpsw_init_host_port_dual_mac(struct cpsw_common *cpsw) 521 + { 511 522 int vlan = cpsw->data.default_vlan; 512 523 513 524 writel(CPSW_FIFO_DUAL_MAC_MODE, &cpsw->host_port_regs->tx_in_ctl); ··· 579 536 /* Enable internal fifo flow control */ 580 537 writel(0x7, &cpsw->regs->flow_control); 581 538 582 - cpsw_init_host_port_dual_mac(priv); 539 + if (cpsw_is_switch_en(cpsw)) 540 + cpsw_init_host_port_switch(cpsw); 541 + else 542 + cpsw_init_host_port_dual_mac(cpsw); 583 543 584 544 cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, 585 545 ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); ··· 612 566 /* learning make no sense in dual_mac mode */ 613 567 cpsw_ale_control_set(cpsw->ale, priv->emac_port, 614 568 ALE_PORT_NOLEARN, 1); 569 + } 570 + 571 + static void cpsw_port_add_switch_def_ale_entries(struct cpsw_priv *priv, 572 + struct cpsw_slave *slave) 573 + { 574 + u32 port_mask = 1 << priv->emac_port | ALE_PORT_HOST; 575 + struct cpsw_common *cpsw = priv->cpsw; 576 + u32 reg; 577 + 578 + cpsw_ale_control_set(cpsw->ale, priv->emac_port, 579 + ALE_PORT_DROP_UNKNOWN_VLAN, 0); 580 + cpsw_ale_control_set(cpsw->ale, priv->emac_port, 581 + ALE_PORT_NOLEARN, 0); 582 + /* disabling SA_UPDATE required to make stp work, without this setting 583 + * Host MAC addresses will jump between ports. 584 + * As per TRM MAC address can be defined as unicast supervisory (super) 585 + * by setting both (ALE_BLOCKED | ALE_SECURE) which should prevent 586 + * SA_UPDATE, but HW seems works incorrectly and setting ALE_SECURE 587 + * causes STP packets to be dropped due to ingress filter 588 + * if (source address found) and (secure) and 589 + * (receive port number != port_number)) 590 + * then discard the packet 591 + */ 592 + cpsw_ale_control_set(cpsw->ale, priv->emac_port, 593 + ALE_PORT_NO_SA_UPDATE, 1); 594 + 595 + cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, 596 + port_mask, ALE_VLAN, slave->port_vlan, 597 + ALE_MCAST_FWD_2); 598 + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, 599 + HOST_PORT_NUM, ALE_VLAN, slave->port_vlan); 600 + 601 + reg = (cpsw->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : 602 + CPSW2_PORT_VLAN; 603 + slave_write(slave, slave->port_vlan, reg); 615 604 } 616 605 617 606 static void cpsw_adjust_link(struct net_device *ndev) ··· 761 680 762 681 slave->mac_control = 0; /* no link yet */ 763 682 764 - cpsw_port_add_dual_emac_def_ale_entries(priv, slave); 683 + if (cpsw_is_switch_en(cpsw)) 684 + cpsw_port_add_switch_def_ale_entries(priv, slave); 685 + else 686 + cpsw_port_add_dual_emac_def_ale_entries(priv, slave); 765 687 766 688 if (!slave->data->phy_node) 767 689 dev_err(priv->dev, "no phy found on slave %d\n", ··· 832 748 struct cpsw_common *cpsw = priv->cpsw; 833 749 int ret; 834 750 835 - cpsw_info(priv, ifdown, "starting ndev\n"); 751 + dev_info(priv->dev, "starting ndev. mode: %s\n", 752 + cpsw_is_switch_en(cpsw) ? "switch" : "dual_mac"); 836 753 ret = pm_runtime_get_sync(cpsw->dev); 837 754 if (ret < 0) { 838 755 pm_runtime_put_noidle(cpsw->dev); ··· 1017 932 int ret; 1018 933 int i; 1019 934 935 + if (cpsw_is_switch_en(cpsw)) { 936 + dev_dbg(cpsw->dev, "ndo del vlan is called in switch mode\n"); 937 + return 0; 938 + } 939 + 1020 940 if (vid == cpsw->data.default_vlan) 1021 941 return 0; 1022 942 ··· 1100 1010 return n - drops; 1101 1011 } 1102 1012 1013 + static int cpsw_get_port_parent_id(struct net_device *ndev, 1014 + struct netdev_phys_item_id *ppid) 1015 + { 1016 + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); 1017 + 1018 + ppid->id_len = sizeof(cpsw->base_mac); 1019 + memcpy(&ppid->id, &cpsw->base_mac, ppid->id_len); 1020 + 1021 + return 0; 1022 + } 1023 + 1103 1024 static const struct net_device_ops cpsw_netdev_ops = { 1104 1025 .ndo_open = cpsw_ndo_open, 1105 1026 .ndo_stop = cpsw_ndo_stop, ··· 1130 1029 .ndo_get_phys_port_name = cpsw_ndo_get_phys_port_name, 1131 1030 .ndo_bpf = cpsw_ndo_bpf, 1132 1031 .ndo_xdp_xmit = cpsw_ndo_xdp_xmit, 1032 + .ndo_get_port_parent_id = cpsw_get_port_parent_id, 1133 1033 }; 1134 1034 1135 1035 static void cpsw_get_drvinfo(struct net_device *ndev, ··· 1460 1358 return ret; 1461 1359 } 1462 1360 1463 - static const struct devlink_ops cpsw_devlink_ops; 1361 + bool cpsw_port_dev_check(const struct net_device *ndev) 1362 + { 1363 + if (ndev->netdev_ops == &cpsw_netdev_ops) { 1364 + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); 1365 + 1366 + return !cpsw->data.dual_emac; 1367 + } 1368 + 1369 + return false; 1370 + } 1371 + 1372 + static void cpsw_port_offload_fwd_mark_update(struct cpsw_common *cpsw) 1373 + { 1374 + int set_val = 0; 1375 + int i; 1376 + 1377 + if (!cpsw->ale_bypass && 1378 + (cpsw->br_members == (ALE_PORT_1 | ALE_PORT_2))) 1379 + set_val = 1; 1380 + 1381 + dev_dbg(cpsw->dev, "set offload_fwd_mark %d\n", set_val); 1382 + 1383 + for (i = 0; i < cpsw->data.slaves; i++) { 1384 + struct net_device *sl_ndev = cpsw->slaves[i].ndev; 1385 + struct cpsw_priv *priv = netdev_priv(sl_ndev); 1386 + 1387 + priv->offload_fwd_mark = set_val; 1388 + } 1389 + } 1390 + 1391 + static int cpsw_netdevice_port_link(struct net_device *ndev, 1392 + struct net_device *br_ndev) 1393 + { 1394 + struct cpsw_priv *priv = netdev_priv(ndev); 1395 + struct cpsw_common *cpsw = priv->cpsw; 1396 + 1397 + if (!cpsw->br_members) { 1398 + cpsw->hw_bridge_dev = br_ndev; 1399 + } else { 1400 + /* This is adding the port to a second bridge, this is 1401 + * unsupported 1402 + */ 1403 + if (cpsw->hw_bridge_dev != br_ndev) 1404 + return -EOPNOTSUPP; 1405 + } 1406 + 1407 + cpsw->br_members |= BIT(priv->emac_port); 1408 + 1409 + cpsw_port_offload_fwd_mark_update(cpsw); 1410 + 1411 + return NOTIFY_DONE; 1412 + } 1413 + 1414 + static void cpsw_netdevice_port_unlink(struct net_device *ndev) 1415 + { 1416 + struct cpsw_priv *priv = netdev_priv(ndev); 1417 + struct cpsw_common *cpsw = priv->cpsw; 1418 + 1419 + cpsw->br_members &= ~BIT(priv->emac_port); 1420 + 1421 + cpsw_port_offload_fwd_mark_update(cpsw); 1422 + 1423 + if (!cpsw->br_members) 1424 + cpsw->hw_bridge_dev = NULL; 1425 + } 1426 + 1427 + /* netdev notifier */ 1428 + static int cpsw_netdevice_event(struct notifier_block *unused, 1429 + unsigned long event, void *ptr) 1430 + { 1431 + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 1432 + struct netdev_notifier_changeupper_info *info; 1433 + int ret = NOTIFY_DONE; 1434 + 1435 + if (!cpsw_port_dev_check(ndev)) 1436 + return NOTIFY_DONE; 1437 + 1438 + switch (event) { 1439 + case NETDEV_CHANGEUPPER: 1440 + info = ptr; 1441 + 1442 + if (netif_is_bridge_master(info->upper_dev)) { 1443 + if (info->linking) 1444 + ret = cpsw_netdevice_port_link(ndev, 1445 + info->upper_dev); 1446 + else 1447 + cpsw_netdevice_port_unlink(ndev); 1448 + } 1449 + break; 1450 + default: 1451 + return NOTIFY_DONE; 1452 + } 1453 + 1454 + return notifier_from_errno(ret); 1455 + } 1456 + 1457 + static struct notifier_block cpsw_netdevice_nb __read_mostly = { 1458 + .notifier_call = cpsw_netdevice_event, 1459 + }; 1460 + 1461 + static int cpsw_register_notifiers(struct cpsw_common *cpsw) 1462 + { 1463 + int ret = 0; 1464 + 1465 + ret = register_netdevice_notifier(&cpsw_netdevice_nb); 1466 + if (ret) { 1467 + dev_err(cpsw->dev, "can't register netdevice notifier\n"); 1468 + return ret; 1469 + } 1470 + 1471 + ret = cpsw_switchdev_register_notifiers(cpsw); 1472 + if (ret) 1473 + unregister_netdevice_notifier(&cpsw_netdevice_nb); 1474 + 1475 + return ret; 1476 + } 1477 + 1478 + static void cpsw_unregister_notifiers(struct cpsw_common *cpsw) 1479 + { 1480 + cpsw_switchdev_unregister_notifiers(cpsw); 1481 + unregister_netdevice_notifier(&cpsw_netdevice_nb); 1482 + } 1483 + 1484 + static const struct devlink_ops cpsw_devlink_ops = { 1485 + }; 1486 + 1487 + static int cpsw_dl_switch_mode_get(struct devlink *dl, u32 id, 1488 + struct devlink_param_gset_ctx *ctx) 1489 + { 1490 + struct cpsw_devlink *dl_priv = devlink_priv(dl); 1491 + struct cpsw_common *cpsw = dl_priv->cpsw; 1492 + 1493 + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); 1494 + 1495 + if (id != CPSW_DL_PARAM_SWITCH_MODE) 1496 + return -EOPNOTSUPP; 1497 + 1498 + ctx->val.vbool = !cpsw->data.dual_emac; 1499 + 1500 + return 0; 1501 + } 1502 + 1503 + static int cpsw_dl_switch_mode_set(struct devlink *dl, u32 id, 1504 + struct devlink_param_gset_ctx *ctx) 1505 + { 1506 + struct cpsw_devlink *dl_priv = devlink_priv(dl); 1507 + struct cpsw_common *cpsw = dl_priv->cpsw; 1508 + int vlan = cpsw->data.default_vlan; 1509 + bool switch_en = ctx->val.vbool; 1510 + bool if_running = false; 1511 + int i; 1512 + 1513 + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); 1514 + 1515 + if (id != CPSW_DL_PARAM_SWITCH_MODE) 1516 + return -EOPNOTSUPP; 1517 + 1518 + if (switch_en == !cpsw->data.dual_emac) 1519 + return 0; 1520 + 1521 + if (!switch_en && cpsw->br_members) { 1522 + dev_err(cpsw->dev, "Remove ports from BR before disabling switch mode\n"); 1523 + return -EINVAL; 1524 + } 1525 + 1526 + rtnl_lock(); 1527 + 1528 + for (i = 0; i < cpsw->data.slaves; i++) { 1529 + struct cpsw_slave *slave = &cpsw->slaves[i]; 1530 + struct net_device *sl_ndev = slave->ndev; 1531 + 1532 + if (!sl_ndev || !netif_running(sl_ndev)) 1533 + continue; 1534 + 1535 + if_running = true; 1536 + } 1537 + 1538 + if (!if_running) { 1539 + /* all ndevs are down */ 1540 + cpsw->data.dual_emac = !switch_en; 1541 + for (i = 0; i < cpsw->data.slaves; i++) { 1542 + struct cpsw_slave *slave = &cpsw->slaves[i]; 1543 + struct net_device *sl_ndev = slave->ndev; 1544 + struct cpsw_priv *priv; 1545 + 1546 + if (!sl_ndev) 1547 + continue; 1548 + 1549 + priv = netdev_priv(sl_ndev); 1550 + if (switch_en) 1551 + vlan = cpsw->data.default_vlan; 1552 + else 1553 + vlan = slave->data->dual_emac_res_vlan; 1554 + slave->port_vlan = vlan; 1555 + } 1556 + goto exit; 1557 + } 1558 + 1559 + if (switch_en) { 1560 + dev_info(cpsw->dev, "Enable switch mode\n"); 1561 + 1562 + /* enable bypass - no forwarding; all traffic goes to Host */ 1563 + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1); 1564 + 1565 + /* clean up ALE table */ 1566 + cpsw_ale_control_set(cpsw->ale, 0, ALE_CLEAR, 1); 1567 + cpsw_ale_control_get(cpsw->ale, 0, ALE_AGEOUT); 1568 + 1569 + cpsw_init_host_port_switch(cpsw); 1570 + 1571 + for (i = 0; i < cpsw->data.slaves; i++) { 1572 + struct cpsw_slave *slave = &cpsw->slaves[i]; 1573 + struct net_device *sl_ndev = slave->ndev; 1574 + struct cpsw_priv *priv; 1575 + 1576 + if (!sl_ndev) 1577 + continue; 1578 + 1579 + priv = netdev_priv(sl_ndev); 1580 + slave->port_vlan = vlan; 1581 + if (netif_running(sl_ndev)) 1582 + cpsw_port_add_switch_def_ale_entries(priv, 1583 + slave); 1584 + } 1585 + 1586 + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 0); 1587 + cpsw->data.dual_emac = false; 1588 + } else { 1589 + dev_info(cpsw->dev, "Disable switch mode\n"); 1590 + 1591 + /* enable bypass - no forwarding; all traffic goes to Host */ 1592 + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1); 1593 + 1594 + cpsw_ale_control_set(cpsw->ale, 0, ALE_CLEAR, 1); 1595 + cpsw_ale_control_get(cpsw->ale, 0, ALE_AGEOUT); 1596 + 1597 + cpsw_init_host_port_dual_mac(cpsw); 1598 + 1599 + for (i = 0; i < cpsw->data.slaves; i++) { 1600 + struct cpsw_slave *slave = &cpsw->slaves[i]; 1601 + struct net_device *sl_ndev = slave->ndev; 1602 + struct cpsw_priv *priv; 1603 + 1604 + if (!sl_ndev) 1605 + continue; 1606 + 1607 + priv = netdev_priv(slave->ndev); 1608 + slave->port_vlan = slave->data->dual_emac_res_vlan; 1609 + cpsw_port_add_dual_emac_def_ale_entries(priv, slave); 1610 + } 1611 + 1612 + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 0); 1613 + cpsw->data.dual_emac = true; 1614 + } 1615 + exit: 1616 + rtnl_unlock(); 1617 + 1618 + return 0; 1619 + } 1464 1620 1465 1621 static int cpsw_dl_ale_ctrl_get(struct devlink *dl, u32 id, 1466 1622 struct devlink_param_gset_ctx *ctx) ··· 1752 1392 case CPSW_DL_PARAM_ALE_BYPASS: 1753 1393 ret = cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1754 1394 ctx->val.vbool); 1395 + if (!ret) { 1396 + cpsw->ale_bypass = ctx->val.vbool; 1397 + cpsw_port_offload_fwd_mark_update(cpsw); 1398 + } 1755 1399 break; 1756 1400 default: 1757 1401 return -EOPNOTSUPP; ··· 1765 1401 } 1766 1402 1767 1403 static const struct devlink_param cpsw_devlink_params[] = { 1404 + DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_SWITCH_MODE, 1405 + "switch_mode", DEVLINK_PARAM_TYPE_BOOL, 1406 + BIT(DEVLINK_PARAM_CMODE_RUNTIME), 1407 + cpsw_dl_switch_mode_get, cpsw_dl_switch_mode_set, 1408 + NULL), 1768 1409 DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_ALE_BYPASS, 1769 1410 "ale_bypass", DEVLINK_PARAM_TYPE_BOOL, 1770 1411 BIT(DEVLINK_PARAM_CMODE_RUNTIME), ··· 1919 1550 1920 1551 cpsw->rx_packet_max = rx_packet_max; 1921 1552 cpsw->descs_pool_size = descs_pool_size; 1553 + eth_random_addr(cpsw->base_mac); 1922 1554 1923 1555 ret = cpsw_init_common(cpsw, ss_regs, ale_ageout, 1924 1556 (u32 __force)ss_res->start + CPSW2_BD_OFFSET, ··· 1974 1604 goto clean_unregister_netdev; 1975 1605 } 1976 1606 1607 + ret = cpsw_register_notifiers(cpsw); 1608 + if (ret) 1609 + goto clean_unregister_netdev; 1610 + 1977 1611 ret = cpsw_register_devlink(cpsw); 1978 1612 if (ret) 1979 1613 goto clean_unregister_notifiers; ··· 2021 1647 return ret; 2022 1648 } 2023 1649 1650 + cpsw_unregister_notifiers(cpsw); 2024 1651 cpsw_unregister_devlink(cpsw); 2025 1652 cpsw_unregister_ports(cpsw); 2026 1653
+5
drivers/net/ethernet/ti/cpsw_priv.h
··· 356 356 int speed; 357 357 int usage_count; 358 358 struct page_pool *page_pool[CPSW_MAX_QUEUES]; 359 + u8 br_members; 360 + struct net_device *hw_bridge_dev; 361 + bool ale_bypass; 362 + u8 base_mac[ETH_ALEN]; 359 363 }; 360 364 361 365 struct cpsw_priv { ··· 380 376 381 377 u32 emac_port; 382 378 struct cpsw_common *cpsw; 379 + int offload_fwd_mark; 383 380 }; 384 381 385 382 #define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw)
+589
drivers/net/ethernet/ti/cpsw_switchdev.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Texas Instruments switchdev Driver 4 + * 5 + * Copyright (C) 2019 Texas Instruments 6 + * 7 + */ 8 + 9 + #include <linux/etherdevice.h> 10 + #include <linux/if_bridge.h> 11 + #include <linux/netdevice.h> 12 + #include <linux/workqueue.h> 13 + #include <net/switchdev.h> 14 + 15 + #include "cpsw.h" 16 + #include "cpsw_ale.h" 17 + #include "cpsw_priv.h" 18 + #include "cpsw_switchdev.h" 19 + 20 + struct cpsw_switchdev_event_work { 21 + struct work_struct work; 22 + struct switchdev_notifier_fdb_info fdb_info; 23 + struct cpsw_priv *priv; 24 + unsigned long event; 25 + }; 26 + 27 + static int cpsw_port_stp_state_set(struct cpsw_priv *priv, 28 + struct switchdev_trans *trans, u8 state) 29 + { 30 + struct cpsw_common *cpsw = priv->cpsw; 31 + u8 cpsw_state; 32 + int ret = 0; 33 + 34 + if (switchdev_trans_ph_prepare(trans)) 35 + return 0; 36 + 37 + switch (state) { 38 + case BR_STATE_FORWARDING: 39 + cpsw_state = ALE_PORT_STATE_FORWARD; 40 + break; 41 + case BR_STATE_LEARNING: 42 + cpsw_state = ALE_PORT_STATE_LEARN; 43 + break; 44 + case BR_STATE_DISABLED: 45 + cpsw_state = ALE_PORT_STATE_DISABLE; 46 + break; 47 + case BR_STATE_LISTENING: 48 + case BR_STATE_BLOCKING: 49 + cpsw_state = ALE_PORT_STATE_BLOCK; 50 + break; 51 + default: 52 + return -EOPNOTSUPP; 53 + } 54 + 55 + ret = cpsw_ale_control_set(cpsw->ale, priv->emac_port, 56 + ALE_PORT_STATE, cpsw_state); 57 + dev_dbg(priv->dev, "ale state: %u\n", cpsw_state); 58 + 59 + return ret; 60 + } 61 + 62 + static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv, 63 + struct switchdev_trans *trans, 64 + struct net_device *orig_dev, 65 + unsigned long brport_flags) 66 + { 67 + struct cpsw_common *cpsw = priv->cpsw; 68 + bool unreg_mcast_add = false; 69 + 70 + if (switchdev_trans_ph_prepare(trans)) 71 + return 0; 72 + 73 + if (brport_flags & BR_MCAST_FLOOD) 74 + unreg_mcast_add = true; 75 + dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n", 76 + unreg_mcast_add, priv->emac_port); 77 + 78 + cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port), 79 + unreg_mcast_add); 80 + 81 + return 0; 82 + } 83 + 84 + static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, 85 + struct switchdev_trans *trans, 86 + unsigned long flags) 87 + { 88 + if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD)) 89 + return -EINVAL; 90 + 91 + return 0; 92 + } 93 + 94 + static int cpsw_port_attr_set(struct net_device *ndev, 95 + const struct switchdev_attr *attr, 96 + struct switchdev_trans *trans) 97 + { 98 + struct cpsw_priv *priv = netdev_priv(ndev); 99 + int ret; 100 + 101 + dev_dbg(priv->dev, "attr: id %u port: %u\n", attr->id, priv->emac_port); 102 + 103 + switch (attr->id) { 104 + case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: 105 + ret = cpsw_port_attr_br_flags_pre_set(ndev, trans, 106 + attr->u.brport_flags); 107 + break; 108 + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: 109 + ret = cpsw_port_stp_state_set(priv, trans, attr->u.stp_state); 110 + dev_dbg(priv->dev, "stp state: %u\n", attr->u.stp_state); 111 + break; 112 + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: 113 + ret = cpsw_port_attr_br_flags_set(priv, trans, attr->orig_dev, 114 + attr->u.brport_flags); 115 + break; 116 + default: 117 + ret = -EOPNOTSUPP; 118 + break; 119 + } 120 + 121 + return ret; 122 + } 123 + 124 + static u16 cpsw_get_pvid(struct cpsw_priv *priv) 125 + { 126 + struct cpsw_common *cpsw = priv->cpsw; 127 + u32 __iomem *port_vlan_reg; 128 + u32 pvid; 129 + 130 + if (priv->emac_port) { 131 + int reg = CPSW2_PORT_VLAN; 132 + 133 + if (cpsw->version == CPSW_VERSION_1) 134 + reg = CPSW1_PORT_VLAN; 135 + pvid = slave_read(cpsw->slaves + (priv->emac_port - 1), reg); 136 + } else { 137 + port_vlan_reg = &cpsw->host_port_regs->port_vlan; 138 + pvid = readl(port_vlan_reg); 139 + } 140 + 141 + pvid = pvid & 0xfff; 142 + 143 + return pvid; 144 + } 145 + 146 + static void cpsw_set_pvid(struct cpsw_priv *priv, u16 vid, bool cfi, u32 cos) 147 + { 148 + struct cpsw_common *cpsw = priv->cpsw; 149 + void __iomem *port_vlan_reg; 150 + u32 pvid; 151 + 152 + pvid = vid; 153 + pvid |= cfi ? BIT(12) : 0; 154 + pvid |= (cos & 0x7) << 13; 155 + 156 + if (priv->emac_port) { 157 + int reg = CPSW2_PORT_VLAN; 158 + 159 + if (cpsw->version == CPSW_VERSION_1) 160 + reg = CPSW1_PORT_VLAN; 161 + /* no barrier */ 162 + slave_write(cpsw->slaves + (priv->emac_port - 1), pvid, reg); 163 + } else { 164 + /* CPU port */ 165 + port_vlan_reg = &cpsw->host_port_regs->port_vlan; 166 + writel(pvid, port_vlan_reg); 167 + } 168 + } 169 + 170 + static int cpsw_port_vlan_add(struct cpsw_priv *priv, bool untag, bool pvid, 171 + u16 vid, struct net_device *orig_dev) 172 + { 173 + bool cpu_port = netif_is_bridge_master(orig_dev); 174 + struct cpsw_common *cpsw = priv->cpsw; 175 + int unreg_mcast_mask = 0; 176 + int reg_mcast_mask = 0; 177 + int untag_mask = 0; 178 + int port_mask; 179 + int ret = 0; 180 + u32 flags; 181 + 182 + if (cpu_port) { 183 + port_mask = BIT(HOST_PORT_NUM); 184 + flags = orig_dev->flags; 185 + unreg_mcast_mask = port_mask; 186 + } else { 187 + port_mask = BIT(priv->emac_port); 188 + flags = priv->ndev->flags; 189 + } 190 + 191 + if (flags & IFF_MULTICAST) 192 + reg_mcast_mask = port_mask; 193 + 194 + if (untag) 195 + untag_mask = port_mask; 196 + 197 + ret = cpsw_ale_vlan_add_modify(cpsw->ale, vid, port_mask, untag_mask, 198 + reg_mcast_mask, unreg_mcast_mask); 199 + if (ret) { 200 + dev_err(priv->dev, "Unable to add vlan\n"); 201 + return ret; 202 + } 203 + 204 + if (cpu_port) 205 + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, 206 + HOST_PORT_NUM, ALE_VLAN, vid); 207 + if (!pvid) 208 + return ret; 209 + 210 + cpsw_set_pvid(priv, vid, 0, 0); 211 + 212 + dev_dbg(priv->dev, "VID add: %s: vid:%u ports:%X\n", 213 + priv->ndev->name, vid, port_mask); 214 + return ret; 215 + } 216 + 217 + static int cpsw_port_vlan_del(struct cpsw_priv *priv, u16 vid, 218 + struct net_device *orig_dev) 219 + { 220 + bool cpu_port = netif_is_bridge_master(orig_dev); 221 + struct cpsw_common *cpsw = priv->cpsw; 222 + int port_mask; 223 + int ret = 0; 224 + 225 + if (cpu_port) 226 + port_mask = BIT(HOST_PORT_NUM); 227 + else 228 + port_mask = BIT(priv->emac_port); 229 + 230 + ret = cpsw_ale_del_vlan(cpsw->ale, vid, port_mask); 231 + if (ret != 0) 232 + return ret; 233 + 234 + /* We don't care for the return value here, error is returned only if 235 + * the unicast entry is not present 236 + */ 237 + if (cpu_port) 238 + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, 239 + HOST_PORT_NUM, ALE_VLAN, vid); 240 + 241 + if (vid == cpsw_get_pvid(priv)) 242 + cpsw_set_pvid(priv, 0, 0, 0); 243 + 244 + /* We don't care for the return value here, error is returned only if 245 + * the multicast entry is not present 246 + */ 247 + cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast, 248 + port_mask, ALE_VLAN, vid); 249 + dev_dbg(priv->dev, "VID del: %s: vid:%u ports:%X\n", 250 + priv->ndev->name, vid, port_mask); 251 + 252 + return ret; 253 + } 254 + 255 + static int cpsw_port_vlans_add(struct cpsw_priv *priv, 256 + const struct switchdev_obj_port_vlan *vlan, 257 + struct switchdev_trans *trans) 258 + { 259 + bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 260 + struct net_device *orig_dev = vlan->obj.orig_dev; 261 + bool cpu_port = netif_is_bridge_master(orig_dev); 262 + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 263 + u16 vid; 264 + 265 + dev_dbg(priv->dev, "VID add: %s: vid:%u flags:%X\n", 266 + priv->ndev->name, vlan->vid_begin, vlan->flags); 267 + 268 + if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY)) 269 + return 0; 270 + 271 + if (switchdev_trans_ph_prepare(trans)) 272 + return 0; 273 + 274 + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 275 + int err; 276 + 277 + err = cpsw_port_vlan_add(priv, untag, pvid, vid, orig_dev); 278 + if (err) 279 + return err; 280 + } 281 + 282 + return 0; 283 + } 284 + 285 + static int cpsw_port_vlans_del(struct cpsw_priv *priv, 286 + const struct switchdev_obj_port_vlan *vlan) 287 + 288 + { 289 + struct net_device *orig_dev = vlan->obj.orig_dev; 290 + u16 vid; 291 + 292 + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 293 + int err; 294 + 295 + err = cpsw_port_vlan_del(priv, vid, orig_dev); 296 + if (err) 297 + return err; 298 + } 299 + 300 + return 0; 301 + } 302 + 303 + static int cpsw_port_mdb_add(struct cpsw_priv *priv, 304 + struct switchdev_obj_port_mdb *mdb, 305 + struct switchdev_trans *trans) 306 + 307 + { 308 + struct net_device *orig_dev = mdb->obj.orig_dev; 309 + bool cpu_port = netif_is_bridge_master(orig_dev); 310 + struct cpsw_common *cpsw = priv->cpsw; 311 + int port_mask; 312 + int err; 313 + 314 + if (switchdev_trans_ph_prepare(trans)) 315 + return 0; 316 + 317 + if (cpu_port) 318 + port_mask = BIT(HOST_PORT_NUM); 319 + else 320 + port_mask = BIT(priv->emac_port); 321 + 322 + err = cpsw_ale_add_mcast(cpsw->ale, mdb->addr, port_mask, 323 + ALE_VLAN, mdb->vid, 0); 324 + dev_dbg(priv->dev, "MDB add: %s: vid %u:%pM ports: %X\n", 325 + priv->ndev->name, mdb->vid, mdb->addr, port_mask); 326 + 327 + return err; 328 + } 329 + 330 + static int cpsw_port_mdb_del(struct cpsw_priv *priv, 331 + struct switchdev_obj_port_mdb *mdb) 332 + 333 + { 334 + struct net_device *orig_dev = mdb->obj.orig_dev; 335 + bool cpu_port = netif_is_bridge_master(orig_dev); 336 + struct cpsw_common *cpsw = priv->cpsw; 337 + int del_mask; 338 + int err; 339 + 340 + if (cpu_port) 341 + del_mask = BIT(HOST_PORT_NUM); 342 + else 343 + del_mask = BIT(priv->emac_port); 344 + 345 + err = cpsw_ale_del_mcast(cpsw->ale, mdb->addr, del_mask, 346 + ALE_VLAN, mdb->vid); 347 + dev_dbg(priv->dev, "MDB del: %s: vid %u:%pM ports: %X\n", 348 + priv->ndev->name, mdb->vid, mdb->addr, del_mask); 349 + 350 + return err; 351 + } 352 + 353 + static int cpsw_port_obj_add(struct net_device *ndev, 354 + const struct switchdev_obj *obj, 355 + struct switchdev_trans *trans, 356 + struct netlink_ext_ack *extack) 357 + { 358 + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 359 + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 360 + struct cpsw_priv *priv = netdev_priv(ndev); 361 + int err = 0; 362 + 363 + dev_dbg(priv->dev, "obj_add: id %u port: %u\n", 364 + obj->id, priv->emac_port); 365 + 366 + switch (obj->id) { 367 + case SWITCHDEV_OBJ_ID_PORT_VLAN: 368 + err = cpsw_port_vlans_add(priv, vlan, trans); 369 + break; 370 + case SWITCHDEV_OBJ_ID_PORT_MDB: 371 + case SWITCHDEV_OBJ_ID_HOST_MDB: 372 + err = cpsw_port_mdb_add(priv, mdb, trans); 373 + break; 374 + default: 375 + err = -EOPNOTSUPP; 376 + break; 377 + } 378 + 379 + return err; 380 + } 381 + 382 + static int cpsw_port_obj_del(struct net_device *ndev, 383 + const struct switchdev_obj *obj) 384 + { 385 + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 386 + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 387 + struct cpsw_priv *priv = netdev_priv(ndev); 388 + int err = 0; 389 + 390 + dev_dbg(priv->dev, "obj_del: id %u port: %u\n", 391 + obj->id, priv->emac_port); 392 + 393 + switch (obj->id) { 394 + case SWITCHDEV_OBJ_ID_PORT_VLAN: 395 + err = cpsw_port_vlans_del(priv, vlan); 396 + break; 397 + case SWITCHDEV_OBJ_ID_PORT_MDB: 398 + case SWITCHDEV_OBJ_ID_HOST_MDB: 399 + err = cpsw_port_mdb_del(priv, mdb); 400 + break; 401 + default: 402 + err = -EOPNOTSUPP; 403 + break; 404 + } 405 + 406 + return err; 407 + } 408 + 409 + static void cpsw_fdb_offload_notify(struct net_device *ndev, 410 + struct switchdev_notifier_fdb_info *rcv) 411 + { 412 + struct switchdev_notifier_fdb_info info; 413 + 414 + info.addr = rcv->addr; 415 + info.vid = rcv->vid; 416 + info.offloaded = true; 417 + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, 418 + ndev, &info.info, NULL); 419 + } 420 + 421 + static void cpsw_switchdev_event_work(struct work_struct *work) 422 + { 423 + struct cpsw_switchdev_event_work *switchdev_work = 424 + container_of(work, struct cpsw_switchdev_event_work, work); 425 + struct cpsw_priv *priv = switchdev_work->priv; 426 + struct switchdev_notifier_fdb_info *fdb; 427 + struct cpsw_common *cpsw = priv->cpsw; 428 + int port = priv->emac_port; 429 + 430 + rtnl_lock(); 431 + switch (switchdev_work->event) { 432 + case SWITCHDEV_FDB_ADD_TO_DEVICE: 433 + fdb = &switchdev_work->fdb_info; 434 + 435 + dev_dbg(cpsw->dev, "cpsw_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n", 436 + fdb->addr, fdb->vid, fdb->added_by_user, 437 + fdb->offloaded, port); 438 + 439 + if (!fdb->added_by_user) 440 + break; 441 + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) 442 + port = HOST_PORT_NUM; 443 + 444 + cpsw_ale_add_ucast(cpsw->ale, (u8 *)fdb->addr, port, 445 + fdb->vid ? ALE_VLAN : 0, fdb->vid); 446 + cpsw_fdb_offload_notify(priv->ndev, fdb); 447 + break; 448 + case SWITCHDEV_FDB_DEL_TO_DEVICE: 449 + fdb = &switchdev_work->fdb_info; 450 + 451 + dev_dbg(cpsw->dev, "cpsw_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n", 452 + fdb->addr, fdb->vid, fdb->added_by_user, 453 + fdb->offloaded, port); 454 + 455 + if (!fdb->added_by_user) 456 + break; 457 + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) 458 + port = HOST_PORT_NUM; 459 + 460 + cpsw_ale_del_ucast(cpsw->ale, (u8 *)fdb->addr, port, 461 + fdb->vid ? ALE_VLAN : 0, fdb->vid); 462 + break; 463 + default: 464 + break; 465 + } 466 + rtnl_unlock(); 467 + 468 + kfree(switchdev_work->fdb_info.addr); 469 + kfree(switchdev_work); 470 + dev_put(priv->ndev); 471 + } 472 + 473 + /* called under rcu_read_lock() */ 474 + static int cpsw_switchdev_event(struct notifier_block *unused, 475 + unsigned long event, void *ptr) 476 + { 477 + struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); 478 + struct switchdev_notifier_fdb_info *fdb_info = ptr; 479 + struct cpsw_switchdev_event_work *switchdev_work; 480 + struct cpsw_priv *priv = netdev_priv(ndev); 481 + int err; 482 + 483 + if (event == SWITCHDEV_PORT_ATTR_SET) { 484 + err = switchdev_handle_port_attr_set(ndev, ptr, 485 + cpsw_port_dev_check, 486 + cpsw_port_attr_set); 487 + return notifier_from_errno(err); 488 + } 489 + 490 + if (!cpsw_port_dev_check(ndev)) 491 + return NOTIFY_DONE; 492 + 493 + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 494 + if (WARN_ON(!switchdev_work)) 495 + return NOTIFY_BAD; 496 + 497 + INIT_WORK(&switchdev_work->work, cpsw_switchdev_event_work); 498 + switchdev_work->priv = priv; 499 + switchdev_work->event = event; 500 + 501 + switch (event) { 502 + case SWITCHDEV_FDB_ADD_TO_DEVICE: 503 + case SWITCHDEV_FDB_DEL_TO_DEVICE: 504 + memcpy(&switchdev_work->fdb_info, ptr, 505 + sizeof(switchdev_work->fdb_info)); 506 + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); 507 + if (!switchdev_work->fdb_info.addr) 508 + goto err_addr_alloc; 509 + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, 510 + fdb_info->addr); 511 + dev_hold(ndev); 512 + break; 513 + default: 514 + kfree(switchdev_work); 515 + return NOTIFY_DONE; 516 + } 517 + 518 + queue_work(system_long_wq, &switchdev_work->work); 519 + 520 + return NOTIFY_DONE; 521 + 522 + err_addr_alloc: 523 + kfree(switchdev_work); 524 + return NOTIFY_BAD; 525 + } 526 + 527 + static struct notifier_block cpsw_switchdev_notifier = { 528 + .notifier_call = cpsw_switchdev_event, 529 + }; 530 + 531 + static int cpsw_switchdev_blocking_event(struct notifier_block *unused, 532 + unsigned long event, void *ptr) 533 + { 534 + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 535 + int err; 536 + 537 + switch (event) { 538 + case SWITCHDEV_PORT_OBJ_ADD: 539 + err = switchdev_handle_port_obj_add(dev, ptr, 540 + cpsw_port_dev_check, 541 + cpsw_port_obj_add); 542 + return notifier_from_errno(err); 543 + case SWITCHDEV_PORT_OBJ_DEL: 544 + err = switchdev_handle_port_obj_del(dev, ptr, 545 + cpsw_port_dev_check, 546 + cpsw_port_obj_del); 547 + return notifier_from_errno(err); 548 + case SWITCHDEV_PORT_ATTR_SET: 549 + err = switchdev_handle_port_attr_set(dev, ptr, 550 + cpsw_port_dev_check, 551 + cpsw_port_attr_set); 552 + return notifier_from_errno(err); 553 + default: 554 + break; 555 + } 556 + 557 + return NOTIFY_DONE; 558 + } 559 + 560 + static struct notifier_block cpsw_switchdev_bl_notifier = { 561 + .notifier_call = cpsw_switchdev_blocking_event, 562 + }; 563 + 564 + int cpsw_switchdev_register_notifiers(struct cpsw_common *cpsw) 565 + { 566 + int ret = 0; 567 + 568 + ret = register_switchdev_notifier(&cpsw_switchdev_notifier); 569 + if (ret) { 570 + dev_err(cpsw->dev, "register switchdev notifier fail ret:%d\n", 571 + ret); 572 + return ret; 573 + } 574 + 575 + ret = register_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier); 576 + if (ret) { 577 + dev_err(cpsw->dev, "register switchdev blocking notifier ret:%d\n", 578 + ret); 579 + unregister_switchdev_notifier(&cpsw_switchdev_notifier); 580 + } 581 + 582 + return ret; 583 + } 584 + 585 + void cpsw_switchdev_unregister_notifiers(struct cpsw_common *cpsw) 586 + { 587 + unregister_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier); 588 + unregister_switchdev_notifier(&cpsw_switchdev_notifier); 589 + }
+15
drivers/net/ethernet/ti/cpsw_switchdev.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Texas Instruments Ethernet Switch Driver 4 + */ 5 + 6 + #ifndef DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ 7 + #define DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ 8 + 9 + #include <net/switchdev.h> 10 + 11 + bool cpsw_port_dev_check(const struct net_device *dev); 12 + int cpsw_switchdev_register_notifiers(struct cpsw_common *cpsw); 13 + void cpsw_switchdev_unregister_notifiers(struct cpsw_common *cpsw); 14 + 15 + #endif /* DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ */