From nobody Sun Feb 8 19:54:38 2026 Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9114C2D7DF2 for ; Fri, 6 Feb 2026 15:42:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770392571; cv=none; b=AuDHyhgB2TlMl7SvtFLH53uY99K3EVJSKsUfwxGGOWBCNOh2WfKF9lRqwd+3os8a+81gNQxVyx86ncou/Lq2bcXDD8VyNy7nEbRN+ANrM0dePq7yB9Uxn13TjBum5nI2yupfEFmQrPju/vXWUlNg85lzGmPZrZ9TO4q7i41sv+E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770392571; c=relaxed/simple; bh=00tZ7hEKaVSKAGSZ3kjjf4Nu/LRjLj2wUt3oFw5KAcA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gDv/8Pi/WSFbKEE3XxkqGHOsnu1ub0vRfneHmHqkZ4LH+XQXb6RwjMbIDs3GSgm1dnyRu9CXWLrpq71LJMl5tT4vp/J8tpqa4RGhbQ7ro7feAvV+Rg1b0DyoO6+9XkJzgKiaMoloSazLmUd5du+nhzYyOxTZlImvd2+0rOaTfjQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=NhkTVQMG; arc=none smtp.client-ip=209.85.222.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NhkTVQMG" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-8c6aaf3cd62so213598385a.3 for ; Fri, 06 Feb 2026 07:42:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770392570; x=1770997370; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+eYlMgeBfdVMTpRaGQ8tUVtwdsLeLniXT3Abva0RN7Y=; b=NhkTVQMGBryqOfrPlLlZng0BAcfGQiI46hpoAJveY6rFxUbt89rVSCP9Fo1rub3EJy cUUkdY1LrXY2CTorjrYNpF+oRRv0jwtHeX6/U4ikcb/p0XmDgmgvaosPuusqAyIcF+Du hk3aCiqVky3Xs9LizrBMPZtu+d0kbk7vuMsOjHFgB8WtSkRgYO7CFDMS3hylzOTmHgdK GPgDaqdGBuqxxrYVL1h/qzLKGvCr9dPD7XubB226IkGVL39uNAJz5ZTybIOljBe42/w/ WeGjCFSt2dIlG5GyTjUnschyPDKJQ9rQwJgrkHIGKEkaRsbk6RZPWHDAQ4PcTpwDuRNQ pYFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770392570; x=1770997370; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=+eYlMgeBfdVMTpRaGQ8tUVtwdsLeLniXT3Abva0RN7Y=; b=QqNqaXyy2GeNVbu7wzC3GO34I2r1Da3qPRNcfev01NgXAVxFabOzqyyHEmgVbRSaRd pnDEAfhP+3QyeFRinucRD4071K1PDmmoffuLPsLpAWMC8+NxM5ZRta6UfkgH6i4vkQQX yqRrJUgwwLO4/hjyuylA+gR3Tsewr2KfnnD2P1DC1rVZaAuyd1pSnibnvAk6QVXRiLVi EKwqQzd5071rGhNvWAhBsTeeZvCc6RKkYumOt7swy8dyyoLUs40MTjdpdMopTvDY8zh5 hmtF6glhB46CkOjRXXe/7UWNkdbj394LYILcDBXICJ6015ZndwIAAPei06XEGT6VR8Wb jw+A== X-Forwarded-Encrypted: i=1; AJvYcCVl8QTIQDP6GWl/OpnZUluJmKgJPDJ6mPnhXWGId07sGvykLRf1dxULzvxGBQODMWIZPkphVFBonMCg4no=@vger.kernel.org X-Gm-Message-State: AOJu0Yyon08r6HZw50woGvjZvxBIhiiC5MkgRz0EcnPXSTzkKABJY2mi BK/Pla18yyoH8WrQ3jAktttcpXm2FOrf6Ny48/7aypek7MXvZi6YqwQA X-Gm-Gg: AZuq6aJOco06I/EMfKZnuQhyvxdxjtGpn+beGKhLgUkxl06MOW7ggp5drqvDOO51Ud1 PQPWYm2SvRc5NAJ70krWJGozwZeo5CdkPsSwhKk01NKDKN/Ond6sp6GvSOkPoP0+0fbVlfEhNVf 5a4Hi5h8uwfcfdEItCAQ2HwQkVF/WB6X2yEFgWWCZhfbAN0RvrSPhHcqETSSjOrDIQplRY+4NSW u11BXfU7aaCXMuGAt/f7MXYMi8wrfBRszkdzl8CsupwOSKRQCmA0X3MuTvecHGcS9yghVq4HAsW fPElbXjU1Rgv3hJVGpr2bVelm1QkERQBR6KxPGECLwbaBWwlF3l5yEC7A6CK3BhWvAIXTBDcy/g iRhbaP2LkY49uDCi5qL1j50uBhZmoYdIvcR1B2m4w4o76CMxtZr/p9n8ngTOJQEW3zpCv7dJO9K gj9wr4k8ZkmIoOzp0dsV/2VUcx2Ag40te/0/16Vg/4kCQ4 X-Received: by 2002:a05:620a:bc9:b0:8ca:d5cb:6841 with SMTP id af79cd13be357-8caf1acb650mr389015585a.49.1770392570454; Fri, 06 Feb 2026 07:42:50 -0800 (PST) Received: from PF5YBGDS.localdomain ([163.114.130.1]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8caf9eea0c0sm181499185a.42.2026.02.06.07.42.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 07:42:50 -0800 (PST) From: mike.marciniszyn@gmail.com To: Alexander Duyck , Jakub Kicinski , kernel-team@meta.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Russell King , Jacob Keller , Mohsin Bashir , Lee Trager , "Mike Marciniszyn (Meta)" , Dan Carpenter , Pei Xiao , Stanislav Fomichev , Kuniyuki Iwashima , Samiullah Khawaja , Ahmed Zaki , Alexander Lobakin Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next v12 2/5] eth fbnic: Add register self test Date: Fri, 6 Feb 2026 10:42:42 -0500 Message-ID: <20260206154246.814-3-mike.marciniszyn@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260206154246.814-1-mike.marciniszyn@gmail.com> References: <20260206154246.814-1-mike.marciniszyn@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Mike Marciniszyn (Meta)" The register test will be used to verify hardware is behaving as expected. The test itself will have us writing to registers that should have no side effects due to us resetting after the test has been completed. While the test is being run the interface should be offline. This patch counts on the first patch of this series to export netif_open() and also ensures that the half close calls netif_close() to avoid deadlock. Signed-off-by: Mike Marciniszyn (Meta) --- drivers/net/ethernet/meta/fbnic/fbnic_csr.c | 126 ++++++++++++++++++ drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 4 + .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 50 +++++++ 3 files changed, 180 insertions(+) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.c b/drivers/net/ethe= rnet/meta/fbnic/fbnic_csr.c index d9c0dc1c2af9..c1541388d23c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.c @@ -147,3 +147,129 @@ int fbnic_csr_regs_len(struct fbnic_dev *fbd) return len; } + +/* CSR register test data + * + * The register test will be used to verify hardware is behaving as expect= ed. + * + * The test itself will have us writing to registers that should have no + * side effects due to us resetting after the test has been completed. + * While the test is being run the interface should be offline. + */ +struct fbnic_csr_reg_test_data { + int reg; + u16 reg_offset; + u8 array_len; + u32 read; + u32 write; +}; + +#define FBNIC_QUEUE_REG_TEST(_name, _read, _write) { \ + .reg =3D FBNIC_QUEUE(0) + FBNIC_QUEUE_##_name, \ + .reg_offset =3D FBNIC_QUEUE_STRIDE, \ + .array_len =3D 64, \ + .read =3D _read, \ + .write =3D _write \ +} + +static const struct fbnic_csr_reg_test_data pattern_test[] =3D { + FBNIC_QUEUE_REG_TEST(TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET, + FBNIC_QUEUE_TWQ_CTL_RESET), + FBNIC_QUEUE_REG_TEST(TWQ0_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(TWQ0_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TWQ0_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TWQ0_BAH, ~0, ~0), + FBNIC_QUEUE_REG_TEST(TWQ1_CTL, FBNIC_QUEUE_TWQ_CTL_RESET, + FBNIC_QUEUE_TWQ_CTL_RESET), + FBNIC_QUEUE_REG_TEST(TWQ1_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(TWQ1_SIZE, FBNIC_QUEUE_TWQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TWQ1_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TWQ1_BAH, ~0, ~0), + FBNIC_QUEUE_REG_TEST(TCQ_CTL, FBNIC_QUEUE_TCQ_CTL_RESET, + FBNIC_QUEUE_TCQ_CTL_RESET), + FBNIC_QUEUE_REG_TEST(TCQ_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(TCQ_SIZE, FBNIC_QUEUE_TCQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(TCQ_BAH, ~0, ~0), + FBNIC_QUEUE_REG_TEST(RCQ_CTL, FBNIC_QUEUE_RCQ_CTL_RESET, + FBNIC_QUEUE_RCQ_CTL_RESET), + FBNIC_QUEUE_REG_TEST(RCQ_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(RCQ_SIZE, FBNIC_QUEUE_RCQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(RCQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(RCQ_BAH, ~0, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_CTL, FBNIC_QUEUE_BDQ_CTL_RESET, + FBNIC_QUEUE_BDQ_CTL_RESET), + FBNIC_QUEUE_REG_TEST(BDQ_HPQ_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_HPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_HPQ_BAH, ~0, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_PPQ_PTRS, 0, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_PPQ_SIZE, FBNIC_QUEUE_BDQ_SIZE_MASK, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAL, FBNIC_QUEUE_BAL_MASK, ~0), + FBNIC_QUEUE_REG_TEST(BDQ_PPQ_BAH, ~0, ~0), +}; + +static int +fbnic_csr_reg_pattern_test(struct fbnic_dev *fbd, int index, + const struct fbnic_csr_reg_test_data *test_data) +{ + static const u32 pattern[] =3D { ~0, 0x5A5A5A5A, 0xA5A5A5A5, 0}; + u32 reg =3D test_data->reg + test_data->reg_offset * index; + int i; + + for (i =3D 0; i < ARRAY_SIZE(pattern); i++) { + u32 val =3D pattern[i] & test_data->write; + u32 result; + + wr32(fbd, reg, val); + result =3D rd32(fbd, reg); + val &=3D test_data->read; + + if (result =3D=3D val) + continue; + + dev_err(fbd->dev, + "%s: reg 0x%06X failed, expected 0x%08X received 0x%08X\n", + __func__, reg, val, result); + + /* Note that FBNIC_INTR_STATUS(0) could be tested and fail + * and the result would not be reported since the register + * offset is 0. However as that register isn't included in + * the register test that isn't an issue. + */ + return reg; + } + + return 0; +} + +/** + * fbnic_csr_regs_test() - Verify behavior of NIC registers + * @fbd: device to test + * + * This function is meant to test the bit values of various registers in + * the NIC device. Specifically this test will verify which bits are + * writable and which ones are not. It will write varying patterns of bits + * to the registers testing for sticky bits, or bits that are writable but + * should not be. + * + * Return: non-zero on failure. + **/ +int fbnic_csr_regs_test(struct fbnic_dev *fbd) +{ + const struct fbnic_csr_reg_test_data *test_data; + + for (test_data =3D pattern_test; + test_data < pattern_test + ARRAY_SIZE(pattern_test); test_data++) { + u32 i; + + for (i =3D 0; i < test_data->array_len; i++) { + int reg =3D fbnic_csr_reg_pattern_test(fbd, i, test_data); + + if (reg) + return reg; + } + } + + return 0; +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethe= rnet/meta/fbnic/fbnic_csr.h index b717db879cd3..633a29146617 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -1210,4 +1210,8 @@ enum{ FBNIC_CSR_VERSION_V1_0_ASIC =3D 1, }; +struct fbnic_dev; + +int fbnic_csr_regs_test(struct fbnic_dev *fbd); + #endif /* _FBNIC_CSR_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/= ethernet/meta/fbnic/fbnic_ethtool.c index 11745a2d8a44..2e882dbd408d 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -126,6 +126,16 @@ static const struct fbnic_stat fbnic_gstrings_xdp_stat= s[] =3D { #define FBNIC_STATS_LEN \ (FBNIC_HW_STATS_LEN + FBNIC_XDP_STATS_LEN * FBNIC_MAX_XDPQS) +enum fbnic_self_test_results { + TEST_REG =3D 0, +}; + +static const char fbnic_gstrings_self_test[][ETH_GSTRING_LEN] =3D { + [TEST_REG] =3D "Register test (offline)", +}; + +#define FBNIC_TEST_LEN ARRAY_SIZE(fbnic_gstrings_self_test) + static void fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvin= fo) { @@ -475,6 +485,10 @@ static void fbnic_get_strings(struct net_device *dev, = u32 sset, u8 *data) for (i =3D 0; i < FBNIC_MAX_XDPQS; i++) fbnic_get_xdp_queue_strings(&data, i); break; + case ETH_SS_TEST: + memcpy(data, fbnic_gstrings_self_test, + sizeof(fbnic_gstrings_self_test)); + break; } } @@ -566,6 +580,8 @@ static int fbnic_get_sset_count(struct net_device *dev,= int sset) switch (sset) { case ETH_SS_STATS: return FBNIC_STATS_LEN; + case ETH_SS_TEST: + return FBNIC_TEST_LEN; default: return -EOPNOTSUPP; } @@ -1475,6 +1491,39 @@ fbnic_remove_rxfh_context(struct net_device *netdev, return 0; } +static int fbnic_ethtool_regs_test(struct net_device *netdev, u64 *data) +{ + struct fbnic_net *fbn =3D netdev_priv(netdev); + struct fbnic_dev *fbd =3D fbn->fbd; + + *data =3D fbnic_csr_regs_test(fbd); + + return !!*data; +} + +static void fbnic_self_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + bool if_running =3D netif_running(netdev); + + if (!(eth_test->flags & ETH_TEST_FL_OFFLINE)) { + data[TEST_REG] =3D 0; + return; + } + + if (if_running) + netif_close(netdev); + + if (fbnic_ethtool_regs_test(netdev, &data[TEST_REG])) + eth_test->flags |=3D ETH_TEST_FL_FAILED; + + if (if_running && netif_open(netdev, NULL)) { + netdev_err(netdev, + "Failed to re-initialize hardware following test\n"); + eth_test->flags |=3D ETH_TEST_FL_FAILED; + } +} + static void fbnic_get_channels(struct net_device *netdev, struct ethtool_channels *ch) { @@ -1893,6 +1942,7 @@ static const struct ethtool_ops fbnic_ethtool_ops =3D= { .get_pause_stats =3D fbnic_get_pause_stats, .get_pauseparam =3D fbnic_phylink_get_pauseparam, .set_pauseparam =3D fbnic_phylink_set_pauseparam, + .self_test =3D fbnic_self_test, .get_strings =3D fbnic_get_strings, .get_ethtool_stats =3D fbnic_get_ethtool_stats, .get_sset_count =3D fbnic_get_sset_count, -- 2.43.0