From: Mike Marciniszyn <mike.marciniszyn@gmail.com>
To: Alexander Duyck <alexanderduyck@fb.com>,
Jakub Kicinski <kuba@kernel.org>,
kernel-team@meta.com, Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Russell King <linux@armlinux.org.uk>,
Jacob Keller <jacob.e.keller@intel.com>,
Lee Trager <lee@trager.us>,
Mohsin Bashir <mohsin.bashr@gmail.com>,
Dan Carpenter <dan.carpenter@linaro.org>,
Pei Xiao <xiaopei01@kylinos.cn>,
Stanislav Fomichev <sdf@fomichev.me>,
Willem de Bruijn <willemb@google.com>,
Samiullah Khawaja <skhawaja@google.com>,
Hangbin Liu <liuhangbin@gmail.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v3 3/5] eth fbnic: Add msix self test
Date: Fri, 6 Mar 2026 14:27:32 -0500 [thread overview]
Message-ID: <aasqpPj2rOIKgnSY@PF5YBGDS.localdomain> (raw)
In-Reply-To: <20260305150947.16893-4-mike.marciniszyn@gmail.com>
On Thu, Mar 05, 2026 at 10:09:45AM -0500, mike.marciniszyn@gmail.com wrote:
> From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
>
> This function is meant to test the global interrupt registers and the
> PCIe IP MSI-X functionality. It essentially goes through and tests
> various combinations of the set, clear, and mask bits in order to
> verify the behavior is as we expect it to be from the driver.
>
> Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
> ---
> v2 - add enum for test return codes
> v3 - add missing enum
>
> drivers/net/ethernet/meta/fbnic/fbnic.h | 18 ++
> .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 28 ++++
> drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 154 ++++++++++++++++++
> 3 files changed, 214 insertions(+)
>
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
> index 779a083b9215..534caa3c872d 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic.h
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
> @@ -194,6 +194,38 @@ void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr);
> int fbnic_request_irq(struct fbnic_dev *dev, int nr, irq_handler_t handler,
> unsigned long flags, const char *name, void *data);
> void fbnic_free_irq(struct fbnic_dev *dev, int nr, void *data);
> +
> +/**
> + * enum fbnic_msix_self_test_codes - return codes from self test routines
> + *
> + * These are the codes returned from the self test routines and
> + * stored in the test result array indexed by the specific
> + * test name.
> + *
> + * @FBNIC_TEST_MSIX_SUCCESS: no errors
> + * @FBNIC_TEST_MSIX_NOMEM: allocation failure
> + * @FBNIC_TEST_MSIX_IRQ_REQ_FAIL: IRQ request failure
> + * @FBNIC_TEST_MSIX_MASK: masking failed to prevent IRQ
> + * @FBNIC_TEST_MSIX_UNMASK: unmasking failure w/ sw status set
> + * @FBNIC_TEST_MSIX_IRQ_CLEAR: interrupt when clearing mask
> + * @FBNIC_TEST_MSIX_NO_INTERRUPT: no interrupt when not masked
> + * @FBNIC_TEST_MSIX_NO_CLEAR_OR_MASK: status not cleared, or mask not set
> + * @FBNIC_TEST_MSIX_BITS_SET_AFTER_TEST: Bits are set after test
> + */
> +enum fbnic_msix_self_test_codes {
> + FBNIC_TEST_MSIX_SUCCESS = 0,
> + FBNIC_TEST_MSIX_NOMEM = 5,
> + FBNIC_TEST_MSIX_IRQ_REQ_FAIL = 10,
> + FBNIC_TEST_MSIX_MASK = 20,
> + FBNIC_TEST_MSIX_UNMASK = 30,
> + FBNIC_TEST_MSIX_IRQ_CLEAR = 40,
> + FBNIC_TEST_MSIX_NO_INTERRUPT = 50,
> + FBNIC_TEST_MSIX_NO_CLEAR_OR_MASK = 60,
> + FBNIC_TEST_MSIX_BITS_SET_AFTER_TEST = 70,
> +};
> +
> +enum fbnic_msix_self_test_codes fbnic_msix_test(struct fbnic_dev *fbd);
> +
> void fbnic_free_irqs(struct fbnic_dev *fbd);
> int fbnic_alloc_irqs(struct fbnic_dev *fbd);
>
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> index 2e882dbd408d..b0c8d1b069e2 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> @@ -128,10 +128,12 @@ static const struct fbnic_stat fbnic_gstrings_xdp_stats[] = {
>
> enum fbnic_self_test_results {
> TEST_REG = 0,
> + TEST_MSIX,
> };
>
> static const char fbnic_gstrings_self_test[][ETH_GSTRING_LEN] = {
> [TEST_REG] = "Register test (offline)",
> + [TEST_MSIX] = "MSI-X Interrupt test (offline)",
> };
>
> #define FBNIC_TEST_LEN ARRAY_SIZE(fbnic_gstrings_self_test)
> @@ -1501,6 +1503,28 @@ static int fbnic_ethtool_regs_test(struct net_device *netdev, u64 *data)
> return !!*data;
> }
>
> +/**
> + * fbnic_ethtool_msix_test - Verify behavior of NIC interrupts
> + * @netdev: netdev device to test
> + * @data: Pointer to results storage
> + *
> + * This function is meant to test the global interrupt registers and the
> + * PCIe IP MSI-X functionality. It essentially goes through and tests
> + * test various combinations of the set, clear, and mask bits in order to
> + * verify the behavior is as we expect it to be from the driver.
> + *
> + * Return: non-zero on failure.
> + **/
> +static int fbnic_ethtool_msix_test(struct net_device *netdev, u64 *data)
> +{
> + struct fbnic_net *fbn = netdev_priv(netdev);
> + struct fbnic_dev *fbd = fbn->fbd;
> +
> + *data = fbnic_msix_test(fbd);
> +
> + return !!*data;
> +}
> +
> static void fbnic_self_test(struct net_device *netdev,
> struct ethtool_test *eth_test, u64 *data)
> {
> @@ -1508,6 +1532,7 @@ static void fbnic_self_test(struct net_device *netdev,
>
> if (!(eth_test->flags & ETH_TEST_FL_OFFLINE)) {
> data[TEST_REG] = 0;
> + data[TEST_MSIX] = 0;
> return;
> }
>
> @@ -1517,6 +1542,9 @@ static void fbnic_self_test(struct net_device *netdev,
> if (fbnic_ethtool_regs_test(netdev, &data[TEST_REG]))
> eth_test->flags |= ETH_TEST_FL_FAILED;
>
> + if (fbnic_ethtool_msix_test(netdev, &data[TEST_MSIX]))
> + eth_test->flags |= ETH_TEST_FL_FAILED;
> +
> if (if_running && netif_open(netdev, NULL)) {
> netdev_err(netdev,
> "Failed to re-initialize hardware following test\n");
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
> index 02e8b0b257fe..44034d53112c 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
> @@ -238,6 +238,160 @@ void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data)
> free_irq(irq, data);
> }
>
> +struct fbnic_msix_test_data {
> + struct fbnic_dev *fbd;
> + unsigned long test_msix_status[BITS_TO_LONGS(FBNIC_MAX_MSIX_VECS)];
> + int irq_vector[FBNIC_MAX_MSIX_VECS];
> +};
> +
> +static irqreturn_t fbnic_irq_test(int irq, void *data)
> +{
> + struct fbnic_msix_test_data *test_data = data;
> + struct fbnic_dev *fbd = test_data->fbd;
> + int i;
> +
> + for (i = fbd->num_irqs; i--;) {
> + if (test_data->irq_vector[i] == irq) {
> + set_bit(i, test_data->test_msix_status);
> + break;
> + }
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * fbnic_msix_test - Verify behavior of NIC interrupts
> + * @fbd: device to test
> + *
> + * This function is meant to test the global interrupt registers and the
> + * PCIe IP MSI-X functionality. It essentially goes through and tests
> + * various combinations of the set, clear, and mask bits in order to
> + * verify the behavior is as we expect it to be from the driver.
> + *
> + * Return: See enum fbnic_msix_self_test_codes
> + **/
> +enum fbnic_msix_self_test_codes fbnic_msix_test(struct fbnic_dev *fbd)
> +{
> + enum fbnic_msix_self_test_codes result = FBNIC_TEST_MSIX_SUCCESS;
> + struct pci_dev *pdev = to_pci_dev(fbd->dev);
> + struct fbnic_msix_test_data *test_data;
> + u32 mask = 0;
> + int i;
> +
> + /* Allocate bitmap and IRQ vector table */
> + test_data = kzalloc(sizeof(*test_data), GFP_KERNEL);
There is a change in the patchworks checkpatch test the wants to see this as:
test_data = kzalloc_obj(*test_data, GFP_KERNEL);
Unfortunately, the net-next repo does not yet have this api and doesn't
have the checkpatch and the new api that comes in:
Commit 070580b0b174 ("checkpatch: Suggest kmalloc_obj family for sizeof allocations")
This looks like the checkpatch.pl in the test is not from net-next/main.
> +
> + /* memory allocation failure */
> + if (!test_data)
> + return FBNIC_TEST_MSIX_NOMEM;
> +
> + /* Initialize test data */
> + test_data->fbd = fbd;
> +
> + for (i = FBNIC_NON_NAPI_VECTORS; i < fbd->num_irqs; i++) {
> + /* Add IRQ to vector table so it can be found */
> + test_data->irq_vector[i] = pci_irq_vector(pdev, i);
> +
> + /* Enable the interrupt */
> + if (!fbnic_request_irq(fbd, i, fbnic_irq_test, 0,
> + fbd->netdev->name, test_data))
> + continue;
> +
> + while (i-- > FBNIC_NON_NAPI_VECTORS)
> + fbnic_free_irq(fbd, i, test_data);
> + kfree(test_data);
> +
> + /* IRQ request failure */
> + return FBNIC_TEST_MSIX_IRQ_REQ_FAIL;
> + }
> +
> + /* Test each bit individually */
> + for (i = FBNIC_NON_NAPI_VECTORS; i < fbd->num_irqs; i++) {
> + mask = 1U << (i % 32);
> +
> + /* Start with mask set and interrupt cleared */
> + fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(i / 32), mask);
> + fbnic_wrfl(fbd);
> + fbnic_wr32(fbd, FBNIC_INTR_CLEAR(i / 32), mask);
> + fbnic_wrfl(fbd);
> +
> + /* masking failure to prevent interrupt */
> + result = FBNIC_TEST_MSIX_MASK;
> +
> + fbnic_wr32(fbd, FBNIC_INTR_SET(i / 32), mask);
> + fbnic_wrfl(fbd);
> + usleep_range(10000, 11000);
> +
> + if (test_bit(i, test_data->test_msix_status))
> + break;
> +
> + /* unmasking failure w/ sw status set */
> + result = FBNIC_TEST_MSIX_UNMASK;
> +
> + fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(i / 32), mask);
> + fbnic_wrfl(fbd);
> + usleep_range(10000, 11000);
> +
> + if (!test_bit(i, test_data->test_msix_status))
> + break;
> +
> + /* interrupt when clearing mask */
> + result = FBNIC_TEST_MSIX_IRQ_CLEAR;
> +
> + clear_bit(i, test_data->test_msix_status);
> + fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(i / 32), mask);
> + fbnic_wrfl(fbd);
> + usleep_range(10000, 11000);
> +
> + if (test_bit(i, test_data->test_msix_status))
> + break;
> +
> + /* interrupt not triggering when not masked */
> + result = FBNIC_TEST_MSIX_NO_INTERRUPT;
> +
> + fbnic_wr32(fbd, FBNIC_INTR_SET(i / 32), mask);
> + fbnic_wrfl(fbd);
> + usleep_range(10000, 11000);
> +
> + if (!test_bit(i, test_data->test_msix_status))
> + break;
> +
> + /* status not cleared, or mask not set */
> + result = FBNIC_TEST_MSIX_NO_CLEAR_OR_MASK;
> + if (mask & fbnic_rd32(fbd, FBNIC_INTR_STATUS(i / 32)))
> + break;
> + if (!(mask & fbnic_rd32(fbd, FBNIC_INTR_MASK(i / 32))))
> + break;
> +
> + /* Result = 0 - Success */
> + result = FBNIC_TEST_MSIX_SUCCESS;
> +
> + clear_bit(i, test_data->test_msix_status);
> + }
> +
> + if (i < fbd->num_irqs) {
> + fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(i / 32), mask);
> + fbnic_wrfl(fbd);
> + fbnic_wr32(fbd, FBNIC_INTR_CLEAR(i / 32), mask);
> + fbnic_wrfl(fbd);
> + clear_bit(i, test_data->test_msix_status);
> + }
> +
> + for (i = FBNIC_NON_NAPI_VECTORS; i < fbd->num_irqs; i++) {
> + /* Test for bits set after testing */
> + if (test_bit(i, test_data->test_msix_status))
> + result = FBNIC_TEST_MSIX_BITS_SET_AFTER_TEST;
> +
> + /* Free IRQ */
> + fbnic_free_irq(fbd, i, test_data);
> + }
> +
> + kfree(test_data);
> +
> + return result;
> +}
> +
> void fbnic_napi_name_irqs(struct fbnic_dev *fbd)
> {
> unsigned int i;
> --
> 2.43.0
>
next prev parent reply other threads:[~2026-03-06 19:27 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-05 15:09 [PATCH net-next v3 0/5] eth fbnic: Add fbnic self tests mike.marciniszyn
2026-03-05 15:09 ` [PATCH net-next v3 1/5] net: export netif_open for self_test usage mike.marciniszyn
2026-03-06 19:30 ` Mike Marciniszyn
2026-03-05 15:09 ` [PATCH net-next v3 2/5] eth fbnic: Add register self test mike.marciniszyn
2026-03-05 15:09 ` [PATCH net-next v3 3/5] eth fbnic: Add msix " mike.marciniszyn
2026-03-06 19:27 ` Mike Marciniszyn [this message]
2026-03-06 22:09 ` Jakub Kicinski
2026-03-07 10:58 ` Mike Marciniszyn
2026-03-05 15:09 ` [PATCH net-next v3 4/5] eth fbnic: TLV support for use by MBX " mike.marciniszyn
2026-03-05 15:09 ` [PATCH net-next v3 5/5] eth fbnic: Add mailbox " mike.marciniszyn
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=aasqpPj2rOIKgnSY@PF5YBGDS.localdomain \
--to=mike.marciniszyn@gmail.com \
--cc=alexanderduyck@fb.com \
--cc=andrew+netdev@lunn.ch \
--cc=dan.carpenter@linaro.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jacob.e.keller@intel.com \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=lee@trager.us \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=liuhangbin@gmail.com \
--cc=mohsin.bashr@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=skhawaja@google.com \
--cc=willemb@google.com \
--cc=xiaopei01@kylinos.cn \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox