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(dev: 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(dev: 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(val: 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(val: 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(val: 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(dev: port->dev, stats: &new_stats); |
112 | |
113 | if (ingress) { |
114 | flow_stats_update(flow_stats: stats, |
115 | bytes: new_stats.rx_bytes - old_stats->bytes, |
116 | pkts: new_stats.rx_packets - old_stats->pkts, |
117 | drops: new_stats.rx_dropped - old_stats->drops, |
118 | lastused: old_stats->lastused, |
119 | used_hw_stats: 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(flow_stats: stats, |
127 | bytes: new_stats.tx_bytes - old_stats->bytes, |
128 | pkts: new_stats.tx_packets - old_stats->pkts, |
129 | drops: new_stats.tx_dropped - old_stats->drops, |
130 | lastused: old_stats->lastused, |
131 | used_hw_stats: 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 | |