From 462a088c474832b19ff2730de1e6bea66d399c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Sat, 15 Oct 2022 23:01:29 +0200 Subject: Add Turris kernel (includes patches from OpenWrt) --- ...8k-add-support-for-mib-autocast-in-Ethern.patch | 226 +++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 pkgs/patches-linux-5.15/766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch (limited to 'pkgs/patches-linux-5.15/766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch') diff --git a/pkgs/patches-linux-5.15/766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch b/pkgs/patches-linux-5.15/766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch new file mode 100644 index 0000000..c4bc2b3 --- /dev/null +++ b/pkgs/patches-linux-5.15/766-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch @@ -0,0 +1,226 @@ +From 5c957c7ca78cce5e4b96866722b0115bd758d945 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:30 +0100 +Subject: [PATCH 11/16] 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 +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++- + drivers/net/dsa/qca8k.h | 17 ++++++- + 2 files changed, 121 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv) + int ret; + + mutex_lock(&priv->reg_mutex); +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | ++ QCA8K_MIB_BUSY); + if (ret) + goto exit; + +@@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds, + ETH_GSTRING_LEN); + } + ++static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ const struct qca8k_match_data *match_data; ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ const struct qca8k_mib_desc *mib; ++ struct mib_ethhdr *mib_ethhdr; ++ int i, mib_len, offset = 0; ++ u64 *data; ++ u8 port; ++ ++ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); ++ mib_eth_data = &priv->mib_eth_data; ++ ++ /* The switch autocast every port. Ignore other packet and ++ * parse only the requested one. ++ */ ++ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); ++ if (port != mib_eth_data->req_port) ++ goto exit; ++ ++ match_data = device_get_match_data(priv->dev); ++ data = mib_eth_data->data; ++ ++ for (i = 0; i < match_data->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ ++ /* First 3 mib are present in the skb head */ ++ if (i < 3) { ++ data[i] = mib_ethhdr->data[i]; ++ continue; ++ } ++ ++ mib_len = sizeof(uint32_t); ++ ++ /* Some mib are 64 bit wide */ ++ if (mib->size == 2) ++ mib_len = sizeof(uint64_t); ++ ++ /* Copy the mib value from packet to the */ ++ memcpy(data + i, skb->data + offset, mib_len); ++ ++ /* Set the offset for the next mib */ ++ offset += mib_len; ++ } ++ ++exit: ++ /* Complete on receiving all the mib packet */ ++ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) ++ complete(&mib_eth_data->rw_done); ++} ++ ++static int ++qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ mib_eth_data = &priv->mib_eth_data; ++ ++ mutex_lock(&mib_eth_data->mutex); ++ ++ reinit_completion(&mib_eth_data->rw_done); ++ ++ mib_eth_data->req_port = dp->index; ++ mib_eth_data->data = data; ++ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Send mib autocast request */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | ++ QCA8K_MIB_BUSY); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ if (ret) ++ goto exit; ++ ++ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); ++ ++exit: ++ mutex_unlock(&mib_eth_data->mutex); ++ ++ return ret; ++} ++ + static void + qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +@@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switc + u32 hi = 0; + int ret; + ++ if (priv->mgmt_master && ++ qca8k_get_ethtool_stats_eth(ds, port, data) > 0) ++ return; ++ + match_data = of_device_get_match_data(priv->dev); + + for (i = 0; i < match_data->mib_count; i++) { +@@ -2592,9 +2690,11 @@ qca8k_master_change(struct dsa_switch *d + return; + + mutex_lock(&priv->mgmt_eth_data.mutex); ++ mutex_lock(&priv->mib_eth_data.mutex); + + priv->mgmt_master = operational ? (struct net_device *)master : NULL; + ++ mutex_unlock(&priv->mib_eth_data.mutex); + mutex_unlock(&priv->mgmt_eth_data.mutex); + } + +@@ -2608,6 +2708,7 @@ static int qca8k_connect_tag_protocol(st + tagger_data = ds->tagger_data; + + tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; ++ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; + + break; + default: +@@ -2736,6 +2837,9 @@ qca8k_sw_probe(struct mdio_device *mdiod + mutex_init(&priv->mgmt_eth_data.mutex); + init_completion(&priv->mgmt_eth_data.rw_done); + ++ mutex_init(&priv->mib_eth_data.mutex); ++ init_completion(&priv->mib_eth_data.rw_done); ++ + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = QCA8K_NUM_PORTS; + priv->ds->priv = priv; +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -67,7 +67,7 @@ + #define QCA8K_REG_MODULE_EN 0x030 + #define QCA8K_MODULE_EN_MIB BIT(0) + #define QCA8K_REG_MIB 0x034 +-#define QCA8K_MIB_FLUSH BIT(24) ++#define QCA8K_MIB_FUNC GENMASK(26, 24) + #define QCA8K_MIB_CPU_KEEP BIT(20) + #define QCA8K_MIB_BUSY BIT(17) + #define QCA8K_MDIO_MASTER_CTRL 0x3c +@@ -317,6 +317,12 @@ enum qca8k_vlan_cmd { + QCA8K_VLAN_READ = 6, + }; + ++enum qca8k_mid_cmd { ++ QCA8K_MIB_FLUSH = 1, ++ QCA8K_MIB_FLUSH_PORT = 2, ++ QCA8K_MIB_CAST = 3, ++}; ++ + struct ar8xxx_port_status { + int enabled; + }; +@@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data { + u32 data[4]; + }; + ++struct qca8k_mib_eth_data { ++ struct completion rw_done; ++ struct mutex mutex; /* Process one command at time */ ++ refcount_t port_parsed; /* Counter to track parsed port */ ++ u8 req_port; ++ u64 *data; /* pointer to ethtool data */ ++}; ++ + struct qca8k_ports_config { + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; +@@ -367,6 +381,7 @@ struct qca8k_priv { + unsigned int port_mtu[QCA8K_NUM_PORTS]; + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct qca8k_mgmt_eth_data mgmt_eth_data; ++ struct qca8k_mib_eth_data mib_eth_data; + }; + + struct qca8k_mib_desc { -- cgit v1.2.3