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
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.
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
20 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
23 drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++-
24 drivers/net/dsa/qca8k.h | 17 ++++++-
25 2 files changed, 121 insertions(+), 2 deletions(-)
27 diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
28 index e3a215f04559..199cf4f761c0 100644
29 --- a/drivers/net/dsa/qca8k.c
30 +++ b/drivers/net/dsa/qca8k.c
31 @@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv)
34 mutex_lock(&priv->reg_mutex);
35 - ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
36 + ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
37 + QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
38 + FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
43 @@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
47 +static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
49 + const struct qca8k_match_data *match_data;
50 + struct qca8k_mib_eth_data *mib_eth_data;
51 + struct qca8k_priv *priv = ds->priv;
52 + const struct qca8k_mib_desc *mib;
53 + struct mib_ethhdr *mib_ethhdr;
54 + int i, mib_len, offset = 0;
58 + mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
59 + mib_eth_data = &priv->mib_eth_data;
61 + /* The switch autocast every port. Ignore other packet and
62 + * parse only the requested one.
64 + port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr));
65 + if (port != mib_eth_data->req_port)
68 + match_data = device_get_match_data(priv->dev);
69 + data = mib_eth_data->data;
71 + for (i = 0; i < match_data->mib_count; i++) {
72 + mib = &ar8327_mib[i];
74 + /* First 3 mib are present in the skb head */
76 + data[i] = mib_ethhdr->data[i];
80 + mib_len = sizeof(uint32_t);
82 + /* Some mib are 64 bit wide */
84 + mib_len = sizeof(uint64_t);
86 + /* Copy the mib value from packet to the */
87 + memcpy(data + i, skb->data + offset, mib_len);
89 + /* Set the offset for the next mib */
94 + /* Complete on receiving all the mib packet */
95 + if (refcount_dec_and_test(&mib_eth_data->port_parsed))
96 + complete(&mib_eth_data->rw_done);
100 +qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
102 + struct dsa_port *dp = dsa_to_port(ds, port);
103 + struct qca8k_mib_eth_data *mib_eth_data;
104 + struct qca8k_priv *priv = ds->priv;
107 + mib_eth_data = &priv->mib_eth_data;
109 + mutex_lock(&mib_eth_data->mutex);
111 + reinit_completion(&mib_eth_data->rw_done);
113 + mib_eth_data->req_port = dp->index;
114 + mib_eth_data->data = data;
115 + refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS);
117 + mutex_lock(&priv->reg_mutex);
119 + /* Send mib autocast request */
120 + ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
121 + QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
122 + FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) |
125 + mutex_unlock(&priv->reg_mutex);
130 + ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
133 + mutex_unlock(&mib_eth_data->mutex);
139 qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
141 @@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
145 + if (priv->mgmt_master &&
146 + qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
149 match_data = of_device_get_match_data(priv->dev);
151 for (i = 0; i < match_data->mib_count; i++) {
152 @@ -2593,9 +2691,11 @@ qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
155 mutex_lock(&priv->mgmt_eth_data.mutex);
156 + mutex_lock(&priv->mib_eth_data.mutex);
158 priv->mgmt_master = operational ? (struct net_device *)master : NULL;
160 + mutex_unlock(&priv->mib_eth_data.mutex);
161 mutex_unlock(&priv->mgmt_eth_data.mutex);
164 @@ -2609,6 +2709,7 @@ static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
165 tagger_data = ds->tagger_data;
167 tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
168 + tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler;
172 @@ -2737,6 +2838,9 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
173 mutex_init(&priv->mgmt_eth_data.mutex);
174 init_completion(&priv->mgmt_eth_data.rw_done);
176 + mutex_init(&priv->mib_eth_data.mutex);
177 + init_completion(&priv->mib_eth_data.rw_done);
179 priv->ds->dev = &mdiodev->dev;
180 priv->ds->num_ports = QCA8K_NUM_PORTS;
181 priv->ds->priv = priv;
182 diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
183 index 75c28689a652..2d7d084db089 100644
184 --- a/drivers/net/dsa/qca8k.h
185 +++ b/drivers/net/dsa/qca8k.h
187 #define QCA8K_REG_MODULE_EN 0x030
188 #define QCA8K_MODULE_EN_MIB BIT(0)
189 #define QCA8K_REG_MIB 0x034
190 -#define QCA8K_MIB_FLUSH BIT(24)
191 +#define QCA8K_MIB_FUNC GENMASK(26, 24)
192 #define QCA8K_MIB_CPU_KEEP BIT(20)
193 #define QCA8K_MIB_BUSY BIT(17)
194 #define QCA8K_MDIO_MASTER_CTRL 0x3c
195 @@ -317,6 +317,12 @@ enum qca8k_vlan_cmd {
199 +enum qca8k_mid_cmd {
200 + QCA8K_MIB_FLUSH = 1,
201 + QCA8K_MIB_FLUSH_PORT = 2,
202 + QCA8K_MIB_CAST = 3,
205 struct ar8xxx_port_status {
208 @@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data {
212 +struct qca8k_mib_eth_data {
213 + struct completion rw_done;
214 + struct mutex mutex; /* Process one command at time */
215 + refcount_t port_parsed; /* Counter to track parsed port */
217 + u64 *data; /* pointer to ethtool data */
220 struct qca8k_ports_config {
221 bool sgmii_rx_clk_falling_edge;
222 bool sgmii_tx_clk_falling_edge;
223 @@ -367,6 +381,7 @@ struct qca8k_priv {
224 unsigned int port_mtu[QCA8K_NUM_PORTS];
225 struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
226 struct qca8k_mgmt_eth_data mgmt_eth_data;
227 + struct qca8k_mib_eth_data mib_eth_data;
230 struct qca8k_mib_desc {