From 0a2cdeeae9ddc14d752173be6af98bc9fb45c6ad Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 4 Nov 2024 15:00:41 +0800 Subject: [PATCH 01/16] net: tcp: replace the document for "lsndtime" in tcp_sock Commit d5fed5addb2b ("tcp: reorganize tcp_sock fast path variables") moved the fields around and misplaced the documentation for "lsndtime". So, let's replace it in the proper place. Signed-off-by: Menglong Dong Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20241104070041.64302-1-dongml2@chinatelecom.cn Signed-off-by: Jakub Kicinski --- include/linux/tcp.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 6a5e08b937b3..f88daaa76d83 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -200,7 +200,6 @@ struct tcp_sock { /* TX read-mostly hotpath cache lines */ __cacheline_group_begin(tcp_sock_read_tx); - /* timestamp of last sent data packet (for restart window) */ u32 max_window; /* Maximal window ever seen from peer */ u32 rcv_ssthresh; /* Current window clamp */ u32 reordering; /* Packet reordering metric. */ @@ -263,7 +262,7 @@ struct tcp_sock { u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ u32 pushed_seq; /* Last pushed seq, required to talk to windows */ - u32 lsndtime; + u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ u32 mdev_us; /* medium deviation */ u32 rtt_seq; /* sequence number to update rttvar */ u64 tcp_wstamp_ns; /* departure time for next sent data packet */ -- 2.51.0 From 690e50dd69ee48e43e0f7c42396487da1b81be14 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 3 Nov 2024 08:53:14 -0800 Subject: [PATCH 02/16] tools: ynl-gen: de-kdocify enums with no doc for entries Sometimes the names of the enum entries are self-explanatory or come from standards. Forcing authors to write trivial kdoc for each of such entries seems unreasonable, but kdoc would complain about undocumented entries. Detect enums which only have documentation for the entire type and no documentation for entries. Render their doc as a plain comment. Link: https://patch.msgid.link/20241103165314.1631237-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/uapi/linux/dpll.h | 14 +++++++------- tools/net/ynl/lib/nlspec.py | 3 +++ tools/net/ynl/ynl-gen-c.py | 14 +++++++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 2b7ec2da4bcc..bf97d4b6d51f 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -79,13 +79,13 @@ enum dpll_lock_status_error { DPLL_LOCK_STATUS_ERROR_MAX = (__DPLL_LOCK_STATUS_ERROR_MAX - 1) }; -/** - * enum dpll_clock_quality_level - level of quality of a clock device. This - * mainly applies when the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. The - * current list is defined according to the table 11-7 contained in ITU-T - * G.8264/Y.1364 document. One may extend this list freely by other ITU-T - * defined clock qualities, or different ones defined by another - * standardization body (for those, please use different prefix). +/* + * level of quality of a clock device. This mainly applies when the dpll + * lock-status is DPLL_LOCK_STATUS_HOLDOVER. The current list is defined + * according to the table 11-7 contained in ITU-T G.8264/Y.1364 document. One + * may extend this list freely by other ITU-T defined clock qualities, or + * different ones defined by another standardization body (for those, please + * use different prefix). */ enum dpll_clock_quality_level { DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC = 1, diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index b6d6f8aef423..a745739655ad 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -131,6 +131,9 @@ class SpecEnumSet(SpecElement): def has_doc(self): if 'doc' in self.yaml: return True + return self.has_entry_doc() + + def has_entry_doc(self): for entry in self.entries.values(): if entry.has_doc(): return True diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index aa22eb092475..c48b69071111 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2437,11 +2437,15 @@ def render_uapi(family, cw): enum = family.consts[const['name']] if enum.has_doc(): - cw.p('/**') - doc = '' - if 'doc' in enum: - doc = ' - ' + enum['doc'] - cw.write_doc_line(enum.enum_name + doc) + if enum.has_entry_doc(): + cw.p('/**') + doc = '' + if 'doc' in enum: + doc = ' - ' + enum['doc'] + cw.write_doc_line(enum.enum_name + doc) + else: + cw.p('/*') + cw.write_doc_line(enum['doc'], indent=False) for entry in enum.entries.values(): if entry.has_doc(): doc = '@' + entry.c_name + ': ' + entry['doc'] -- 2.51.0 From b356b9170815f822394667010d478d53901ff581 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sun, 3 Nov 2024 19:41:49 +0000 Subject: [PATCH 03/16] net: ena: Remove autopolling mode This manually reverts commit a4e262cde3cd ("net: ena: allow automatic fallback to polling mode") which is unused. (I did it manually because there are other minor comment and function changes surrounding it). Build tested only. Suggested-by: David Arinzon Signed-off-by: Dr. David Alan Gilbert Link: https://patch.msgid.link/20241103194149.293456-1-linux@treblig.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amazon/ena/ena_com.c | 25 +++++------------------ drivers/net/ethernet/amazon/ena/ena_com.h | 14 ------------- 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index d958cda9e58b..b23331ea2478 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -763,25 +763,16 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com if (comp_ctx->status == ENA_CMD_COMPLETED) { netdev_err(admin_queue->ena_dev->net_device, - "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", - comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF"); - /* Check if fallback to polling is enabled */ - if (admin_queue->auto_polling) - admin_queue->polling = true; + "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d)\n", + comp_ctx->cmd_opcode); } else { netdev_err(admin_queue->ena_dev->net_device, "The ena device didn't send a completion for the admin cmd %d status %d\n", comp_ctx->cmd_opcode, comp_ctx->status); } - /* Check if shifted to polling mode. - * This will happen if there is a completion without an interrupt - * and autopolling mode is enabled. Continuing normal execution in such case - */ - if (!admin_queue->polling) { - admin_queue->running_state = false; - ret = -ETIME; - goto err; - } + admin_queue->running_state = false; + ret = -ETIME; + goto err; } ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); @@ -1650,12 +1641,6 @@ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling) ena_dev->admin_queue.polling = polling; } -void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev, - bool polling) -{ - ena_dev->admin_queue.auto_polling = polling; -} - int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) { struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index a372c5e768a7..975876cfe720 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -224,9 +224,6 @@ struct ena_com_admin_queue { /* Indicate if the admin queue should poll for completion */ bool polling; - /* Define if fallback to polling mode should occur */ - bool auto_polling; - u16 curr_cmd_id; /* Indicate that the ena was initialized and can @@ -493,17 +490,6 @@ bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev); */ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling); -/* ena_com_set_admin_auto_polling_mode - Enable autoswitch to polling mode - * @ena_dev: ENA communication layer struct - * @polling: Enable/Disable polling mode - * - * Set the autopolling mode. - * If autopolling is on: - * In case of missing interrupt when data is available switch to polling. - */ -void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev, - bool polling); - /* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler * @ena_dev: ENA communication layer struct * -- 2.51.0 From 6a7d68f72797de9ba8a5129975d42994ae27635d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sat, 2 Nov 2024 22:01:42 +0000 Subject: [PATCH 04/16] net: ena: Remove deadcode ena_com_get_dev_basic_stats() has been unused since 2017's commit d81db2405613 ("net/ena: refactor ena_get_stats64 to be atomic context safe") ena_com_get_offload_settings() has been unused since the original commit of ENA back in 2016 in commit 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Remove them. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: David Arinzon Link: https://patch.msgid.link/20241102220142.80285-1-linux@treblig.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amazon/ena/ena_com.c | 33 ----------------------- drivers/net/ethernet/amazon/ena/ena_com.h | 18 ------------- 2 files changed, 51 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index b23331ea2478..66445617fbfb 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -2183,21 +2183,6 @@ int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev, return ret; } -int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, - struct ena_admin_basic_stats *stats) -{ - struct ena_com_stats_ctx ctx; - int ret; - - memset(&ctx, 0x0, sizeof(ctx)); - ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC); - if (likely(ret == 0)) - memcpy(stats, &ctx.get_resp.u.basic_stats, - sizeof(ctx.get_resp.u.basic_stats)); - - return ret; -} - int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len) { struct ena_admin_aq_get_stats_cmd *get_cmd; @@ -2274,24 +2259,6 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) return ret; } -int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, - struct ena_admin_feature_offload_desc *offload) -{ - int ret; - struct ena_admin_get_feat_resp resp; - - ret = ena_com_get_feature(ena_dev, &resp, - ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); - if (unlikely(ret)) { - netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret); - return ret; - } - - memcpy(offload, &resp.u.offload, sizeof(resp.u.offload)); - - return 0; -} - int ena_com_set_hash_function(struct ena_com_dev *ena_dev) { struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 975876cfe720..9414e93d107b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -577,15 +577,6 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag); int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, struct ena_com_dev_get_features_ctx *get_feat_ctx); -/* ena_com_get_dev_basic_stats - Get device basic statistics - * @ena_dev: ENA communication layer struct - * @stats: stats return value - * - * @return: 0 on Success and negative value otherwise. - */ -int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, - struct ena_admin_basic_stats *stats); - /* ena_com_get_eni_stats - Get extended network interface statistics * @ena_dev: ENA communication layer struct * @stats: stats return value @@ -621,15 +612,6 @@ int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 */ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu); -/* ena_com_get_offload_settings - Retrieve the device offloads capabilities - * @ena_dev: ENA communication layer struct - * @offlad: offload return value - * - * @return: 0 on Success and negative value otherwise. - */ -int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, - struct ena_admin_feature_offload_desc *offload); - /* ena_com_rss_init - Init RSS * @ena_dev: ENA communication layer struct * @log_size: indirection log size -- 2.51.0 From 18ec5491a4959e11ab37438e0b1ff8e3638ceafa Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 2 Nov 2024 16:52:17 -0500 Subject: [PATCH 05/16] ptp: Remove 'default y' for VMCLOCK PTP device The VMCLOCK device gives support for accurate timekeeping even across live migration, unlike the KVM PTP clock. To help ensure that users can always use ptp_vmclock where it's available in preference to ptp_kvm, set it to 'default PTP_1588_CLOCK_VMCLOCK' instead of 'default y'. Signed-off-by: David Woodhouse Link: https://patch.msgid.link/89955b74d225129d6e3d79b53aa8d81d1b50560f.camel@infradead.org Signed-off-by: Jakub Kicinski --- drivers/ptp/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 3eac514195af..07bf7f9aae01 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -135,12 +135,16 @@ config PTP_1588_CLOCK_VMCLOCK tristate "Virtual machine PTP clock" depends on X86_TSC || ARM_ARCH_TIMER depends on PTP_1588_CLOCK && ACPI && ARCH_SUPPORTS_INT128 - default y + default PTP_1588_CLOCK_KVM help This driver adds support for using a virtual precision clock advertised by the hypervisor. This clock is only useful in virtual machines where such a device is present. + Unlike the KVM virtual PTP clock, the VMCLOCK device offers support + for reliable timekeeping even across live migration. So this driver + is enabled by default whenever the KVM PTP clock is. + To compile this driver as a module, choose M here: the module will be called ptp_vmclock. -- 2.51.0 From d2068805f688ce6e9c6099f3636879fa76e76497 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 1 Nov 2024 14:48:27 -0700 Subject: [PATCH 06/16] net: ena: remove devm from ethtool There's no need for devm bloat here. In addition, these are freed right before the function exits. Also swapped kcalloc order for consistency. Signed-off-by: Rosen Penev Reviewed-by: Shay Agroskin Link: https://patch.msgid.link/20241101214828.289752-2-rosenp@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 60fb35ec4b15..a3c934c3de71 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -1129,22 +1129,18 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) return; } - strings_buf = devm_kcalloc(&adapter->pdev->dev, - ETH_GSTRING_LEN, strings_num, - GFP_ATOMIC); + strings_buf = kcalloc(strings_num, ETH_GSTRING_LEN, GFP_ATOMIC); if (!strings_buf) { netif_err(adapter, drv, netdev, "Failed to allocate strings_buf\n"); return; } - data_buf = devm_kcalloc(&adapter->pdev->dev, - strings_num, sizeof(u64), - GFP_ATOMIC); + data_buf = kcalloc(strings_num, sizeof(u64), GFP_ATOMIC); if (!data_buf) { netif_err(adapter, drv, netdev, "Failed to allocate data buf\n"); - devm_kfree(&adapter->pdev->dev, strings_buf); + kfree(strings_buf); return; } @@ -1166,8 +1162,8 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) strings_buf + i * ETH_GSTRING_LEN, data_buf[i]); - devm_kfree(&adapter->pdev->dev, strings_buf); - devm_kfree(&adapter->pdev->dev, data_buf); + kfree(strings_buf); + kfree(data_buf); } void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf) -- 2.51.0 From a12fcef429e17cb3db47cde0692a185d3ca712a3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 29 Oct 2024 18:43:15 +0200 Subject: [PATCH 07/16] soc: fsl_qbman: use be16_to_cpu() in qm_sg_entry_get_off() struct qm_sg_entry :: offset is a 13-bit field, declared as __be16. When using be32_to_cpu(), a wrong value will be calculated on little endian systems (Arm), because type promotion from 16-bit to 32-bit, which is done before the byte swap and always in the CPU native endianness, changes the value of the scatter/gather list entry offset in big-endian interpretation (adds two zero bytes in the LSB interpretation). The result of the byte swap is ANDed with GENMASK(12, 0), so the result is always zero, because only those bytes added by type promotion remain after the application of the bit mask. The impact of the bug is that scatter/gather frames with a non-zero offset into the buffer are treated by the driver as if they had a zero offset. This is all in theory, because in practice, qm_sg_entry_get_off() has a single caller, where the bug is inconsequential, because at that call site the buffer offset will always be zero, as will be explained in the subsequent change. Flagged by sparse: warning: cast to restricted __be32 warning: cast from restricted __be16 Signed-off-by: Vladimir Oltean Reviewed-by: Breno Leitao Acked-by: Christophe Leroy Acked-by: Madalin Bucur Link: https://patch.msgid.link/20241029164317.50182-2-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- include/soc/fsl/qman.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index 0d3d6beb7fdb..7f7a4932d7f1 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -242,7 +242,7 @@ static inline void qm_sg_entry_set_f(struct qm_sg_entry *sg, int len) static inline int qm_sg_entry_get_off(const struct qm_sg_entry *sg) { - return be32_to_cpu(sg->offset) & QM_SG_OFF_MASK; + return be16_to_cpu(sg->offset) & QM_SG_OFF_MASK; } /* "Frame Dequeue Response" */ -- 2.51.0 From 81f8ee2823f321c297d9d41f7e6b8fc81750b4ee Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 29 Oct 2024 18:43:16 +0200 Subject: [PATCH 08/16] net: dpaa_eth: add assertions about SGT entry offsets in sg_fd_to_skb() Multi-buffer frame descriptors (FDs) point to a buffer holding a scatter/gather table (SGT), which is a finite array of fixed-size entries, the last of which has qm_sg_entry_is_final(&sgt[i]) == true. Each SGT entry points to a buffer holding pieces of the frame. DPAARM.pdf explains in the figure called "Internal and External Margins, Scatter/Gather Frame Format" that the SGT table is located within its buffer at the same offset as the frame data start is located within the first packet buffer. +------------------------+ Scatter/Gather Buffer | First Buffer | Last Buffer ^ +------------+ ^ +-|---->^ +------------+ +->+------------+ | | | | ICEOF | | | | | |////////////| | +------------+ v | | | | | |////////////| BSM | |/ part of //| | |BSM | | | |////////////| | |/ Internal /| | | | | | |////////////| | |/ Context //| | | | | | |// Frame ///| | +------------+ | | | | | ... |/ content //| | | | | | | | | |////////////| | | | | | | | | |////////////| v +------------+ | | v +------------+ |////////////| | Scatter/ //| sgt[0]--+ | |// Frame ///| |////////////| | Gather List| ... | |/ content //| +------------+ ^ |////////////| sgt[N]----+ |////////////| | | | BEM |////////////| |////////////| | | | +------------+ +------------+ +------------+ v BSM = Buffer Start Margin, BEM = Buffer End Margin, both are configured by dpaa_eth_init_rx_port() for the RX FMan port relevant here. sg_fd_to_skb() runs in the calling context of rx_default_dqrr() - the NAPI receive callback - which only expects to receive contiguous (qm_fd_contig) or scatter/gather (qm_fd_sg) frame descriptors. Everything else is irrelevant codewise. The processing done by sg_fd_to_skb() is weird because it does not conform to the expectations laid out by the aforementioned figure. Namely, it parses the OFFSET field only for SGT entries with i != 0 (codewise, skb != NULL). In those cases, OFFSET should always be 0. Also, it does not parse the OFFSET field for the sgt[0] case, the only case where the buffer offset is meaningful in this context. There, it uses the fd_off, aka the offset to the Scatter/Gather List in the Scatter/Gather Buffer from the figure. By equivalence, they should both be equal to the BSM (in turn, equal to priv->rx_headroom). This can actually be explained due to the bug which we had in qm_sg_entry_get_off() until the previous change: - qm_sg_entry_get_off() did not actually _work_ for sgt[0]. It returned zero even with a non-zero offset, so fd_off had to be used as a fill-in. - qm_sg_entry_get_off() always returned zero for sgt[i>0], and that resulted in no user-visible bug, because the buffer offset _was supposed_ to be zero for those buffers. So remove it from calculations. Add assertions about the OFFSET field in both cases (first or subsequent SGT entries) to make it absolutely obvious when something is not well handled. Similar logic can be seen in the driver for the architecturally similar DPAA2, where dpaa2_eth_build_frag_skb() calls dpaa2_sg_get_offset() only for i == 0. For the rest, there is even a comment stating the same thing: * Data in subsequent SG entries is stored from the * beginning of the buffer, so we don't need to add the * sg_offset. Tested on LS1046A. Signed-off-by: Vladimir Oltean Acked-by: Christophe Leroy Acked-by: Madalin Bucur Link: https://patch.msgid.link/20241029164317.50182-3-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/freescale/dpaa/dpaa_eth.c | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index ac06b01fe934..e280013afa63 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1820,7 +1820,6 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, struct page *page, *head_page; struct dpaa_bp *dpaa_bp; void *vaddr, *sg_vaddr; - int frag_off, frag_len; struct sk_buff *skb; dma_addr_t sg_addr; int page_offset; @@ -1863,6 +1862,11 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, * on Tx, if extra headers are added. */ WARN_ON(fd_off != priv->rx_headroom); + /* The offset to data start within the buffer holding + * the SGT should always be equal to the offset to data + * start within the first buffer holding the frame. + */ + WARN_ON_ONCE(fd_off != qm_sg_entry_get_off(&sgt[i])); skb_reserve(skb, fd_off); skb_put(skb, qm_sg_entry_get_len(&sgt[i])); } else { @@ -1876,21 +1880,23 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, page = virt_to_page(sg_vaddr); head_page = virt_to_head_page(sg_vaddr); - /* Compute offset in (possibly tail) page */ + /* Compute offset of sg_vaddr in (possibly tail) page */ page_offset = ((unsigned long)sg_vaddr & (PAGE_SIZE - 1)) + (page_address(page) - page_address(head_page)); - /* page_offset only refers to the beginning of sgt[i]; - * but the buffer itself may have an internal offset. + + /* Non-initial SGT entries should not have a buffer + * offset. */ - frag_off = qm_sg_entry_get_off(&sgt[i]) + page_offset; - frag_len = qm_sg_entry_get_len(&sgt[i]); + WARN_ON_ONCE(qm_sg_entry_get_off(&sgt[i])); + /* skb_add_rx_frag() does no checking on the page; if * we pass it a tail page, we'll end up with - * bad page accounting and eventually with segafults. + * bad page accounting and eventually with segfaults. */ - skb_add_rx_frag(skb, i - 1, head_page, frag_off, - frag_len, dpaa_bp->size); + skb_add_rx_frag(skb, i - 1, head_page, page_offset, + qm_sg_entry_get_len(&sgt[i]), + dpaa_bp->size); } /* Update the pool count for the current {cpu x bpool} */ -- 2.51.0 From 0a746cf8bb6df43566c345f334ca1b931f926449 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 29 Oct 2024 18:43:17 +0200 Subject: [PATCH 09/16] net: dpaa_eth: extract hash using __be32 pointer in rx_default_dqrr() Sparse provides the following output: warning: cast to restricted __be32 This is a harmless warning due to the fact that we dereference the hash stored in the FD using an incorrect type annotation. Suppress the warning by using the correct __be32 type instead of u32. No functional change. Signed-off-by: Vladimir Oltean Reviewed-by: Breno Leitao Acked-by: Christophe Leroy Acked-by: Madalin Bucur Link: https://patch.msgid.link/20241029164317.50182-4-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index e280013afa63..bf5baef5c3e0 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2772,7 +2772,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use && !fman_port_get_hash_result_offset(priv->mac_dev->port[RX], &hash_offset)) { - hash = be32_to_cpu(*(u32 *)(vaddr + hash_offset)); + hash = be32_to_cpu(*(__be32 *)(vaddr + hash_offset)); hash_valid = true; } -- 2.51.0 From 6aacd1484468361d1d04badfe75f264fa5314864 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Tue, 29 Oct 2024 16:46:12 +0800 Subject: [PATCH 10/16] virtio-net: fix overflow inside virtnet_rq_alloc When the frag just got a page, then may lead to regression on VM. Specially if the sysctl net.core.high_order_alloc_disable value is 1, then the frag always get a page when do refill. Which could see reliable crashes or scp failure (scp a file 100M in size to VM). The issue is that the virtnet_rq_dma takes up 16 bytes at the beginning of a new frag. When the frag size is larger than PAGE_SIZE, everything is fine. However, if the frag is only one page and the total size of the buffer and virtnet_rq_dma is larger than one page, an overflow may occur. The commit f9dac92ba908 ("virtio_ring: enable premapped mode whatever use_dma_api") introduced this problem. And we reverted some commits to fix this in last linux version. Now we try to enable it and fix this bug directly. Here, when the frag size is not enough, we reduce the buffer len to fix this problem. Reported-by: "Si-Wei Liu" Tested-by: Darren Kenny Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Paolo Abeni --- drivers/net/virtio_net.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 869586c17ffd..3ff063fff443 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -926,9 +926,6 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) void *buf, *head; dma_addr_t addr; - if (unlikely(!skb_page_frag_refill(size, alloc_frag, gfp))) - return NULL; - head = page_address(alloc_frag->page); if (rq->do_dma) { @@ -2423,6 +2420,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, len = SKB_DATA_ALIGN(len) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + if (unlikely(!skb_page_frag_refill(len, &rq->alloc_frag, gfp))) + return -ENOMEM; + buf = virtnet_rq_alloc(rq, len, gfp); if (unlikely(!buf)) return -ENOMEM; @@ -2525,6 +2525,12 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, */ len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room); + if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp))) + return -ENOMEM; + + if (!alloc_frag->offset && len + room + sizeof(struct virtnet_rq_dma) > alloc_frag->size) + len -= sizeof(struct virtnet_rq_dma); + buf = virtnet_rq_alloc(rq, len + room, gfp); if (unlikely(!buf)) return -ENOMEM; -- 2.51.0 From a33f3df850750216f432b637a5020ad6a740cac1 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Tue, 29 Oct 2024 16:46:13 +0800 Subject: [PATCH 11/16] virtio_net: big mode skip the unmap check The virtio-net big mode did not enable premapped mode, so we did not need to check the unmap. And the subsequent commit will remove the failover code for failing enable premapped for merge and small mode. So we need to remove the checking do_dma code in the big mode path. Tested-by: Darren Kenny Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Paolo Abeni --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 3ff063fff443..b82f6b8a8231 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -987,7 +987,7 @@ static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf) return; } - if (rq->do_dma) + if (!vi->big_packets || vi->mergeable_rx_bufs) virtnet_rq_unmap(rq, buf, 0); virtnet_rq_free_buf(vi, rq, buf); @@ -2712,7 +2712,7 @@ static int virtnet_receive_packets(struct virtnet_info *vi, } } else { while (packets < budget && - (buf = virtnet_rq_get_buf(rq, &len, NULL)) != NULL) { + (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { receive_buf(vi, rq, buf, len, NULL, xdp_xmit, stats); packets++; } -- 2.51.0 From 47008bb51c3e11c187dacc17af334bdca97c2dca Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Tue, 29 Oct 2024 16:46:14 +0800 Subject: [PATCH 12/16] virtio_net: enable premapped mode for merge and small by default Currently, the virtio core will perform a dma operation for each buffer. Although, the same page may be operated multiple times. In premapped mod, we can perform only one dma operation for the pages of the alloc frag. This is beneficial for the iommu device. kernel command line: intel_iommu=on iommu.passthrough=0 | strict=0 | strict=1 Before | 775496pps | 428614pps After | 1109316pps | 742853pps In the 6.11, we disabled this feature because a regress [1]. Now, we fix the problem and re-enable it. [1]: http://lore.kernel.org/all/8b20cc28-45a9-4643-8e87-ba164a540c0a@oracle.com Tested-by: Darren Kenny Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Paolo Abeni --- drivers/net/virtio_net.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b82f6b8a8231..befc30b3abb1 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -6107,6 +6107,17 @@ err_ctrl: return -ENOMEM; } +static void virtnet_rq_set_premapped(struct virtnet_info *vi) +{ + int i; + + for (i = 0; i < vi->max_queue_pairs; i++) { + /* error should never happen */ + BUG_ON(virtqueue_set_dma_premapped(vi->rq[i].vq)); + vi->rq[i].do_dma = true; + } +} + static int init_vqs(struct virtnet_info *vi) { int ret; @@ -6120,6 +6131,10 @@ static int init_vqs(struct virtnet_info *vi) if (ret) goto err_free; + /* disable for big mode */ + if (!vi->big_packets || vi->mergeable_rx_bufs) + virtnet_rq_set_premapped(vi); + cpus_read_lock(); virtnet_set_affinity(vi); cpus_read_unlock(); -- 2.51.0 From fb22437c1ba37fc54eff949023923cc7887aaaa1 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Tue, 29 Oct 2024 16:46:15 +0800 Subject: [PATCH 13/16] virtio_net: rx remove premapped failover code Now, the premapped mode can be enabled unconditionally. So we can remove the failover code for merge and small mode. The virtnet_rq_xxx() helper would be only used if the mode is using pre mapping. A check is added to prevent misusing of these API. Tested-by: Darren Kenny Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Paolo Abeni --- drivers/net/virtio_net.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index befc30b3abb1..4b27ded8fc16 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -356,9 +356,6 @@ struct receive_queue { struct xdp_rxq_info xsk_rxq_info; struct xdp_buff **xsk_buffs; - - /* Do dma by self */ - bool do_dma; }; /* This structure can contain rss message with maximum settings for indirection table and keysize @@ -856,11 +853,14 @@ ok: static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len) { + struct virtnet_info *vi = rq->vq->vdev->priv; struct page *page = virt_to_head_page(buf); struct virtnet_rq_dma *dma; void *head; int offset; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); + head = page_address(page); dma = head; @@ -885,10 +885,13 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len) static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx) { + struct virtnet_info *vi = rq->vq->vdev->priv; void *buf; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); + buf = virtqueue_get_buf_ctx(rq->vq, len, ctx); - if (buf && rq->do_dma) + if (buf) virtnet_rq_unmap(rq, buf, *len); return buf; @@ -896,15 +899,13 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx) static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len) { + struct virtnet_info *vi = rq->vq->vdev->priv; struct virtnet_rq_dma *dma; dma_addr_t addr; u32 offset; void *head; - if (!rq->do_dma) { - sg_init_one(rq->sg, buf, len); - return; - } + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); head = page_address(rq->alloc_frag.page); @@ -922,50 +923,51 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len) static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) { struct page_frag *alloc_frag = &rq->alloc_frag; + struct virtnet_info *vi = rq->vq->vdev->priv; struct virtnet_rq_dma *dma; void *buf, *head; dma_addr_t addr; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); + head = page_address(alloc_frag->page); - if (rq->do_dma) { - dma = head; - - /* new pages */ - if (!alloc_frag->offset) { - if (rq->last_dma) { - /* Now, the new page is allocated, the last dma - * will not be used. So the dma can be unmapped - * if the ref is 0. - */ - virtnet_rq_unmap(rq, rq->last_dma, 0); - rq->last_dma = NULL; - } + dma = head; - dma->len = alloc_frag->size - sizeof(*dma); + /* new pages */ + if (!alloc_frag->offset) { + if (rq->last_dma) { + /* Now, the new page is allocated, the last dma + * will not be used. So the dma can be unmapped + * if the ref is 0. + */ + virtnet_rq_unmap(rq, rq->last_dma, 0); + rq->last_dma = NULL; + } - addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1, - dma->len, DMA_FROM_DEVICE, 0); - if (virtqueue_dma_mapping_error(rq->vq, addr)) - return NULL; + dma->len = alloc_frag->size - sizeof(*dma); - dma->addr = addr; - dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr); + addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1, + dma->len, DMA_FROM_DEVICE, 0); + if (virtqueue_dma_mapping_error(rq->vq, addr)) + return NULL; - /* Add a reference to dma to prevent the entire dma from - * being released during error handling. This reference - * will be freed after the pages are no longer used. - */ - get_page(alloc_frag->page); - dma->ref = 1; - alloc_frag->offset = sizeof(*dma); + dma->addr = addr; + dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr); - rq->last_dma = dma; - } + /* Add a reference to dma to prevent the entire dma from + * being released during error handling. This reference + * will be freed after the pages are no longer used. + */ + get_page(alloc_frag->page); + dma->ref = 1; + alloc_frag->offset = sizeof(*dma); - ++dma->ref; + rq->last_dma = dma; } + ++dma->ref; + buf = head + alloc_frag->offset; get_page(alloc_frag->page); @@ -2433,8 +2435,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp); if (err < 0) { - if (rq->do_dma) - virtnet_rq_unmap(rq, buf, 0); + virtnet_rq_unmap(rq, buf, 0); put_page(virt_to_head_page(buf)); } @@ -2554,8 +2555,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, ctx = mergeable_len_to_ctx(len + room, headroom); err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp); if (err < 0) { - if (rq->do_dma) - virtnet_rq_unmap(rq, buf, 0); + virtnet_rq_unmap(rq, buf, 0); put_page(virt_to_head_page(buf)); } @@ -5922,7 +5922,7 @@ static void free_receive_page_frags(struct virtnet_info *vi) int i; for (i = 0; i < vi->max_queue_pairs; i++) if (vi->rq[i].alloc_frag.page) { - if (vi->rq[i].do_dma && vi->rq[i].last_dma) + if (vi->rq[i].last_dma) virtnet_rq_unmap(&vi->rq[i], vi->rq[i].last_dma, 0); put_page(vi->rq[i].alloc_frag.page); } @@ -6111,11 +6111,9 @@ static void virtnet_rq_set_premapped(struct virtnet_info *vi) { int i; - for (i = 0; i < vi->max_queue_pairs; i++) { + for (i = 0; i < vi->max_queue_pairs; i++) /* error should never happen */ BUG_ON(virtqueue_set_dma_premapped(vi->rq[i].vq)); - vi->rq[i].do_dma = true; - } } static int init_vqs(struct virtnet_info *vi) -- 2.51.0 From 9bdb67b53f3f2c702ef8bf4723c3d2c5523aba9b Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Fri, 1 Nov 2024 08:09:07 +0100 Subject: [PATCH 14/16] net: sparx5: expose some sparx5 VCAP symbols MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In preparation for lan969x VCAP support, expose the following symbols for use by the lan969x VCAP implementation: - The symbols SPARX5_*_LOOKUPS defines the number of lookups in each VCAP instance. These are the same for lan969x. Move them to the header file. - The struct sparx5_vcap_inst encapsulates information about a single VCAP instance. Move this struct to the header file and declare the sparx5_vcap_inst_cfg as extern. Reviewed-by: Steen Hegelund Reviewed-by: Jens Emil Schulz Østergaard Signed-off-by: Daniel Machon Signed-off-by: Paolo Abeni --- .../microchip/sparx5/sparx5_vcap_impl.c | 18 +--------------- .../microchip/sparx5/sparx5_vcap_impl.h | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index 967c8621c250..0bdf7a378892 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -17,7 +17,6 @@ #define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */ #define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ -#define SPARX5_IS2_LOOKUPS 4 #define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \ (ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \ ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \ @@ -27,7 +26,6 @@ ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \ ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp)) -#define SPARX5_IS0_LOOKUPS 6 #define VCAP_IS0_KEYSEL(_ena, _etype, _ipv4, _ipv6, _mpls_uc, _mpls_mc, _mlbs) \ (ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(_ena) | \ ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(_etype) | \ @@ -37,31 +35,17 @@ ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_SET(_mpls_mc) | \ ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_SET(_mlbs)) -#define SPARX5_ES0_LOOKUPS 1 #define VCAP_ES0_KEYSEL(_key) (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(_key)) #define SPARX5_STAT_ESDX_GRN_PKTS 0x300 #define SPARX5_STAT_ESDX_YEL_PKTS 0x301 -#define SPARX5_ES2_LOOKUPS 2 #define VCAP_ES2_KEYSEL(_ena, _arp, _ipv4, _ipv6) \ (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(_ena) | \ EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(_arp) | \ EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(_ipv4) | \ EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(_ipv6)) -static struct sparx5_vcap_inst { - enum vcap_type vtype; /* type of vcap */ - int vinst; /* instance number within the same type */ - int lookups; /* number of lookups in this vcap type */ - int lookups_per_instance; /* number of lookups in this instance */ - int first_cid; /* first chain id in this vcap */ - int last_cid; /* last chain id in this vcap */ - int count; /* number of available addresses, not in super vcap */ - int map_id; /* id in the super vcap block mapping (if applicable) */ - int blockno; /* starting block in super vcap (if applicable) */ - int blocks; /* number of blocks in super vcap (if applicable) */ - bool ingress; /* is vcap in the ingress path */ -} sparx5_vcap_inst_cfg[] = { +const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[] = { { .vtype = VCAP_TYPE_IS0, /* CLM-0 */ .vinst = 0, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h index 2684d9199b05..d0a42406bf26 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h @@ -16,6 +16,11 @@ #include "vcap_api.h" #include "vcap_api_client.h" +#define SPARX5_IS2_LOOKUPS 4 +#define SPARX5_IS0_LOOKUPS 6 +#define SPARX5_ES0_LOOKUPS 1 +#define SPARX5_ES2_LOOKUPS 2 + #define SPARX5_VCAP_CID_IS0_L0 VCAP_CID_INGRESS_L0 /* IS0/CLM lookup 0 */ #define SPARX5_VCAP_CID_IS0_L1 VCAP_CID_INGRESS_L1 /* IS0/CLM lookup 1 */ #define SPARX5_VCAP_CID_IS0_L2 VCAP_CID_INGRESS_L2 /* IS0/CLM lookup 2 */ @@ -40,6 +45,22 @@ #define SPARX5_VCAP_CID_ES2_MAX \ (VCAP_CID_EGRESS_STAGE2_L1 + VCAP_CID_LOOKUP_SIZE - 1) /* ES2 Max */ +struct sparx5_vcap_inst { + enum vcap_type vtype; /* type of vcap */ + int vinst; /* instance number within the same type */ + int lookups; /* number of lookups in this vcap type */ + int lookups_per_instance; /* number of lookups in this instance */ + int first_cid; /* first chain id in this vcap */ + int last_cid; /* last chain id in this vcap */ + int count; /* number of available addresses, not in super vcap */ + int map_id; /* id in the super vcap block mapping (if applicable) */ + int blockno; /* starting block in super vcap (if applicable) */ + int blocks; /* number of blocks in super vcap (if applicable) */ + bool ingress; /* is vcap in the ingress path */ +}; + +extern const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[]; + /* IS0 port keyset selection control */ /* IS0 ethernet, IPv4, IPv6 traffic type keyset generation */ -- 2.51.0 From 8f5a812efff8495ba0df93239b62d008925b37d1 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Fri, 1 Nov 2024 08:09:08 +0100 Subject: [PATCH 15/16] net: sparx5: replace SPX5_PORTS with n_ports MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The Sparx5 VCAP implementation uses the SPX5_PORTS symbol to iterate over the 65 front ports of Sparx5. Replace the use with the n_ports constant from the match data, which translates to 65 of Sparx5 and 30 on lan969x. Reviewed-by: Steen Hegelund Reviewed-by: Jens Emil Schulz Østergaard Signed-off-by: Daniel Machon Signed-off-by: Paolo Abeni --- .../microchip/sparx5/sparx5_vcap_impl.c | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index 0bdf7a378892..bbff8158a3de 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -1777,6 +1777,7 @@ void sparx5_vcap_set_port_keyset(struct net_device *ndev, static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1788,7 +1789,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, VCAP_IS0_PS_MPLS_FOLLOW_ETYPE, VCAP_IS0_PS_MLBS_FOLLOW_ETYPE); for (lookup = 0; lookup < admin->lookups; ++lookup) { - for (portno = 0; portno < SPX5_PORTS; ++portno) { + for (portno = 0; portno < consts->n_ports; ++portno) { spx5_wr(keysel, sparx5, ANA_CL_ADV_CL_CFG(portno, lookup)); spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA, @@ -1803,6 +1804,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1813,13 +1815,13 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, VCAP_IS2_PS_ARP_ARP); for (lookup = 0; lookup < admin->lookups; ++lookup) { - for (portno = 0; portno < SPX5_PORTS; ++portno) { + for (portno = 0; portno < consts->n_ports; ++portno) { spx5_wr(keysel, sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); } } /* IS2 lookups are in bit 0:3 */ - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), ANA_ACL_VCAP_S2_CFG_SEC_ENA, sparx5, @@ -1830,11 +1832,12 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno; u32 keysel; keysel = VCAP_ES0_KEYSEL(VCAP_ES0_PS_FORCE_ISDX_LOOKUPS); - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(keysel, REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA, sparx5, REW_RTAG_ETAG_CTRL(portno)); @@ -1846,6 +1849,7 @@ static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1853,7 +1857,7 @@ static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5, VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER, VCAP_ES2_PS_IPV6_IP_7TUPLE); for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_wr(keysel, sparx5, EACL_VCAP_ES2_KEY_SEL(portno, lookup)); } @@ -1885,19 +1889,20 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; switch (admin->vtype) { case VCAP_TYPE_IS0: for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(0), ANA_CL_ADV_CL_CFG_LOOKUP_ENA, sparx5, ANA_CL_ADV_CL_CFG(portno, lookup)); break; case VCAP_TYPE_IS2: - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), ANA_ACL_VCAP_S2_CFG_SEC_ENA, sparx5, @@ -1909,7 +1914,7 @@ static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, break; case VCAP_TYPE_ES2: for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(0), EACL_VCAP_ES2_KEY_SEL_KEY_ENA, sparx5, @@ -2026,6 +2031,7 @@ static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, /* Allocate a vcap control and vcap instances and configure the system */ int sparx5_vcap_init(struct sparx5 *sparx5) { + const struct sparx5_consts *consts = sparx5->data->consts; const struct sparx5_vcap_inst *cfg; struct vcap_control *ctrl; struct vcap_admin *admin; @@ -2069,7 +2075,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5) list_add_tail(&admin->list, &ctrl->list); } dir = vcap_debugfs(sparx5->dev, sparx5->debugfs_root, ctrl); - for (idx = 0; idx < SPX5_PORTS; ++idx) + for (idx = 0; idx < consts->n_ports; ++idx) if (sparx5->ports[idx]) vcap_port_debugfs(sparx5->dev, dir, ctrl, sparx5->ports[idx]->ndev); -- 2.51.0 From 8caa21e4e4ed4ed8bebb95f47e724bf78883679a Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Fri, 1 Nov 2024 08:09:09 +0100 Subject: [PATCH 16/16] net: sparx5: add new VCAP constants to match data MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In preparation for lan969x VCAP support, add the following three new VCAP constants to match data: - vcaps_cfg (contains configuration data for each VCAP). - vcaps (contains auto-generated information about VCAP keys and actions). - vcap_stats: (contains auto-generated string names of all the keys and actions) Add these constants to the Sparx5 match data constants and use them to initialize the VCAP's in sparx5_vcap_init(). Reviewed-by: Steen Hegelund Reviewed-by: Jens Emil Schulz Østergaard Signed-off-by: Daniel Machon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microchip/sparx5/sparx5_main.c | 5 +++++ drivers/net/ethernet/microchip/sparx5/sparx5_main.h | 3 +++ drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h | 2 ++ drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c | 6 +++--- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index 4f2d5413a64f..bac87e885bf1 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -30,6 +30,8 @@ #include "sparx5_main.h" #include "sparx5_port.h" #include "sparx5_qos.h" +#include "sparx5_vcap_ag_api.h" +#include "sparx5_vcap_impl.h" const struct sparx5_regs *regs; @@ -1063,6 +1065,9 @@ static const struct sparx5_consts sparx5_consts = { .qres_max_prio_idx = 630, .qres_max_colour_idx = 638, .tod_pin = 4, + .vcaps = sparx5_vcaps, + .vcaps_cfg = sparx5_vcap_inst_cfg, + .vcap_stats = &sparx5_vcap_stats, }; static const struct sparx5_ops sparx5_ops = { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index 146bdc938adc..d5dd953b0a71 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -303,6 +303,9 @@ struct sparx5_consts { u32 qres_max_prio_idx; /* Maximum QRES prio index */ u32 qres_max_colour_idx; /* Maximum QRES colour index */ u32 tod_pin; /* PTP TOD pin */ + const struct sparx5_vcap_inst *vcaps_cfg; + const struct vcap_info *vcaps; + const struct vcap_statistics *vcap_stats; }; struct sparx5_ops { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h index 7d106f1276fe..e68f5639a40a 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h @@ -10,6 +10,8 @@ #ifndef __SPARX5_VCAP_AG_API_H__ #define __SPARX5_VCAP_AG_API_H__ +#include "vcap_api.h" + /* VCAPs */ extern const struct vcap_info sparx5_vcaps[]; extern const struct vcap_statistics sparx5_vcap_stats; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index bbff8158a3de..25066ddb8d4d 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -2053,14 +2053,14 @@ int sparx5_vcap_init(struct sparx5 *sparx5) sparx5->vcap_ctrl = ctrl; /* select the sparx5 VCAP model */ - ctrl->vcaps = sparx5_vcaps; - ctrl->stats = &sparx5_vcap_stats; + ctrl->vcaps = consts->vcaps; + ctrl->stats = consts->vcap_stats; /* Setup callbacks to allow the API to use the VCAP HW */ ctrl->ops = &sparx5_vcap_ops; INIT_LIST_HEAD(&ctrl->list); for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { - cfg = &sparx5_vcap_inst_cfg[idx]; + cfg = &consts->vcaps_cfg[idx]; admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); if (IS_ERR(admin)) { err = PTR_ERR(admin); -- 2.51.0