diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:46 +0000 |
commit | 7f3a4257159dea8e7ef66d1a539dc6df708b8ed3 (patch) | |
tree | bcc69b5f4609f348fac49e2f59e210b29eaea783 /drivers/net/ethernet/microchip | |
parent | Adding upstream version 6.9.12. (diff) | |
download | linux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.tar.xz linux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.zip |
Adding upstream version 6.10.3.upstream/6.10.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/net/ethernet/microchip')
28 files changed, 589 insertions, 70 deletions
diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index 443128adbc..3885d6fbac 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -75,7 +75,7 @@ static int regmap_encx24j600_sfr_read(void *context, u8 reg, u8 *val, if (unlikely(ret)) return ret; } else { - /* Translate registers that are more effecient using + /* Translate registers that are more efficient using * 3-byte SPI commands */ switch (reg) { @@ -129,7 +129,7 @@ static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx, if (unlikely(ret)) return ret; } else { - /* Translate registers that are more effecient using + /* Translate registers that are more efficient using * 3-byte SPI commands */ switch (reg) { diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c index d7c8aa77ec..b011bf5c23 100644 --- a/drivers/net/ethernet/microchip/encx24j600.c +++ b/drivers/net/ethernet/microchip/encx24j600.c @@ -569,7 +569,7 @@ static void encx24j600_dump_config(struct encx24j600_priv *priv, pr_info(DRV_NAME " MABBIPG: %04X\n", encx24j600_read_reg(priv, MABBIPG)); - /* PHY configuation */ + /* PHY configuration */ pr_info(DRV_NAME " PHCON1: %04X\n", encx24j600_read_phy(priv, PHCON1)); pr_info(DRV_NAME " PHCON2: %04X\n", encx24j600_read_phy(priv, PHCON2)); pr_info(DRV_NAME " PHANA: %04X\n", encx24j600_read_phy(priv, PHANA)); @@ -837,7 +837,9 @@ static void encx24j600_hw_tx(struct encx24j600_priv *priv) dump_packet("TX", priv->tx_skb->len, priv->tx_skb->data); if (encx24j600_read_reg(priv, EIR) & TXABTIF) - /* Last transmition aborted due to error. Reset TX interface */ + /* Last transmission aborted due to error. + * Reset TX interface + */ encx24j600_reset_hw_tx(priv); /* Clear the TXIF flag if were previously set */ @@ -1112,7 +1114,6 @@ MODULE_DEVICE_TABLE(spi, encx24j600_spi_id_table); static struct spi_driver encx24j600_spi_net_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .bus = &spi_bus_type, }, .probe = encx24j600_spi_probe, diff --git a/drivers/net/ethernet/microchip/encx24j600_hw.h b/drivers/net/ethernet/microchip/encx24j600_hw.h index 34c5a28989..2522f4f48b 100644 --- a/drivers/net/ethernet/microchip/encx24j600_hw.h +++ b/drivers/net/ethernet/microchip/encx24j600_hw.h @@ -243,7 +243,7 @@ int devm_regmap_init_encx24j600(struct device *dev, /* MAIPG */ /* value of the high byte is given by the reserved bits, - * value of the low byte is recomended setting of the + * value of the low byte is recommended setting of the * IPG parameter. */ #define MAIPGH_VAL 0x0C diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c index def932035c..0d1740d646 100644 --- a/drivers/net/ethernet/microchip/lan743x_ethtool.c +++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c @@ -1076,15 +1076,10 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev, buf = lan743x_csr_read(adapter, MAC_CR); if (buf & MAC_CR_EEE_EN_) { - eee->eee_enabled = true; - eee->tx_lpi_enabled = true; /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */ buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT); eee->tx_lpi_timer = buf; } else { - eee->eee_enabled = false; - eee->eee_active = false; - eee->tx_lpi_enabled = false; eee->tx_lpi_timer = 0; } @@ -1097,7 +1092,6 @@ static int lan743x_ethtool_set_eee(struct net_device *netdev, struct lan743x_adapter *adapter; struct phy_device *phydev; u32 buf = 0; - int ret = 0; if (!netdev) return -EINVAL; @@ -1114,23 +1108,8 @@ static int lan743x_ethtool_set_eee(struct net_device *netdev, } if (eee->eee_enabled) { - ret = phy_init_eee(phydev, false); - if (ret) { - netif_err(adapter, drv, adapter->netdev, - "EEE initialization failed\n"); - return ret; - } - buf = (u32)eee->tx_lpi_timer; lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf); - - buf = lan743x_csr_read(adapter, MAC_CR); - buf |= MAC_CR_EEE_EN_; - lan743x_csr_write(adapter, MAC_CR, buf); - } else { - buf = lan743x_csr_read(adapter, MAC_CR); - buf &= ~MAC_CR_EEE_EN_; - lan743x_csr_write(adapter, MAC_CR, buf); } return phy_ethtool_set_eee(phydev, eee); diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index ecde3582e3..e418539565 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -803,7 +803,7 @@ static int lan743x_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int index) u32 val, mii_access; int ret; - /* comfirm MII not busy */ + /* confirm MII not busy */ ret = lan743x_mac_mii_wait_till_not_busy(adapter); if (ret < 0) return ret; @@ -868,7 +868,7 @@ static int lan743x_mdiobus_read_c45(struct mii_bus *bus, int phy_id, u32 mmd_access; int ret; - /* comfirm MII not busy */ + /* confirm MII not busy */ ret = lan743x_mac_mii_wait_till_not_busy(adapter); if (ret < 0) return ret; @@ -1462,6 +1462,13 @@ static void lan743x_phy_link_status_change(struct net_device *netdev) phydev->interface == PHY_INTERFACE_MODE_1000BASEX || phydev->interface == PHY_INTERFACE_MODE_2500BASEX) lan743x_sgmii_config(adapter); + + data = lan743x_csr_read(adapter, MAC_CR); + if (phydev->enable_tx_lpi) + data |= MAC_CR_EEE_EN_; + else + data &= ~MAC_CR_EEE_EN_; + lan743x_csr_write(adapter, MAC_CR, data); } } @@ -3188,7 +3195,7 @@ static int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu) ret = lan743x_mac_set_mtu(adapter, new_mtu); if (!ret) - netdev->mtu = new_mtu; + WRITE_ONCE(netdev->mtu, new_mtu); return ret; } diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index 2801f08bf1..dcea6652d5 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -58,7 +58,7 @@ int lan743x_gpio_init(struct lan743x_adapter *adapter) static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter, u32 bit_mask) { - int timeout = 1000; + int timeout = PTP_CMD_CTL_TIMEOUT_CNT; u32 data = 0; while (timeout && @@ -555,7 +555,7 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, if (half == wf_high) { /* It's 50% match. Use the toggle option */ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_; - /* In this case, devide period value by 2 */ + /* In this case, divide period value by 2 */ ts_period = ns_to_timespec64(div_s64(period64, 2)); period_sec = ts_period.tv_sec; period_nsec = ts_period.tv_nsec; diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h index e26d4eff71..0d29914cd4 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.h +++ b/drivers/net/ethernet/microchip/lan743x_ptp.h @@ -21,6 +21,7 @@ #define LAN743X_PTP_N_EXTTS 4 #define LAN743X_PTP_N_PPS 0 #define PCI11X1X_PTP_IO_MAX_CHANNELS 8 +#define PTP_CMD_CTL_TIMEOUT_CNT 50 struct lan743x_adapter; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h b/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h index f3b1e0d318..e706163ce9 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ifh.h @@ -78,7 +78,7 @@ /* Classified internal priority for queuing */ #define IFH_POS_QOS_CLASS 100 -/* Bit mask with eight cpu copy classses */ +/* Bit mask with eight cpu copy classes */ #define IFH_POS_CPUQ 92 /* Relearn + learn flags (*) */ diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 6695ed661e..ec672af12e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -276,7 +276,7 @@ static int lan966x_port_ifh_xmit(struct sk_buff *skb, ++i; } - /* Inidcate EOF and valid bytes in the last word */ + /* Indicate EOF and valid bytes in the last word */ lan_wr(QS_INJ_CTRL_GAP_SIZE_SET(1) | QS_INJ_CTRL_VLD_BYTES_SET(skb->len < LAN966X_BUFFER_MIN_SZ ? 0 : last) | @@ -402,7 +402,7 @@ static int lan966x_port_change_mtu(struct net_device *dev, int new_mtu) lan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(LAN966X_HW_MTU(new_mtu)), lan966x, DEV_MAC_MAXLEN_CFG(port->chip_port)); - dev->mtu = new_mtu; + WRITE_ONCE(dev->mtu, new_mtu); if (!lan966x->fdma) return 0; @@ -520,7 +520,7 @@ bool lan966x_hw_offload(struct lan966x *lan966x, u32 port, struct sk_buff *skb) u32 val; /* The IGMP and MLD frames are not forward by the HW if - * multicast snooping is enabled, therefor don't mark as + * multicast snooping is enabled, therefore don't mark as * offload to allow the SW to forward the frames accordingly. */ val = lan_rd(lan966x, ANA_CPU_FWD_CFG(port)); diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index caa9e0533c..f8bebbcf77 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -326,7 +326,7 @@ struct lan966x { u8 base_mac[ETH_ALEN]; - spinlock_t tx_lock; /* lock for frame transmition */ + spinlock_t tx_lock; /* lock for frame transmission */ struct net_device *bridge; u16 bridge_mask; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 2e83bbb947..fdfa4040d9 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -88,7 +88,7 @@ static void lan966x_port_link_down(struct lan966x_port *port) SYS_FRONT_PORT_MODE_HDX_MODE, lan966x, SYS_FRONT_PORT_MODE(port->chip_port)); - /* 8: Flush the queues accociated with the port */ + /* 8: Flush the queues associated with the port */ lan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(3), QSYS_SW_PORT_MODE_AGING_MODE, lan966x, QSYS_SW_PORT_MODE(port->chip_port)); diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c index d696cf9dbd..43913d6204 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c @@ -45,6 +45,7 @@ static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, static int lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) { + struct netlink_ext_ack *extack = st->fco->common.extack; struct flow_match_control match; int err = 0; @@ -59,7 +60,7 @@ lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) VCAP_KF_L3_FRAGMENT, VCAP_BIT_0); if (err) - goto out; + goto bad_frag_out; } if (match.mask->flags & FLOW_DIS_FIRST_FRAG) { @@ -72,15 +73,20 @@ lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) VCAP_KF_L3_FRAG_OFS_GT0, VCAP_BIT_1); if (err) - goto out; + goto bad_frag_out; } + if (!flow_rule_is_supp_control_flags(FLOW_DIS_IS_FRAGMENT | + FLOW_DIS_FIRST_FRAG, + match.mask->flags, extack)) + return -EOPNOTSUPP; + st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL); return err; -out: - NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); +bad_frag_out: + NL_SET_ERR_MSG_MOD(extack, "ip_frag parse error"); return err; } diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c index 3c44660128..fa34a739c7 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c @@ -157,7 +157,7 @@ void lan966x_vlan_port_apply(struct lan966x_port *port) pvid = lan966x_vlan_port_get_pvid(port); - /* Ingress clasification (ANA_PORT_VLAN_CFG) */ + /* Ingress classification (ANA_PORT_VLAN_CFG) */ /* Default vlan to classify for untagged frames (may be zero) */ val = ANA_VLAN_CFG_VLAN_VID_SET(pvid); if (port->vlan_aware) diff --git a/drivers/net/ethernet/microchip/sparx5/Makefile b/drivers/net/ethernet/microchip/sparx5/Makefile index 1cb1cc3f1a..b68fe9c9a6 100644 --- a/drivers/net/ethernet/microchip/sparx5/Makefile +++ b/drivers/net/ethernet/microchip/sparx5/Makefile @@ -10,7 +10,8 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \ sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \ sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \ sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \ - sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o sparx5_psfp.o + sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \ + sparx5_psfp.o sparx5_mirror.o sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c index 141897dfe3..1915998f60 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c @@ -143,7 +143,7 @@ static void sparx5_fdma_rx_activate(struct sparx5 *sparx5, struct sparx5_rx *rx) static void sparx5_fdma_rx_deactivate(struct sparx5 *sparx5, struct sparx5_rx *rx) { - /* Dectivate the RX channel */ + /* Deactivate the RX channel */ spx5_rmw(0, BIT(rx->channel_id) & FDMA_CH_ACTIVATE_CH_ACTIVATE, sparx5, FDMA_CH_ACTIVATE); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index 3c066b62e6..b64c814eac 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -899,6 +899,9 @@ static int mchp_sparx5_probe(struct platform_device *pdev) dev_err(sparx5->dev, "PTP failed\n"); goto cleanup_ports; } + + INIT_LIST_HEAD(&sparx5->mall_entries); + goto cleanup_config; cleanup_ports: diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index 316fed5f27..1982ae03b4 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -18,6 +18,7 @@ #include <linux/ptp_clock_kernel.h> #include <linux/hrtimer.h> #include <linux/debugfs.h> +#include <net/flow_offload.h> #include "sparx5_main_regs.h" @@ -173,6 +174,7 @@ struct sparx5_port { struct phylink_config phylink_config; struct phylink *phylink; struct phylink_pcs phylink_pcs; + struct flow_stats mirror_stats; u16 portno; /* Ingress default VLAN (pvid) */ u16 pvid; @@ -227,6 +229,22 @@ struct sparx5_mdb_entry { u16 pgid_idx; }; +struct sparx5_mall_mirror_entry { + u32 idx; + struct sparx5_port *port; +}; + +struct sparx5_mall_entry { + struct list_head list; + struct sparx5_port *port; + unsigned long cookie; + enum flow_action_id type; + bool ingress; + union { + struct sparx5_mall_mirror_entry mirror; + }; +}; + #define SPARX5_PTP_TIMEOUT msecs_to_jiffies(10) #define SPARX5_SKB_CB(skb) \ ((struct sparx5_skb_cb *)((skb)->cb)) @@ -295,6 +313,7 @@ struct sparx5 { struct vcap_control *vcap_ctrl; /* PGID allocation map */ u8 pgid_map[PGID_TABLE_SIZE]; + struct list_head mall_entries; /* Common root for debugfs */ struct dentry *debugfs_root; }; @@ -541,6 +560,12 @@ void sparx5_psfp_init(struct sparx5 *sparx5); void sparx5_new_base_time(struct sparx5 *sparx5, const u32 cycle_time, const ktime_t org_base_time, ktime_t *new_base_time); +/* sparx5_mirror.c */ +int sparx5_mirror_add(struct sparx5_mall_entry *entry); +void sparx5_mirror_del(struct sparx5_mall_entry *entry); +void sparx5_mirror_stats(struct sparx5_mall_entry *entry, + struct flow_stats *fstats); + /* Clock period in picoseconds */ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock) { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h index bd03a0a3c1..22acc1f338 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h @@ -83,6 +83,64 @@ enum sparx5_target { #define ANA_AC_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_AC_OWN_UPSID_OWN_UPSID, x) +/* ANA_AC:MIRROR_PROBE:PROBE_CFG */ +#define ANA_AC_PROBE_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 0, 0, 1, 4) + +#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD GENMASK(31, 27) +#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x) +#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x) + +#define ANA_AC_PROBE_CFG_PROBE_CPU_SET GENMASK(26, 19) +#define ANA_AC_PROBE_CFG_PROBE_CPU_SET_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x) +#define ANA_AC_PROBE_CFG_PROBE_CPU_SET_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x) + +#define ANA_AC_PROBE_CFG_PROBE_VID GENMASK(18, 6) +#define ANA_AC_PROBE_CFG_PROBE_VID_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VID, x) +#define ANA_AC_PROBE_CFG_PROBE_VID_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VID, x) + +#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE GENMASK(5, 4) +#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x) +#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x) + +#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE GENMASK(3, 2) +#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x) +#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x) + +#define ANA_AC_PROBE_CFG_PROBE_DIRECTION GENMASK(1, 0) +#define ANA_AC_PROBE_CFG_PROBE_DIRECTION_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x) +#define ANA_AC_PROBE_CFG_PROBE_DIRECTION_GET(x)\ + FIELD_GET(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x) + +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG */ +#define ANA_AC_PROBE_PORT_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 8, 0, 1, 4) + +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG1 */ +#define ANA_AC_PROBE_PORT_CFG1(g) \ + __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 12, 0, 1, 4) + +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG2 */ +#define ANA_AC_PROBE_PORT_CFG2(g) \ + __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 16, 0, 1, 4) + +#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2 BIT(0) +#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_SET(x)\ + FIELD_PREP(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x) +#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_GET(x)\ + FIELD_GET(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x) + /* ANA_AC:SRC:SRC_CFG */ #define ANA_AC_SRC_CFG(g) __REG(TARGET_ANA_AC,\ 0, 1, 849920, g, 102, 16, 0, 0, 1, 4) @@ -6203,6 +6261,16 @@ enum sparx5_target { #define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE_GET(x)\ FIELD_GET(QFWD_SWITCH_PORT_MODE_LEARNALL_MORE, x) +/* QFWD:SYSTEM:FRAME_COPY_CFG */ +#define QFWD_FRAME_COPY_CFG(r)\ + __REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 284, r, 12, 4) + +#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL GENMASK(12, 6) +#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_SET(x)\ + FIELD_PREP(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) +#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_GET(x)\ + FIELD_GET(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) + /* QRES:RES_CTRL:RES_CFG */ #define QRES_RES_CFG(g) __REG(TARGET_QRES,\ 0, 1, 0, g, 5120, 16, 0, 0, 1, 4) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c new file mode 100644 index 0000000000..15db423be4 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip Sparx5 Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. + */ + +#include "sparx5_main.h" +#include "sparx5_main_regs.h" +#include "sparx5_tc.h" + +#define SPX5_MIRROR_PROBE_MAX 3 +#define SPX5_MIRROR_DISABLED 0 +#define SPX5_MIRROR_EGRESS 1 +#define SPX5_MIRROR_INGRESS 2 +#define SPX5_MIRROR_MONITOR_PORT_DEFAULT 65 +#define SPX5_QFWD_MP_OFFSET 9 /* Mirror port offset in the QFWD register */ + +/* Convert from bool ingress/egress to mirror direction */ +static u32 sparx5_mirror_to_dir(bool ingress) +{ + return ingress ? SPX5_MIRROR_INGRESS : SPX5_MIRROR_EGRESS; +} + +/* Get ports belonging to this mirror */ +static u64 sparx5_mirror_port_get(struct sparx5 *sparx5, u32 idx) +{ + return (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32 | + spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx)); +} + +/* Add port to mirror (only front ports) */ +static void sparx5_mirror_port_add(struct sparx5 *sparx5, u32 idx, u32 portno) +{ + u32 val, reg = portno; + + reg = portno / BITS_PER_BYTE; + val = BIT(portno % BITS_PER_BYTE); + + if (reg == 0) + return spx5_rmw(val, val, sparx5, ANA_AC_PROBE_PORT_CFG(idx)); + else + return spx5_rmw(val, val, sparx5, ANA_AC_PROBE_PORT_CFG1(idx)); +} + +/* Delete port from mirror (only front ports) */ +static void sparx5_mirror_port_del(struct sparx5 *sparx5, u32 idx, u32 portno) +{ + u32 val, reg = portno; + + reg = portno / BITS_PER_BYTE; + val = BIT(portno % BITS_PER_BYTE); + + if (reg == 0) + return spx5_rmw(0, val, sparx5, ANA_AC_PROBE_PORT_CFG(idx)); + else + return spx5_rmw(0, val, sparx5, ANA_AC_PROBE_PORT_CFG1(idx)); +} + +/* Check if mirror contains port */ +static bool sparx5_mirror_contains(struct sparx5 *sparx5, u32 idx, u32 portno) +{ + return (sparx5_mirror_port_get(sparx5, idx) & BIT_ULL(portno)) != 0; +} + +/* Check if mirror is empty */ +static bool sparx5_mirror_is_empty(struct sparx5 *sparx5, u32 idx) +{ + return sparx5_mirror_port_get(sparx5, idx) == 0; +} + +/* Get direction of mirror */ +static u32 sparx5_mirror_dir_get(struct sparx5 *sparx5, u32 idx) +{ + u32 val = spx5_rd(sparx5, ANA_AC_PROBE_CFG(idx)); + + return ANA_AC_PROBE_CFG_PROBE_DIRECTION_GET(val); +} + +/* Set direction of mirror */ +static void sparx5_mirror_dir_set(struct sparx5 *sparx5, u32 idx, u32 dir) +{ + spx5_rmw(ANA_AC_PROBE_CFG_PROBE_DIRECTION_SET(dir), + ANA_AC_PROBE_CFG_PROBE_DIRECTION, sparx5, + ANA_AC_PROBE_CFG(idx)); +} + +/* Set the monitor port for this mirror */ +static void sparx5_mirror_monitor_set(struct sparx5 *sparx5, u32 idx, + u32 portno) +{ + spx5_rmw(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_SET(portno), + QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, sparx5, + QFWD_FRAME_COPY_CFG(idx + SPX5_QFWD_MP_OFFSET)); +} + +/* Get the monitor port of this mirror */ +static u32 sparx5_mirror_monitor_get(struct sparx5 *sparx5, u32 idx) +{ + u32 val = spx5_rd(sparx5, + QFWD_FRAME_COPY_CFG(idx + SPX5_QFWD_MP_OFFSET)); + + return QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_GET(val); +} + +/* Check if port is the monitor port of this mirror */ +static bool sparx5_mirror_has_monitor(struct sparx5 *sparx5, u32 idx, + u32 portno) +{ + return sparx5_mirror_monitor_get(sparx5, idx) == portno; +} + +/* Get a suitable mirror for this port */ +static int sparx5_mirror_get(struct sparx5_port *sport, + struct sparx5_port *mport, u32 dir, u32 *idx) +{ + struct sparx5 *sparx5 = sport->sparx5; + u32 i; + + /* Check if this port is already used as a monitor port */ + for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) + if (sparx5_mirror_has_monitor(sparx5, i, sport->portno)) + return -EINVAL; + + /* Check if existing mirror can be reused + * (same direction and monitor port). + */ + for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) { + if (sparx5_mirror_dir_get(sparx5, i) == dir && + sparx5_mirror_has_monitor(sparx5, i, mport->portno)) { + *idx = i; + return 0; + } + } + + /* Return free mirror */ + for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) { + if (sparx5_mirror_is_empty(sparx5, i)) { + *idx = i; + return 0; + } + } + + return -ENOENT; +} + +int sparx5_mirror_add(struct sparx5_mall_entry *entry) +{ + u32 mirror_idx, dir = sparx5_mirror_to_dir(entry->ingress); + struct sparx5_port *sport, *mport; + struct sparx5 *sparx5; + int err; + + /* Source port */ + sport = entry->port; + /* monitor port */ + mport = entry->mirror.port; + sparx5 = sport->sparx5; + + if (sport->portno == mport->portno) + return -EINVAL; + + err = sparx5_mirror_get(sport, mport, dir, &mirror_idx); + if (err) + return err; + + if (sparx5_mirror_contains(sparx5, mirror_idx, sport->portno)) + return -EEXIST; + + /* Add port to mirror */ + sparx5_mirror_port_add(sparx5, mirror_idx, sport->portno); + + /* Set direction of mirror */ + sparx5_mirror_dir_set(sparx5, mirror_idx, dir); + + /* Set monitor port for mirror */ + sparx5_mirror_monitor_set(sparx5, mirror_idx, mport->portno); + + entry->mirror.idx = mirror_idx; + + return 0; +} + +void sparx5_mirror_del(struct sparx5_mall_entry *entry) +{ + struct sparx5_port *port = entry->port; + struct sparx5 *sparx5 = port->sparx5; + u32 mirror_idx = entry->mirror.idx; + + sparx5_mirror_port_del(sparx5, mirror_idx, port->portno); + if (!sparx5_mirror_is_empty(sparx5, mirror_idx)) + return; + + sparx5_mirror_dir_set(sparx5, mirror_idx, SPX5_MIRROR_DISABLED); + + sparx5_mirror_monitor_set(sparx5, + mirror_idx, + SPX5_MIRROR_MONITOR_PORT_DEFAULT); +} + +void sparx5_mirror_stats(struct sparx5_mall_entry *entry, + struct flow_stats *fstats) +{ + struct sparx5_port *port = entry->port; + struct rtnl_link_stats64 new_stats; + struct flow_stats *old_stats; + + old_stats = &entry->port->mirror_stats; + sparx5_get_stats64(port->ndev, &new_stats); + + if (entry->ingress) { + flow_stats_update(fstats, + new_stats.rx_bytes - old_stats->bytes, + new_stats.rx_packets - old_stats->pkts, + new_stats.rx_dropped - old_stats->drops, + old_stats->lastused, + FLOW_ACTION_HW_STATS_IMMEDIATE); + + old_stats->bytes = new_stats.rx_bytes; + old_stats->pkts = new_stats.rx_packets; + old_stats->drops = new_stats.rx_dropped; + old_stats->lastused = jiffies; + } else { + flow_stats_update(fstats, + new_stats.tx_bytes - old_stats->bytes, + new_stats.tx_packets - old_stats->pkts, + new_stats.tx_dropped - old_stats->drops, + old_stats->lastused, + FLOW_ACTION_HW_STATS_IMMEDIATE); + + old_stats->bytes = new_stats.tx_bytes; + old_stats->pkts = new_stats.tx_packets; + old_stats->drops = new_stats.tx_dropped; + old_stats->lastused = jiffies; + } +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c index ac7e1cffbc..f3f5fb4204 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c @@ -67,7 +67,7 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap) for (i = 0; i < IFH_LEN; i++) ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp)); - /* Decode IFH (whats needed) */ + /* Decode IFH (what's needed) */ sparx5_ifh_parse(ifh, &fi); /* Map to port netdev */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c index 60dd2fd603..062e486c00 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c @@ -370,7 +370,7 @@ static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, /* 6: Wait while the last frame is exiting the queues */ usleep_range(8 * spd_prm, 10 * spd_prm); - /* 7: Flush the queues accociated with the port->portno */ + /* 7: Flush the queues associated with the port->portno */ spx5_rmw(HSCH_FLUSH_CTRL_FLUSH_PORT_SET(port->portno) | HSCH_FLUSH_CTRL_FLUSH_DST_SET(1) | HSCH_FLUSH_CTRL_FLUSH_SRC_SET(1) | diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c index 4af85d108a..0b4abc3eb5 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c @@ -190,7 +190,7 @@ static int sparx5_port_bridge_join(struct sparx5_port *port, /* Remove standalone port entry */ sparx5_mact_forget(sparx5, ndev->dev_addr, 0); - /* Port enters in bridge mode therefor don't need to copy to CPU + /* Port enters in bridge mode therefore don't need to copy to CPU * frames for multicast in case the bridge is not requesting them */ __dev_mc_unsync(ndev, sparx5_mc_unsync); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c index 55f255a3c9..8d67d9f24c 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c @@ -159,13 +159,14 @@ out: static int sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) { + struct netlink_ext_ack *extack = st->fco->common.extack; struct flow_match_control mt; u32 value, mask; int err = 0; flow_rule_match_control(st->frule, &mt); - if (mt.mask->flags) { + if (mt.mask->flags & (FLOW_DIS_IS_FRAGMENT | FLOW_DIS_FIRST_FRAG)) { u8 is_frag_key = !!(mt.key->flags & FLOW_DIS_IS_FRAGMENT); u8 is_frag_mask = !!(mt.mask->flags & FLOW_DIS_IS_FRAGMENT); u8 is_frag_idx = (is_frag_key << 1) | is_frag_mask; @@ -178,7 +179,7 @@ sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) u8 vdt = sparx5_vcap_frag_map[is_frag_idx][first_frag_idx]; if (vdt == FRAG_INVAL) { - NL_SET_ERR_MSG_MOD(st->fco->common.extack, + NL_SET_ERR_MSG_MOD(extack, "Match on invalid fragment flag combination"); return -EINVAL; } @@ -190,16 +191,19 @@ sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_FRAGMENT_TYPE, value, mask); - if (err) - goto out; + if (err) { + NL_SET_ERR_MSG_MOD(extack, "ip_frag parse error"); + return err; + } } - st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL); + if (!flow_rule_is_supp_control_flags(FLOW_DIS_IS_FRAGMENT | + FLOW_DIS_FIRST_FRAG, + mt.mask->flags, extack)) + return -EOPNOTSUPP; - return err; + st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL); -out: - NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); return err; } @@ -1023,6 +1027,64 @@ static int sparx5_tc_action_vlan_push(struct vcap_admin *admin, return err; } +static void sparx5_tc_flower_set_port_mask(struct vcap_u72_action *ports, + struct net_device *ndev) +{ + struct sparx5_port *port = netdev_priv(ndev); + int byidx = port->portno / BITS_PER_BYTE; + int biidx = port->portno % BITS_PER_BYTE; + + ports->value[byidx] |= BIT(biidx); +} + +static int sparx5_tc_action_mirred(struct vcap_admin *admin, + struct vcap_rule *vrule, + struct flow_cls_offload *fco, + struct flow_action_entry *act) +{ + struct vcap_u72_action ports = {0}; + int err; + + if (admin->vtype != VCAP_TYPE_IS0 && admin->vtype != VCAP_TYPE_IS2) { + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Mirror action not supported in this VCAP"); + return -EOPNOTSUPP; + } + + err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, + SPX5_PMM_OR_DSTMASK); + if (err) + return err; + + sparx5_tc_flower_set_port_mask(&ports, act->dev); + + return vcap_rule_add_action_u72(vrule, VCAP_AF_PORT_MASK, &ports); +} + +static int sparx5_tc_action_redirect(struct vcap_admin *admin, + struct vcap_rule *vrule, + struct flow_cls_offload *fco, + struct flow_action_entry *act) +{ + struct vcap_u72_action ports = {0}; + int err; + + if (admin->vtype != VCAP_TYPE_IS0 && admin->vtype != VCAP_TYPE_IS2) { + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Redirect action not supported in this VCAP"); + return -EOPNOTSUPP; + } + + err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, + SPX5_PMM_REPLACE_ALL); + if (err) + return err; + + sparx5_tc_flower_set_port_mask(&ports, act->dev); + + return vcap_rule_add_action_u72(vrule, VCAP_AF_PORT_MASK, &ports); +} + /* Remove rule keys that may prevent templates from matching a keyset */ static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin, struct vcap_rule *vrule, @@ -1169,6 +1231,16 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, if (err) goto out; break; + case FLOW_ACTION_MIRRED: + err = sparx5_tc_action_mirred(admin, vrule, fco, act); + if (err) + goto out; + break; + case FLOW_ACTION_REDIRECT: + err = sparx5_tc_action_redirect(admin, vrule, fco, act); + if (err) + goto out; + break; case FLOW_ACTION_ACCEPT: err = sparx5_tc_set_actionset(admin, vrule); if (err) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c index d88a93f226..6b4d1d7b97 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c @@ -11,11 +11,44 @@ #include "sparx5_main.h" #include "sparx5_vcap_impl.h" +static struct sparx5_mall_entry * +sparx5_tc_matchall_entry_find(struct list_head *entries, unsigned long cookie) +{ + struct sparx5_mall_entry *entry; + + list_for_each_entry(entry, entries, list) { + if (entry->cookie == cookie) + return entry; + } + + return NULL; +} + +static void sparx5_tc_matchall_parse_action(struct sparx5_port *port, + struct sparx5_mall_entry *entry, + struct flow_action_entry *action, + bool ingress, + unsigned long cookie) +{ + entry->port = port; + entry->type = action->id; + entry->ingress = ingress; + entry->cookie = cookie; +} + +static void +sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry *entry, + struct flow_action_entry *action) +{ + entry->mirror.port = netdev_priv(action->dev); +} + static int sparx5_tc_matchall_replace(struct net_device *ndev, struct tc_cls_matchall_offload *tmo, bool ingress) { struct sparx5_port *port = netdev_priv(ndev); + struct sparx5_mall_entry *mall_entry; struct flow_action_entry *action; struct sparx5 *sparx5; int err; @@ -27,8 +60,45 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev, } action = &tmo->rule->action.entries[0]; + mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL); + if (!mall_entry) + return -ENOMEM; + + sparx5_tc_matchall_parse_action(port, + mall_entry, + action, + ingress, + tmo->cookie); + sparx5 = port->sparx5; switch (action->id) { + case FLOW_ACTION_MIRRED: + sparx5_tc_matchall_parse_mirror_action(mall_entry, action); + err = sparx5_mirror_add(mall_entry); + if (err) { + switch (err) { + case -EEXIST: + NL_SET_ERR_MSG_MOD(tmo->common.extack, + "Mirroring already exists"); + break; + case -EINVAL: + NL_SET_ERR_MSG_MOD(tmo->common.extack, + "Cannot mirror a monitor port"); + break; + case -ENOENT: + NL_SET_ERR_MSG_MOD(tmo->common.extack, + "No more mirror probes available"); + break; + default: + NL_SET_ERR_MSG_MOD(tmo->common.extack, + "Unknown error"); + break; + } + return err; + } + /* Get baseline stats for this port */ + sparx5_mirror_stats(mall_entry, &tmo->stats); + break; case FLOW_ACTION_GOTO: err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, tmo->common.chain_index, @@ -59,6 +129,9 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev, NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); return -EOPNOTSUPP; } + + list_add_tail(&mall_entry->list, &sparx5->mall_entries); + return 0; } @@ -67,19 +140,51 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev, bool ingress) { struct sparx5_port *port = netdev_priv(ndev); - struct sparx5 *sparx5; - int err; + struct sparx5 *sparx5 = port->sparx5; + struct sparx5_mall_entry *entry; + int err = 0; - sparx5 = port->sparx5; - if (!tmo->rule && tmo->cookie) { + entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries, + tmo->cookie); + if (!entry) + return -ENOENT; + + if (entry->type == FLOW_ACTION_MIRRED) { + sparx5_mirror_del(entry); + } else if (entry->type == FLOW_ACTION_GOTO) { err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0, 0, tmo->cookie, false); - if (err) - return err; - return 0; + } else { + NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); + err = -EOPNOTSUPP; } - NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); - return -EOPNOTSUPP; + + list_del(&entry->list); + + return err; +} + +static int sparx5_tc_matchall_stats(struct net_device *ndev, + struct tc_cls_matchall_offload *tmo, + bool ingress) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct sparx5 *sparx5 = port->sparx5; + struct sparx5_mall_entry *entry; + + entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries, + tmo->cookie); + if (!entry) + return -ENOENT; + + if (entry->type == FLOW_ACTION_MIRRED) { + sparx5_mirror_stats(entry, &tmo->stats); + } else { + NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); + return -EOPNOTSUPP; + } + + return 0; } int sparx5_tc_matchall(struct net_device *ndev, @@ -91,6 +196,8 @@ int sparx5_tc_matchall(struct net_device *ndev, return sparx5_tc_matchall_replace(ndev, tmo, ingress); case TC_CLSMATCHALL_DESTROY: return sparx5_tc_matchall_destroy(ndev, tmo, ingress); + case TC_CLSMATCHALL_STATS: + return sparx5_tc_matchall_stats(ndev, tmo, ingress); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h index c3569a4c7b..4735fad057 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h @@ -290,7 +290,7 @@ enum vcap_keyfield_set { * Sparx5: TCP flag RST , LAN966x: TCP: TCP flag RST. PTP over UDP: messageType * bit 3 * VCAP_KF_L4_SEQUENCE_EQ0_IS: W1, sparx5: is2/es2, lan966x: is2 - * Set if TCP sequence number is 0, LAN966x: Overlayed with PTP over UDP: + * Set if TCP sequence number is 0, LAN966x: Overlaid with PTP over UDP: * messageType bit 0 * VCAP_KF_L4_SPORT: W16, sparx5: is0/is2/es2, lan966x: is1/is2 * TCP/UDP source port diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index ef980e4e5b..2687765abe 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -327,7 +327,7 @@ static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl, } /* Verify that the typegroup information, subword count, keyset and type id - * are in sync and correct, return the list of matchin keysets + * are in sync and correct, return the list of matching keysets */ int vcap_find_keystream_keysets(struct vcap_control *vctrl, @@ -2907,6 +2907,18 @@ int vcap_rule_add_action_u32(struct vcap_rule *rule, } EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); +/* Add a 72 bit action field with value to the rule */ +int vcap_rule_add_action_u72(struct vcap_rule *rule, + enum vcap_action_field action, + struct vcap_u72_action *fieldval) +{ + struct vcap_client_actionfield_data data; + + memcpy(&data.u72, fieldval, sizeof(data.u72)); + return vcap_rule_add_action(rule, action, VCAP_FIELD_U72, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_action_u72); + static int vcap_read_counter(struct vcap_rule_internal *ri, struct vcap_counter *ctr) { @@ -2931,7 +2943,7 @@ void vcap_netbytes_copy(u8 *dst, u8 *src, int count) } EXPORT_SYMBOL_GPL(vcap_netbytes_copy); -/* Convert validation error code into tc extact error message */ +/* Convert validation error code into tc extack error message */ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) { switch (vrule->exterr) { diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h index 88641508f8..cdf79e17ca 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -200,6 +200,8 @@ int vcap_rule_add_action_bit(struct vcap_rule *rule, enum vcap_action_field action, enum vcap_bit val); int vcap_rule_add_action_u32(struct vcap_rule *rule, enum vcap_action_field action, u32 value); +int vcap_rule_add_action_u72(struct vcap_rule *rule, enum vcap_action_field action, + struct vcap_u72_action *fieldval); /* Get number of rules in a vcap instance lookup chain id range */ int vcap_admin_rule_count(struct vcap_admin *admin, int cid); @@ -236,7 +238,7 @@ const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl, /* Copy to host byte order */ void vcap_netbytes_copy(u8 *dst, u8 *src, int count); -/* Convert validation error code into tc extact error message */ +/* Convert validation error code into tc extack error message */ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule); /* Cleanup a VCAP instance */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h index df81d9ff50..844bdf6b5f 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h @@ -109,7 +109,7 @@ int vcap_addr_keysets(struct vcap_control *vctrl, struct net_device *ndev, struct vcap_keyset_list *kslist); /* Verify that the typegroup information, subword count, keyset and type id - * are in sync and correct, return the list of matchin keysets + * are in sync and correct, return the list of matching keysets */ int vcap_find_keystream_keysets(struct vcap_control *vctrl, enum vcap_type vt, u32 *keystream, u32 *mskstream, bool mask, |