Skip to content

Commit 5c957c7

Browse files
Ansueldavem330
authored andcommitted
net: dsa: qca8k: add support for mib autocast in Ethernet packet
The switch can autocast MIB counter using Ethernet packet. Add support for this and provide a handler for the tagger. The switch will send packet with MIB counter for each port, the switch will use completion API to wait for the correct packet to be received and will complete the task only when each packet is received. Although the handler will drop all the other packet, we still have to consume each MIB packet to complete the request. This is done to prevent mixed data with concurrent ethtool request. connect_tag_protocol() is used to add the handler to the tag_qca tagger, master_state_change() use the MIB lock to make sure no MIB Ethernet is in progress. Signed-off-by: Ansuel Smith <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5950c7c commit 5c957c7

File tree

2 files changed

+121
-2
lines changed

2 files changed

+121
-2
lines changed

drivers/net/dsa/qca8k.c

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv)
830830
int ret;
831831

832832
mutex_lock(&priv->reg_mutex);
833-
ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
833+
ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
834+
QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
835+
FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
836+
QCA8K_MIB_BUSY);
834837
if (ret)
835838
goto exit;
836839

@@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
19011904
ETH_GSTRING_LEN);
19021905
}
19031906

1907+
static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
1908+
{
1909+
const struct qca8k_match_data *match_data;
1910+
struct qca8k_mib_eth_data *mib_eth_data;
1911+
struct qca8k_priv *priv = ds->priv;
1912+
const struct qca8k_mib_desc *mib;
1913+
struct mib_ethhdr *mib_ethhdr;
1914+
int i, mib_len, offset = 0;
1915+
u64 *data;
1916+
u8 port;
1917+
1918+
mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
1919+
mib_eth_data = &priv->mib_eth_data;
1920+
1921+
/* The switch autocast every port. Ignore other packet and
1922+
* parse only the requested one.
1923+
*/
1924+
port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr));
1925+
if (port != mib_eth_data->req_port)
1926+
goto exit;
1927+
1928+
match_data = device_get_match_data(priv->dev);
1929+
data = mib_eth_data->data;
1930+
1931+
for (i = 0; i < match_data->mib_count; i++) {
1932+
mib = &ar8327_mib[i];
1933+
1934+
/* First 3 mib are present in the skb head */
1935+
if (i < 3) {
1936+
data[i] = mib_ethhdr->data[i];
1937+
continue;
1938+
}
1939+
1940+
mib_len = sizeof(uint32_t);
1941+
1942+
/* Some mib are 64 bit wide */
1943+
if (mib->size == 2)
1944+
mib_len = sizeof(uint64_t);
1945+
1946+
/* Copy the mib value from packet to the */
1947+
memcpy(data + i, skb->data + offset, mib_len);
1948+
1949+
/* Set the offset for the next mib */
1950+
offset += mib_len;
1951+
}
1952+
1953+
exit:
1954+
/* Complete on receiving all the mib packet */
1955+
if (refcount_dec_and_test(&mib_eth_data->port_parsed))
1956+
complete(&mib_eth_data->rw_done);
1957+
}
1958+
1959+
static int
1960+
qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
1961+
{
1962+
struct dsa_port *dp = dsa_to_port(ds, port);
1963+
struct qca8k_mib_eth_data *mib_eth_data;
1964+
struct qca8k_priv *priv = ds->priv;
1965+
int ret;
1966+
1967+
mib_eth_data = &priv->mib_eth_data;
1968+
1969+
mutex_lock(&mib_eth_data->mutex);
1970+
1971+
reinit_completion(&mib_eth_data->rw_done);
1972+
1973+
mib_eth_data->req_port = dp->index;
1974+
mib_eth_data->data = data;
1975+
refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS);
1976+
1977+
mutex_lock(&priv->reg_mutex);
1978+
1979+
/* Send mib autocast request */
1980+
ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
1981+
QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
1982+
FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) |
1983+
QCA8K_MIB_BUSY);
1984+
1985+
mutex_unlock(&priv->reg_mutex);
1986+
1987+
if (ret)
1988+
goto exit;
1989+
1990+
ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
1991+
1992+
exit:
1993+
mutex_unlock(&mib_eth_data->mutex);
1994+
1995+
return ret;
1996+
}
1997+
19041998
static void
19051999
qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
19062000
uint64_t *data)
@@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
19122006
u32 hi = 0;
19132007
int ret;
19142008

2009+
if (priv->mgmt_master &&
2010+
qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
2011+
return;
2012+
19152013
match_data = of_device_get_match_data(priv->dev);
19162014

19172015
for (i = 0; i < match_data->mib_count; i++) {
@@ -2593,9 +2691,11 @@ qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
25932691
return;
25942692

25952693
mutex_lock(&priv->mgmt_eth_data.mutex);
2694+
mutex_lock(&priv->mib_eth_data.mutex);
25962695

25972696
priv->mgmt_master = operational ? (struct net_device *)master : NULL;
25982697

2698+
mutex_unlock(&priv->mib_eth_data.mutex);
25992699
mutex_unlock(&priv->mgmt_eth_data.mutex);
26002700
}
26012701

@@ -2609,6 +2709,7 @@ static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
26092709
tagger_data = ds->tagger_data;
26102710

26112711
tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
2712+
tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler;
26122713

26132714
break;
26142715
default:
@@ -2737,6 +2838,9 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
27372838
mutex_init(&priv->mgmt_eth_data.mutex);
27382839
init_completion(&priv->mgmt_eth_data.rw_done);
27392840

2841+
mutex_init(&priv->mib_eth_data.mutex);
2842+
init_completion(&priv->mib_eth_data.rw_done);
2843+
27402844
priv->ds->dev = &mdiodev->dev;
27412845
priv->ds->num_ports = QCA8K_NUM_PORTS;
27422846
priv->ds->priv = priv;

drivers/net/dsa/qca8k.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
#define QCA8K_REG_MODULE_EN 0x030
6868
#define QCA8K_MODULE_EN_MIB BIT(0)
6969
#define QCA8K_REG_MIB 0x034
70-
#define QCA8K_MIB_FLUSH BIT(24)
70+
#define QCA8K_MIB_FUNC GENMASK(26, 24)
7171
#define QCA8K_MIB_CPU_KEEP BIT(20)
7272
#define QCA8K_MIB_BUSY BIT(17)
7373
#define QCA8K_MDIO_MASTER_CTRL 0x3c
@@ -317,6 +317,12 @@ enum qca8k_vlan_cmd {
317317
QCA8K_VLAN_READ = 6,
318318
};
319319

320+
enum qca8k_mid_cmd {
321+
QCA8K_MIB_FLUSH = 1,
322+
QCA8K_MIB_FLUSH_PORT = 2,
323+
QCA8K_MIB_CAST = 3,
324+
};
325+
320326
struct ar8xxx_port_status {
321327
int enabled;
322328
};
@@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data {
340346
u32 data[4];
341347
};
342348

349+
struct qca8k_mib_eth_data {
350+
struct completion rw_done;
351+
struct mutex mutex; /* Process one command at time */
352+
refcount_t port_parsed; /* Counter to track parsed port */
353+
u8 req_port;
354+
u64 *data; /* pointer to ethtool data */
355+
};
356+
343357
struct qca8k_ports_config {
344358
bool sgmii_rx_clk_falling_edge;
345359
bool sgmii_tx_clk_falling_edge;
@@ -367,6 +381,7 @@ struct qca8k_priv {
367381
unsigned int port_mtu[QCA8K_NUM_PORTS];
368382
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
369383
struct qca8k_mgmt_eth_data mgmt_eth_data;
384+
struct qca8k_mib_eth_data mib_eth_data;
370385
};
371386

372387
struct qca8k_mib_desc {

0 commit comments

Comments
 (0)