1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include "lan966x_main.h" 4 5 int lan966x_mirror_port_add(struct lan966x_port *port, 6 struct flow_action_entry *action, 7 unsigned long mirror_id, 8 bool ingress, 9 struct netlink_ext_ack *extack) 10 { 11 struct lan966x *lan966x = port->lan966x; 12 struct lan966x_port *monitor_port; 13 14 if (!lan966x_netdevice_check(action->dev)) { 15 NL_SET_ERR_MSG_MOD(extack, 16 "Destination not an lan966x port"); 17 return -EOPNOTSUPP; 18 } 19 20 monitor_port = netdev_priv(action->dev); 21 22 if (lan966x->mirror_mask[ingress] & BIT(port->chip_port)) { 23 NL_SET_ERR_MSG_MOD(extack, 24 "Mirror already exists"); 25 return -EEXIST; 26 } 27 28 if (lan966x->mirror_monitor && 29 lan966x->mirror_monitor != monitor_port) { 30 NL_SET_ERR_MSG_MOD(extack, 31 "Cannot change mirror port while in use"); 32 return -EBUSY; 33 } 34 35 if (port == monitor_port) { 36 NL_SET_ERR_MSG_MOD(extack, 37 "Cannot mirror the monitor port"); 38 return -EINVAL; 39 } 40 41 lan966x->mirror_mask[ingress] |= BIT(port->chip_port); 42 43 lan966x->mirror_monitor = monitor_port; 44 lan_wr(BIT(monitor_port->chip_port), lan966x, ANA_MIRRORPORTS); 45 46 if (ingress) { 47 lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(1), 48 ANA_PORT_CFG_SRC_MIRROR_ENA, 49 lan966x, ANA_PORT_CFG(port->chip_port)); 50 } else { 51 lan_wr(lan966x->mirror_mask[0], lan966x, 52 ANA_EMIRRORPORTS); 53 } 54 55 lan966x->mirror_count++; 56 57 if (ingress) 58 port->tc.ingress_mirror_id = mirror_id; 59 else 60 port->tc.egress_mirror_id = mirror_id; 61 62 return 0; 63 } 64 65 int lan966x_mirror_port_del(struct lan966x_port *port, 66 bool ingress, 67 struct netlink_ext_ack *extack) 68 { 69 struct lan966x *lan966x = port->lan966x; 70 71 if (!(lan966x->mirror_mask[ingress] & BIT(port->chip_port))) { 72 NL_SET_ERR_MSG_MOD(extack, 73 "There is no mirroring for this port"); 74 return -ENOENT; 75 } 76 77 lan966x->mirror_mask[ingress] &= ~BIT(port->chip_port); 78 79 if (ingress) { 80 lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(0), 81 ANA_PORT_CFG_SRC_MIRROR_ENA, 82 lan966x, ANA_PORT_CFG(port->chip_port)); 83 } else { 84 lan_wr(lan966x->mirror_mask[0], lan966x, 85 ANA_EMIRRORPORTS); 86 } 87 88 lan966x->mirror_count--; 89 90 if (lan966x->mirror_count == 0) { 91 lan966x->mirror_monitor = NULL; 92 lan_wr(0, lan966x, ANA_MIRRORPORTS); 93 } 94 95 if (ingress) 96 port->tc.ingress_mirror_id = 0; 97 else 98 port->tc.egress_mirror_id = 0; 99 100 return 0; 101 } 102 103 void lan966x_mirror_port_stats(struct lan966x_port *port, 104 struct flow_stats *stats, 105 bool ingress) 106 { 107 struct rtnl_link_stats64 new_stats; 108 struct flow_stats *old_stats; 109 110 old_stats = &port->tc.mirror_stat; 111 lan966x_stats_get(port->dev, &new_stats); 112 113 if (ingress) { 114 flow_stats_update(stats, 115 new_stats.rx_bytes - old_stats->bytes, 116 new_stats.rx_packets - old_stats->pkts, 117 new_stats.rx_dropped - old_stats->drops, 118 old_stats->lastused, 119 FLOW_ACTION_HW_STATS_IMMEDIATE); 120 121 old_stats->bytes = new_stats.rx_bytes; 122 old_stats->pkts = new_stats.rx_packets; 123 old_stats->drops = new_stats.rx_dropped; 124 old_stats->lastused = jiffies; 125 } else { 126 flow_stats_update(stats, 127 new_stats.tx_bytes - old_stats->bytes, 128 new_stats.tx_packets - old_stats->pkts, 129 new_stats.tx_dropped - old_stats->drops, 130 old_stats->lastused, 131 FLOW_ACTION_HW_STATS_IMMEDIATE); 132 133 old_stats->bytes = new_stats.tx_bytes; 134 old_stats->pkts = new_stats.tx_packets; 135 old_stats->drops = new_stats.tx_dropped; 136 old_stats->lastused = jiffies; 137 } 138 } 139