]> Git Repo - J-linux.git/blob - drivers/net/ethernet/microchip/lan966x/lan966x_mirror.c
Merge tag 'kbuild-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[J-linux.git] / drivers / net / ethernet / microchip / lan966x / lan966x_mirror.c
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 }
This page took 0.036786 seconds and 4 git commands to generate.