139 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include "lan966x_main.h"4 5int 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 else60 port->tc.egress_mirror_id = mirror_id;61 62 return 0;63}64 65int 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 else98 port->tc.egress_mirror_id = 0;99 100 return 0;101}102 103void 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