From: Michael Chan <michael.chan@broadcom.com>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, andrew+netdev@lunn.ch,
pavan.chebbi@broadcom.com, andrew.gospodarek@broadcom.com
Subject: [PATCH net-next v5 09/15] bnxt_en: Add infrastructure for crypto key context IDs
Date: Thu, 9 Jul 2026 21:23:54 -0700 [thread overview]
Message-ID: <20260710042400.3996847-10-michael.chan@broadcom.com> (raw)
In-Reply-To: <20260710042400.3996847-1-michael.chan@broadcom.com>
Each kTLS connection requires a crypto key context ID (KID). These KIDs
are allocated from the firmware in batches. Add data structure to store
these IDs. The bnxt_kid_info structure stores a batch of IDs and it can be
linked as we allocate more batches. There is a bitmap in the structure
to keep track of which ones are in use. Add APIs to allocate and free
these KIDs.
Once allocated, these KIDs are not freed during run-time. They are
re-used for new connections. FW reset or HWRM_FUNC_RESET will free
all KIDs. Call bnxt_clear_crypto() to clear all KIDs in the driver's
structures during these reset events.
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
v5:
More clearly document and explain that bnxt_clear_crypto() has no
concurrent readers/writers.
Add comment to explain that the bnxt_free_one_ctx() caller is reponsible
to check the epoch value when needed.
v4:
https://lore.kernel.org/netdev/20260629184921.3496727-10-michael.chan@broadcom.com/
Fix kernel doc for bnxt_free_one_kctx().
Add BNXT_NEXT_EPOCH() to mask the epoch value.
v3:
https://lore.kernel.org/netdev/20260614072407.2761092-10-michael.chan@broadcom.com/
Use a larger (12-bit) epoch value for the keys.
Improve comments, kerneldoc, and dmesg.
Make sure bnxt_clear_crypto() is called during shutdown with the
BNXT_STATE_OPEN flag cleared.
v2:
https://lore.kernel.org/netdev/20260512212105.3488258-10-michael.chan@broadcom.com/
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 +
.../net/ethernet/broadcom/bnxt/bnxt_crypto.c | 285 ++++++++++++++++++
.../net/ethernet/broadcom/bnxt/bnxt_crypto.h | 70 +++++
3 files changed, 365 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 27f9843f9c5d..4f7042d91078 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -12899,6 +12899,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
bnxt_ulp_irq_stop(bp);
bnxt_free_ctx_mem(bp, false);
bnxt_dcb_free(bp);
+ if (fw_reset || caps_change)
+ bnxt_clear_crypto(bp);
rc = bnxt_fw_init_one(bp);
if (rc) {
clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state);
@@ -14636,6 +14638,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp)
bnxt_hwrm_func_drv_unrgtr(bp);
if (pci_is_enabled(bp->pdev))
pci_disable_device(bp->pdev);
+ bnxt_clear_crypto(bp);
bnxt_free_ctx_mem(bp, false);
}
@@ -17292,6 +17295,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = bnxt_dl_register(bp);
if (rc)
goto init_err_dl;
+ rc = bnxt_crypto_init(bp);
+ if (rc) {
+ bnxt_free_crypto_info(bp);
+ netdev_warn(bp->dev, "Failed to initialize crypto offload, err = %d\n",
+ rc);
+ }
INIT_LIST_HEAD(&bp->usr_fltr_list);
@@ -17518,6 +17527,7 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
if (pci_is_enabled(pdev))
pci_disable_device(pdev);
+ bnxt_clear_crypto(bp);
bnxt_free_ctx_mem(bp, false);
netdev_unlock(netdev);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.c
index b2a96ac725ea..72927c32bf0c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.c
@@ -8,6 +8,7 @@
#include <linux/bnxt/hsi.h>
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_crypto.h"
static u32 bnxt_get_max_crypto_key_ctx(struct bnxt *bp, int key_type)
@@ -55,6 +56,10 @@ void bnxt_alloc_crypto_info(struct bnxt *bp,
for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
kctx = &crypto->kctx[i];
kctx->type = i;
+ INIT_LIST_HEAD(&kctx->list);
+ spin_lock_init(&kctx->lock);
+ atomic_set(&kctx->alloc_pending, 0);
+ init_waitqueue_head(&kctx->alloc_pending_wq);
}
bp->crypto_info = crypto;
}
@@ -66,6 +71,43 @@ void bnxt_alloc_crypto_info(struct bnxt *bp,
bp->fw_cap |= BNXT_FW_CAP_KTLS;
}
+/**
+ * bnxt_clear_crypto - Clear all crypto key contexts
+ * @bp: pointer to bnxt device
+ *
+ * Clears all key context allocations during shutdown or firmware reset.
+ * Frees all key info structures and bitmaps, and increments the epoch
+ * counter to invalidate any outstanding key references.
+ *
+ * Locking: the caller must have cleared BNXT_STATE_OPEN and waited for all
+ * in-flight kTLS control ops to drain. Under these preconditions there are
+ * no concurrent readers or writers of the KID lists, so the lists can be
+ * walked without rcu_read_lock() or the kctx lock.
+ *
+ * Context: Process context during shutdown/reset
+ */
+void bnxt_clear_crypto(struct bnxt *bp)
+{
+ struct bnxt_crypto_info *crypto = bp->crypto_info;
+ struct bnxt_kid_info *kid, *tmp;
+ struct bnxt_kctx *kctx;
+ int i;
+
+ if (!crypto)
+ return;
+
+ /* No concurrent access; see the locking note above. */
+ for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
+ kctx = &crypto->kctx[i];
+ list_for_each_entry_safe(kid, tmp, &kctx->list, list) {
+ list_del(&kid->list);
+ kfree(kid);
+ }
+ kctx->total_alloc = 0;
+ kctx->epoch = BNXT_NEXT_EPOCH(kctx->epoch);
+ }
+}
+
/**
* bnxt_free_crypto_info - Free crypto offload resources
* @bp: pointer to bnxt device
@@ -77,6 +119,7 @@ void bnxt_alloc_crypto_info(struct bnxt *bp,
*/
void bnxt_free_crypto_info(struct bnxt *bp)
{
+ bnxt_clear_crypto(bp);
kfree(bp->crypto_info);
bp->crypto_info = NULL;
bp->fw_cap &= ~BNXT_FW_CAP_KTLS;
@@ -113,3 +156,245 @@ void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt *bp,
if (rx)
req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_KTLS_RX_KEY_CTXS);
}
+
+static int bnxt_key_ctx_store(struct bnxt_kctx *kctx, __le32 *key_buf, u32 num,
+ bool contig, u8 kind, u32 *id)
+{
+ struct bnxt_kid_info *kid;
+ u32 i;
+
+ for (i = 0; i < num; ) {
+ kid = kzalloc_obj(*kid);
+ /* If we cannot store the IDs, they will be lost and only
+ * reclaimed by the FW during reset/reinit.
+ */
+ if (!kid)
+ return -ENOMEM;
+ kid->start_id = le32_to_cpu(key_buf[i]);
+ kid->type = kctx->type;
+ kid->kind = kind;
+ if (contig)
+ kid->count = num;
+ else
+ kid->count = 1;
+ bitmap_set(kid->ids, 0, kid->count);
+ if (id && !i) {
+ clear_bit(0, kid->ids);
+ *id = BNXT_SET_KID(kctx, kid->start_id);
+ }
+ spin_lock(&kctx->lock);
+ list_add_tail_rcu(&kid->list, &kctx->list);
+ WRITE_ONCE(kctx->total_alloc,
+ READ_ONCE(kctx->total_alloc) + kid->count);
+ spin_unlock(&kctx->lock);
+ i += kid->count;
+ }
+ return 0;
+}
+
+/* Note that the driver does not free the key contexts. They are freed
+ * by the FW during FLR and HWRM_FUNC_RESET.
+ */
+static int bnxt_hwrm_key_ctx_alloc(struct bnxt *bp, struct bnxt_kctx *kctx,
+ u8 kind, u32 num, u32 *id)
+{
+ struct bnxt_crypto_info *crypto = bp->crypto_info;
+ struct hwrm_func_key_ctx_alloc_output *resp;
+ struct hwrm_func_key_ctx_alloc_input *req;
+ dma_addr_t mapping;
+ int pending_count;
+ __le32 *key_buf;
+ u32 num_alloc;
+ bool contig;
+ int rc;
+
+ num = min3(num, crypto->max_key_ctxs_alloc, (u32)BNXT_KID_BATCH_SIZE);
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_KEY_CTX_ALLOC);
+ if (rc)
+ return rc;
+
+ key_buf = hwrm_req_dma_slice(bp, req, num * 4, &mapping);
+ if (!key_buf) {
+ rc = -ENOMEM;
+ goto key_alloc_exit;
+ }
+ req->dma_bufr_size_bytes = cpu_to_le32(num * 4);
+ req->host_dma_addr = cpu_to_le64(mapping);
+ resp = hwrm_req_hold(bp, req);
+
+ req->key_ctx_type = kctx->type;
+ req->num_key_ctxs = cpu_to_le16(num);
+
+ pending_count = atomic_inc_return(&kctx->alloc_pending);
+ rc = hwrm_req_send(bp, req);
+ atomic_dec(&kctx->alloc_pending);
+ if (rc)
+ goto key_alloc_exit_wake;
+
+ num_alloc = le16_to_cpu(resp->num_key_ctxs_allocated);
+ if (num_alloc > num) {
+ netdev_warn(bp->dev,
+ "FW allocated more type %d keys (%d) than requested (%d)\n",
+ kctx->type, num_alloc, num);
+ } else if (!num_alloc) {
+ netdev_warn(bp->dev,
+ "FW allocated 0 type %d keys\n", kctx->type);
+ rc = -ENOENT;
+ goto key_alloc_exit_wake;
+ } else {
+ num = num_alloc;
+ }
+ contig = resp->flags &
+ FUNC_KEY_CTX_ALLOC_RESP_FLAGS_KEY_CTXS_CONTIGUOUS;
+ rc = bnxt_key_ctx_store(kctx, key_buf, num, contig, kind, id);
+
+key_alloc_exit_wake:
+ if (pending_count >= BNXT_KCTX_ALLOC_PENDING_MAX)
+ wake_up_all(&kctx->alloc_pending_wq);
+key_alloc_exit:
+ hwrm_req_drop(bp, req);
+ return rc;
+}
+
+bool bnxt_kid_valid(struct bnxt_kctx *kctx, u32 id)
+{
+ struct bnxt_kid_info *kid;
+ bool valid = false;
+ u32 epoch;
+
+ epoch = BNXT_KID_EPOCH(id);
+ if (epoch != kctx->epoch)
+ return false;
+
+ id = BNXT_KID_HW(id);
+ rcu_read_lock();
+ list_for_each_entry_rcu(kid, &kctx->list, list) {
+ if (id >= kid->start_id && id < kid->start_id + kid->count) {
+ if (!test_bit(id - kid->start_id, kid->ids)) {
+ valid = true;
+ break;
+ }
+ }
+ }
+ rcu_read_unlock();
+ return valid;
+}
+
+static int bnxt_alloc_one_kctx(struct bnxt_kctx *kctx, u8 kind, u32 *id)
+{
+ struct bnxt_kid_info *kid;
+ int rc = -ENOMEM;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(kid, &kctx->list, list) {
+ u32 idx = 0;
+
+ if (kid->kind != kind)
+ continue;
+ do {
+ idx = find_next_bit(kid->ids, kid->count, idx);
+ if (idx >= kid->count)
+ break;
+ if (test_and_clear_bit(idx, kid->ids)) {
+ *id = BNXT_SET_KID(kctx, kid->start_id + idx);
+ rc = 0;
+ goto alloc_done;
+ }
+ } while (1);
+ }
+
+alloc_done:
+ rcu_read_unlock();
+ return rc;
+}
+
+/**
+ * bnxt_free_one_kctx - Free a key context for later re-use
+ * @kctx: pointer to bnxt_kctx key context structure
+ * @id: Key context ID
+ *
+ * This function is called to free a key context ID when the offload
+ * using the ID has successfully terminated or aborted. If the offload
+ * cannot be terminated, the caller should not call this function to free
+ * the ID. The ID will only be recycled by the FW during reset/reinit.
+ *
+ * The ID is matched by its hardware id only (epoch stripped), so the caller
+ * must ensure it is valid for the current epoch.
+ */
+void bnxt_free_one_kctx(struct bnxt_kctx *kctx, u32 id)
+{
+ struct bnxt_kid_info *kid;
+
+ id = BNXT_KID_HW(id);
+ rcu_read_lock();
+ list_for_each_entry_rcu(kid, &kctx->list, list) {
+ if (id >= kid->start_id && id < kid->start_id + kid->count) {
+ set_bit(id - kid->start_id, kid->ids);
+ break;
+ }
+ }
+ rcu_read_unlock();
+}
+
+#define BNXT_KCTX_ALLOC_RETRY_MAX 3
+
+int bnxt_key_ctx_alloc_one(struct bnxt *bp, struct bnxt_kctx *kctx, u8 kind,
+ u32 *id)
+{
+ int rc, retry = 0;
+
+ while (retry++ < BNXT_KCTX_ALLOC_RETRY_MAX) {
+ rc = bnxt_alloc_one_kctx(kctx, kind, id);
+ if (!rc)
+ return 0;
+
+ /* When approaching the max, multiple threads may proceed
+ * and exceed the max. Some may fail the serialized HWRM call
+ * later when the max is exceeded.
+ */
+ if ((READ_ONCE(kctx->total_alloc) + BNXT_KID_BATCH_SIZE) >
+ kctx->max_ctx)
+ return -ENOSPC;
+
+ if (!BNXT_KCTX_ALLOC_OK(kctx)) {
+ wait_event(kctx->alloc_pending_wq,
+ BNXT_KCTX_ALLOC_OK(kctx));
+ continue;
+ }
+ rc = bnxt_hwrm_key_ctx_alloc(bp, kctx, kind,
+ BNXT_KID_BATCH_SIZE, id);
+ if (!rc)
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+int bnxt_crypto_init(struct bnxt *bp)
+{
+ struct bnxt_crypto_info *crypto = bp->crypto_info;
+ struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+ struct bnxt_hw_crypto_resc *crypto_resc;
+ int rc;
+
+ if (!crypto || !BNXT_SUPPORTS_KTLS(bp))
+ return 0;
+
+ crypto_resc = &hw_resc->crypto_resc;
+ BNXT_TCK(crypto).max_ctx = crypto_resc->resv_tx_key_ctxs;
+ BNXT_RCK(crypto).max_ctx = crypto_resc->resv_rx_key_ctxs;
+
+ if (!BNXT_TCK(crypto).max_ctx || !BNXT_RCK(crypto).max_ctx)
+ return -ENODEV;
+
+ rc = bnxt_hwrm_key_ctx_alloc(bp, &BNXT_TCK(crypto), BNXT_CTX_KIND_CK_TX,
+ BNXT_KID_BATCH_SIZE, NULL);
+ if (rc)
+ return rc;
+
+ rc = bnxt_hwrm_key_ctx_alloc(bp, &BNXT_RCK(crypto), BNXT_CTX_KIND_CK_RX,
+ BNXT_KID_BATCH_SIZE, NULL);
+ if (rc)
+ return rc;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.h
index e090491006db..f88aa410efdd 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_crypto.h
@@ -16,11 +16,47 @@ enum bnxt_crypto_type {
BNXT_MAX_CRYPTO_KEY_TYPE,
};
+/* Maximum keys supported by newer FW always multiples of 128 */
+#define BNXT_KID_BATCH_SIZE 128
+
+struct bnxt_kid_info {
+ struct list_head list;
+ u8 type;
+ u8 kind;
+ u32 start_id;
+ u32 count;
+ DECLARE_BITMAP(ids, BNXT_KID_BATCH_SIZE);
+};
+
struct bnxt_kctx {
+ struct list_head list;
+ /* to serialize update to the linked list and total_alloc */
+ spinlock_t lock;
u8 type;
+ u16 epoch;
+ u32 total_alloc;
u32 max_ctx;
+ atomic_t alloc_pending;
+#define BNXT_KCTX_ALLOC_PENDING_MAX 8
+ wait_queue_head_t alloc_pending_wq;
};
+#define BNXT_KID_HW_MASK 0x000fffff
+#define BNXT_KID_HW(kid) ((kid) & BNXT_KID_HW_MASK)
+#define BNXT_KID_EPOCH_MASK 0xfff00000
+#define BNXT_KID_EPOCH_SHIFT 20
+#define BNXT_KID_EPOCH(kid) (((kid) & BNXT_KID_EPOCH_MASK) >> \
+ BNXT_KID_EPOCH_SHIFT)
+
+#define BNXT_NEXT_EPOCH(epoch) \
+ (((epoch) + 1) & (BNXT_KID_EPOCH_MASK >> BNXT_KID_EPOCH_SHIFT))
+
+#define BNXT_SET_KID(kctx, kid) \
+ ((kid) | ((u32)(kctx)->epoch << BNXT_KID_EPOCH_SHIFT))
+
+#define BNXT_KCTX_ALLOC_OK(kctx) \
+ (atomic_read(&((kctx)->alloc_pending)) < BNXT_KCTX_ALLOC_PENDING_MAX)
+
struct bnxt_crypto_info {
u16 max_key_ctxs_alloc;
@@ -30,18 +66,31 @@ struct bnxt_crypto_info {
#define BNXT_TCK(crypto) ((crypto)->kctx[BNXT_TX_CRYPTO_KEY_TYPE])
#define BNXT_RCK(crypto) ((crypto)->kctx[BNXT_RX_CRYPTO_KEY_TYPE])
+#define BNXT_CTX_KIND_CK_TX 0x11
+#define BNXT_CTX_KIND_CK_RX 0x12
+
#ifdef CONFIG_BNXT_TLS
void bnxt_alloc_crypto_info(struct bnxt *bp,
struct hwrm_func_qcaps_output *resp);
+void bnxt_clear_crypto(struct bnxt *bp);
void bnxt_free_crypto_info(struct bnxt *bp);
void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt *bp,
struct hwrm_func_cfg_input *req);
+bool bnxt_kid_valid(struct bnxt_kctx *kctx, u32 id);
+void bnxt_free_one_kctx(struct bnxt_kctx *kctx, u32 id);
+int bnxt_key_ctx_alloc_one(struct bnxt *bp, struct bnxt_kctx *kctx, u8 kind,
+ u32 *id);
+int bnxt_crypto_init(struct bnxt *bp);
#else
static inline void bnxt_alloc_crypto_info(struct bnxt *bp,
struct hwrm_func_qcaps_output *resp)
{
}
+static inline void bnxt_clear_crypto(struct bnxt *bp)
+{
+}
+
static inline void bnxt_free_crypto_info(struct bnxt *bp)
{
}
@@ -50,5 +99,26 @@ static inline void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt *bp,
struct hwrm_func_cfg_input *req)
{
}
+
+static inline bool bnxt_kid_valid(struct bnxt_kctx *kctx, u32 id)
+{
+ return false;
+}
+
+static inline void bnxt_free_one_kctx(struct bnxt_kctx *kctx, u32 id)
+{
+}
+
+static inline int bnxt_key_ctx_alloc_one(struct bnxt *bp,
+ struct bnxt_kctx *kctx, u8 kind,
+ u32 *id)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int bnxt_crypto_init(struct bnxt *bp)
+{
+ return 0;
+}
#endif /* CONFIG_BNXT_TLS */
#endif /* BNXT_CRYPTO_H */
--
2.51.0
next prev parent reply other threads:[~2026-07-10 4:25 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 4:23 [PATCH net-next v5 00/15] bnxt_en: Add kTLS TX offload support Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 01/15] bnxt_en: Add Midpath channel information Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 02/15] bnxt_en: Account for the MPC TX and CP rings Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 03/15] bnxt_en: Set default MPC ring count Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 04/15] bnxt_en: Rename xdp_tx_lock to tx_lock Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 05/15] bnxt_en: Allocate and free MPC software structures Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 06/15] bnxt_en: Allocate and free MPC channels from firmware Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 07/15] bnxt_en: Allocate crypto structure and backing store Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 08/15] bnxt_en: Reserve crypto RX and TX key contexts on a PF Michael Chan
2026-07-10 4:23 ` Michael Chan [this message]
2026-07-10 4:23 ` [PATCH net-next v5 10/15] bnxt_en: Add MPC transmit and completion functions Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 11/15] bnxt_en: Add crypto MPC transmit/completion infrastructure Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 12/15] bnxt_en: Support kTLS TX offload by implementing .tls_dev_add/del() Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 13/15] bnxt_en: Implement kTLS TX normal path Michael Chan
2026-07-10 4:23 ` [PATCH net-next v5 14/15] bnxt_en: Add support for inline transmit BDs Michael Chan
2026-07-10 4:24 ` [PATCH net-next v5 15/15] bnxt_en: Add kTLS retransmission support Michael Chan
2026-07-23 13:52 ` [PATCH net-next v5 00/15] bnxt_en: Add kTLS TX offload support Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260710042400.3996847-10-michael.chan@broadcom.com \
--to=michael.chan@broadcom.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrew.gospodarek@broadcom.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pavan.chebbi@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.