OSDN Git Service

kernel: bump 5.15 to 5.15.54
[immortalwrt/immortalwrt.git] / target / linux / generic / backport-5.15 / 766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch
1 From 5c957c7ca78cce5e4b96866722b0115bd758d945 Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Wed, 2 Feb 2022 01:03:30 +0100
4 Subject: [PATCH 11/16] net: dsa: qca8k: add support for mib autocast in
5  Ethernet packet
6
7 The switch can autocast MIB counter using Ethernet packet.
8 Add support for this and provide a handler for the tagger.
9 The switch will send packet with MIB counter for each port, the switch
10 will use completion API to wait for the correct packet to be received
11 and will complete the task only when each packet is received.
12 Although the handler will drop all the other packet, we still have to
13 consume each MIB packet to complete the request. This is done to prevent
14 mixed data with concurrent ethtool request.
15
16 connect_tag_protocol() is used to add the handler to the tag_qca tagger,
17 master_state_change() use the MIB lock to make sure no MIB Ethernet is
18 in progress.
19
20 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
22 ---
23  drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++-
24  drivers/net/dsa/qca8k.h |  17 ++++++-
25  2 files changed, 121 insertions(+), 2 deletions(-)
26
27 --- a/drivers/net/dsa/qca8k.c
28 +++ b/drivers/net/dsa/qca8k.c
29 @@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv)
30         int ret;
31  
32         mutex_lock(&priv->reg_mutex);
33 -       ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
34 +       ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
35 +                                QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
36 +                                FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
37 +                                QCA8K_MIB_BUSY);
38         if (ret)
39                 goto exit;
40  
41 @@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds,
42                         ETH_GSTRING_LEN);
43  }
44  
45 +static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
46 +{
47 +       const struct qca8k_match_data *match_data;
48 +       struct qca8k_mib_eth_data *mib_eth_data;
49 +       struct qca8k_priv *priv = ds->priv;
50 +       const struct qca8k_mib_desc *mib;
51 +       struct mib_ethhdr *mib_ethhdr;
52 +       int i, mib_len, offset = 0;
53 +       u64 *data;
54 +       u8 port;
55 +
56 +       mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
57 +       mib_eth_data = &priv->mib_eth_data;
58 +
59 +       /* The switch autocast every port. Ignore other packet and
60 +        * parse only the requested one.
61 +        */
62 +       port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr));
63 +       if (port != mib_eth_data->req_port)
64 +               goto exit;
65 +
66 +       match_data = device_get_match_data(priv->dev);
67 +       data = mib_eth_data->data;
68 +
69 +       for (i = 0; i < match_data->mib_count; i++) {
70 +               mib = &ar8327_mib[i];
71 +
72 +               /* First 3 mib are present in the skb head */
73 +               if (i < 3) {
74 +                       data[i] = mib_ethhdr->data[i];
75 +                       continue;
76 +               }
77 +
78 +               mib_len = sizeof(uint32_t);
79 +
80 +               /* Some mib are 64 bit wide */
81 +               if (mib->size == 2)
82 +                       mib_len = sizeof(uint64_t);
83 +
84 +               /* Copy the mib value from packet to the */
85 +               memcpy(data + i, skb->data + offset, mib_len);
86 +
87 +               /* Set the offset for the next mib */
88 +               offset += mib_len;
89 +       }
90 +
91 +exit:
92 +       /* Complete on receiving all the mib packet */
93 +       if (refcount_dec_and_test(&mib_eth_data->port_parsed))
94 +               complete(&mib_eth_data->rw_done);
95 +}
96 +
97 +static int
98 +qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
99 +{
100 +       struct dsa_port *dp = dsa_to_port(ds, port);
101 +       struct qca8k_mib_eth_data *mib_eth_data;
102 +       struct qca8k_priv *priv = ds->priv;
103 +       int ret;
104 +
105 +       mib_eth_data = &priv->mib_eth_data;
106 +
107 +       mutex_lock(&mib_eth_data->mutex);
108 +
109 +       reinit_completion(&mib_eth_data->rw_done);
110 +
111 +       mib_eth_data->req_port = dp->index;
112 +       mib_eth_data->data = data;
113 +       refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS);
114 +
115 +       mutex_lock(&priv->reg_mutex);
116 +
117 +       /* Send mib autocast request */
118 +       ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
119 +                                QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
120 +                                FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) |
121 +                                QCA8K_MIB_BUSY);
122 +
123 +       mutex_unlock(&priv->reg_mutex);
124 +
125 +       if (ret)
126 +               goto exit;
127 +
128 +       ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
129 +
130 +exit:
131 +       mutex_unlock(&mib_eth_data->mutex);
132 +
133 +       return ret;
134 +}
135 +
136  static void
137  qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
138                         uint64_t *data)
139 @@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switc
140         u32 hi = 0;
141         int ret;
142  
143 +       if (priv->mgmt_master &&
144 +           qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
145 +               return;
146 +
147         match_data = of_device_get_match_data(priv->dev);
148  
149         for (i = 0; i < match_data->mib_count; i++) {
150 @@ -2611,9 +2709,11 @@ qca8k_master_change(struct dsa_switch *d
151                 return;
152  
153         mutex_lock(&priv->mgmt_eth_data.mutex);
154 +       mutex_lock(&priv->mib_eth_data.mutex);
155  
156         priv->mgmt_master = operational ? (struct net_device *)master : NULL;
157  
158 +       mutex_unlock(&priv->mib_eth_data.mutex);
159         mutex_unlock(&priv->mgmt_eth_data.mutex);
160  }
161  
162 @@ -2627,6 +2727,7 @@ static int qca8k_connect_tag_protocol(st
163                 tagger_data = ds->tagger_data;
164  
165                 tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
166 +               tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler;
167  
168                 break;
169         default:
170 @@ -2755,6 +2856,9 @@ qca8k_sw_probe(struct mdio_device *mdiod
171         mutex_init(&priv->mgmt_eth_data.mutex);
172         init_completion(&priv->mgmt_eth_data.rw_done);
173  
174 +       mutex_init(&priv->mib_eth_data.mutex);
175 +       init_completion(&priv->mib_eth_data.rw_done);
176 +
177         priv->ds->dev = &mdiodev->dev;
178         priv->ds->num_ports = QCA8K_NUM_PORTS;
179         priv->ds->priv = priv;
180 --- a/drivers/net/dsa/qca8k.h
181 +++ b/drivers/net/dsa/qca8k.h
182 @@ -67,7 +67,7 @@
183  #define QCA8K_REG_MODULE_EN                            0x030
184  #define   QCA8K_MODULE_EN_MIB                          BIT(0)
185  #define QCA8K_REG_MIB                                  0x034
186 -#define   QCA8K_MIB_FLUSH                              BIT(24)
187 +#define   QCA8K_MIB_FUNC                               GENMASK(26, 24)
188  #define   QCA8K_MIB_CPU_KEEP                           BIT(20)
189  #define   QCA8K_MIB_BUSY                               BIT(17)
190  #define QCA8K_MDIO_MASTER_CTRL                         0x3c
191 @@ -317,6 +317,12 @@ enum qca8k_vlan_cmd {
192         QCA8K_VLAN_READ = 6,
193  };
194  
195 +enum qca8k_mid_cmd {
196 +       QCA8K_MIB_FLUSH = 1,
197 +       QCA8K_MIB_FLUSH_PORT = 2,
198 +       QCA8K_MIB_CAST = 3,
199 +};
200 +
201  struct ar8xxx_port_status {
202         int enabled;
203  };
204 @@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data {
205         u32 data[4];
206  };
207  
208 +struct qca8k_mib_eth_data {
209 +       struct completion rw_done;
210 +       struct mutex mutex; /* Process one command at time */
211 +       refcount_t port_parsed; /* Counter to track parsed port */
212 +       u8 req_port;
213 +       u64 *data; /* pointer to ethtool data */
214 +};
215 +
216  struct qca8k_ports_config {
217         bool sgmii_rx_clk_falling_edge;
218         bool sgmii_tx_clk_falling_edge;
219 @@ -367,6 +381,7 @@ struct qca8k_priv {
220         unsigned int port_mtu[QCA8K_NUM_PORTS];
221         struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
222         struct qca8k_mgmt_eth_data mgmt_eth_data;
223 +       struct qca8k_mib_eth_data mib_eth_data;
224  };
225  
226  struct qca8k_mib_desc {