OSDN Git Service

kernel: bump 5.15 to 5.15.54
[immortalwrt/immortalwrt.git] / target / linux / generic / backport-5.15 / 762-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch
1 From 2c1bdbc7e7560d7de754cad277d968d56bb1899e Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Tue, 23 Nov 2021 03:59:10 +0100
4 Subject: net: dsa: qca8k: add support for mirror mode
5
6 The switch supports mirror mode. Only one port can set as mirror port and
7 every other port can set to both ingress and egress mode. The mirror
8 port is disabled and reverted to normal operation once every port is
9 removed from sending packet to it.
10
11 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
12 Signed-off-by: David S. Miller <davem@davemloft.net>
13 ---
14  drivers/net/dsa/qca8k.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
15  drivers/net/dsa/qca8k.h |  4 +++
16  2 files changed, 99 insertions(+)
17
18 --- a/drivers/net/dsa/qca8k.c
19 +++ b/drivers/net/dsa/qca8k.c
20 @@ -2046,6 +2046,99 @@ qca8k_port_mdb_del(struct dsa_switch *ds
21  }
22  
23  static int
24 +qca8k_port_mirror_add(struct dsa_switch *ds, int port,
25 +                     struct dsa_mall_mirror_tc_entry *mirror,
26 +                     bool ingress)
27 +{
28 +       struct qca8k_priv *priv = ds->priv;
29 +       int monitor_port, ret;
30 +       u32 reg, val;
31 +
32 +       /* Check for existent entry */
33 +       if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
34 +               return -EEXIST;
35 +
36 +       ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
37 +       if (ret)
38 +               return ret;
39 +
40 +       /* QCA83xx can have only one port set to mirror mode.
41 +        * Check that the correct port is requested and return error otherwise.
42 +        * When no mirror port is set, the values is set to 0xF
43 +        */
44 +       monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
45 +       if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
46 +               return -EEXIST;
47 +
48 +       /* Set the monitor port */
49 +       val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
50 +                        mirror->to_local_port);
51 +       ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
52 +                                QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
53 +       if (ret)
54 +               return ret;
55 +
56 +       if (ingress) {
57 +               reg = QCA8K_PORT_LOOKUP_CTRL(port);
58 +               val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
59 +       } else {
60 +               reg = QCA8K_REG_PORT_HOL_CTRL1(port);
61 +               val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
62 +       }
63 +
64 +       ret = regmap_update_bits(priv->regmap, reg, val, val);
65 +       if (ret)
66 +               return ret;
67 +
68 +       /* Track mirror port for tx and rx to decide when the
69 +        * mirror port has to be disabled.
70 +        */
71 +       if (ingress)
72 +               priv->mirror_rx |= BIT(port);
73 +       else
74 +               priv->mirror_tx |= BIT(port);
75 +
76 +       return 0;
77 +}
78 +
79 +static void
80 +qca8k_port_mirror_del(struct dsa_switch *ds, int port,
81 +                     struct dsa_mall_mirror_tc_entry *mirror)
82 +{
83 +       struct qca8k_priv *priv = ds->priv;
84 +       u32 reg, val;
85 +       int ret;
86 +
87 +       if (mirror->ingress) {
88 +               reg = QCA8K_PORT_LOOKUP_CTRL(port);
89 +               val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
90 +       } else {
91 +               reg = QCA8K_REG_PORT_HOL_CTRL1(port);
92 +               val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
93 +       }
94 +
95 +       ret = regmap_clear_bits(priv->regmap, reg, val);
96 +       if (ret)
97 +               goto err;
98 +
99 +       if (mirror->ingress)
100 +               priv->mirror_rx &= ~BIT(port);
101 +       else
102 +               priv->mirror_tx &= ~BIT(port);
103 +
104 +       /* No port set to send packet to mirror port. Disable mirror port */
105 +       if (!priv->mirror_rx && !priv->mirror_tx) {
106 +               val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
107 +               ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
108 +                                        QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
109 +               if (ret)
110 +                       goto err;
111 +       }
112 +err:
113 +       dev_err(priv->dev, "Failed to del mirror port from %d", port);
114 +}
115 +
116 +static int
117  qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
118                           struct netlink_ext_ack *extack)
119  {
120 @@ -2155,6 +2248,8 @@ static const struct dsa_switch_ops qca8k
121         .port_fdb_dump          = qca8k_port_fdb_dump,
122         .port_mdb_add           = qca8k_port_mdb_add,
123         .port_mdb_del           = qca8k_port_mdb_del,
124 +       .port_mirror_add        = qca8k_port_mirror_add,
125 +       .port_mirror_del        = qca8k_port_mirror_del,
126         .port_vlan_filtering    = qca8k_port_vlan_filtering,
127         .port_vlan_add          = qca8k_port_vlan_add,
128         .port_vlan_del          = qca8k_port_vlan_del,
129 --- a/drivers/net/dsa/qca8k.h
130 +++ b/drivers/net/dsa/qca8k.h
131 @@ -180,6 +180,7 @@
132  #define   QCA8K_ATU_AGE_TIME(x)                                FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x))
133  #define QCA8K_REG_GLOBAL_FW_CTRL0                      0x620
134  #define   QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN            BIT(10)
135 +#define   QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM                GENMASK(7, 4)
136  #define QCA8K_REG_GLOBAL_FW_CTRL1                      0x624
137  #define   QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK           GENMASK(30, 24)
138  #define   QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK             GENMASK(22, 16)
139 @@ -201,6 +202,7 @@
140  #define   QCA8K_PORT_LOOKUP_STATE_LEARNING             QCA8K_PORT_LOOKUP_STATE(0x3)
141  #define   QCA8K_PORT_LOOKUP_STATE_FORWARD              QCA8K_PORT_LOOKUP_STATE(0x4)
142  #define   QCA8K_PORT_LOOKUP_LEARN                      BIT(20)
143 +#define   QCA8K_PORT_LOOKUP_ING_MIRROR_EN              BIT(25)
144  
145  #define QCA8K_REG_GLOBAL_FC_THRESH                     0x800
146  #define   QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK           GENMASK(24, 16)
147 @@ -305,6 +307,8 @@ struct qca8k_ports_config {
148  struct qca8k_priv {
149         u8 switch_id;
150         u8 switch_revision;
151 +       u8 mirror_rx;
152 +       u8 mirror_tx;
153         bool legacy_phy_port_mapping;
154         struct qca8k_ports_config ports_config;
155         struct regmap *regmap;