[PATCH 01/11] firewire: core: add enumerator of self ID sequences and its KUnit test

From: Takashi Sakamoto
Date: Wed Jun 05 2024 - 19:52:17 EST


When the state of bus reset finishes, 1394 OHCI driver constructs self ID
sequences, then it calls fw_core_handle_bus_reset() in core function. The
core function enumerates the self ID sequences to build bus topology.

This commit adds a structure and some helper functions for the enumeration,
and adds a KUnit test suite to ensure its expected behaviour.

Signed-off-by: Takashi Sakamoto <o-takashi@xxxxxxxxxxxxx>
---
drivers/firewire/.kunitconfig | 1 +
drivers/firewire/Kconfig | 15 ++++
drivers/firewire/Makefile | 1 +
drivers/firewire/phy-packet-definitions.h | 78 ++++++++++++++++++
.../firewire/self-id-sequence-helper-test.c | 79 +++++++++++++++++++
5 files changed, 174 insertions(+)
create mode 100644 drivers/firewire/phy-packet-definitions.h
create mode 100644 drivers/firewire/self-id-sequence-helper-test.c

diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig
index 60d9e7c35417..74259204fcdd 100644
--- a/drivers/firewire/.kunitconfig
+++ b/drivers/firewire/.kunitconfig
@@ -4,3 +4,4 @@ CONFIG_FIREWIRE=y
CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y
CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y
CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y
+CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST=y
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 869598b20e3a..49ba692d17d8 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -66,6 +66,21 @@ config FIREWIRE_KUNIT_PACKET_SERDES_TEST
For more information on KUnit and unit tests in general, refer
to the KUnit documentation in Documentation/dev-tools/kunit/.

+config FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST
+ tristate "KUnit tests for helpers of self ID sequence" if !KUNIT_ALL_TESTS
+ depends on FIREWIRE && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds the KUnit tests for helpers of self ID sequence.
+
+ KUnit tests run during boot and output the results to the debug
+ log in TAP format (https://testanything.org/). Only useful for
+ kernel devs running KUnit test harness and are not for inclusion
+ into a production build.
+
+ For more information on KUnit and unit tests in general, refer
+ to the KUnit documentation in Documentation/dev-tools/kunit/.
+
config FIREWIRE_OHCI
tristate "OHCI-1394 controllers"
depends on PCI && FIREWIRE && MMU
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
index 75c47d046925..21b975e0a387 100644
--- a/drivers/firewire/Makefile
+++ b/drivers/firewire/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o

obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += uapi-test.o
obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += packet-serdes-test.o
+obj-$(CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST) += self-id-sequence-helper-test.o
diff --git a/drivers/firewire/phy-packet-definitions.h b/drivers/firewire/phy-packet-definitions.h
new file mode 100644
index 000000000000..479bb3431afb
--- /dev/null
+++ b/drivers/firewire/phy-packet-definitions.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// phy-packet-definitions.h - The definitions of phy packet for IEEE 1394.
+//
+// Copyright (c) 2024 Takashi Sakamoto
+
+#ifndef _FIREWIRE_PHY_PACKET_DEFINITIONS_H
+#define _FIREWIRE_PHY_PACKET_DEFINITIONS_H
+
+#define SELF_ID_EXTENDED_MASK 0x00800000
+#define SELF_ID_EXTENDED_SHIFT 23
+#define SELF_ID_MORE_PACKETS_MASK 0x00000001
+#define SELF_ID_MORE_PACKETS_SHIFT 0
+
+#define SELF_ID_EXTENDED_SEQUENCE_MASK 0x00700000
+#define SELF_ID_EXTENDED_SEQUENCE_SHIFT 20
+
+#define SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT 4
+
+static inline bool phy_packet_self_id_get_extended(u32 quadlet)
+{
+ return (quadlet & SELF_ID_EXTENDED_MASK) >> SELF_ID_EXTENDED_SHIFT;
+}
+
+static inline bool phy_packet_self_id_get_more_packets(u32 quadlet)
+{
+ return (quadlet & SELF_ID_MORE_PACKETS_MASK) >> SELF_ID_MORE_PACKETS_SHIFT;
+}
+
+static inline unsigned int phy_packet_self_id_extended_get_sequence(u32 quadlet)
+{
+ return (quadlet & SELF_ID_EXTENDED_SEQUENCE_MASK) >> SELF_ID_EXTENDED_SEQUENCE_SHIFT;
+}
+
+struct self_id_sequence_enumerator {
+ const u32 *cursor;
+ unsigned int quadlet_count;
+};
+
+static inline const u32 *self_id_sequence_enumerator_next(
+ struct self_id_sequence_enumerator *enumerator, unsigned int *quadlet_count)
+{
+ const u32 *self_id_sequence, *cursor;
+ u32 quadlet;
+ unsigned int count;
+ unsigned int sequence;
+
+ if (enumerator->cursor == NULL || enumerator->quadlet_count == 0)
+ return ERR_PTR(-ENODATA);
+ cursor = enumerator->cursor;
+ count = 1;
+
+ quadlet = *cursor;
+ sequence = 0;
+ while (phy_packet_self_id_get_more_packets(quadlet)) {
+ if (count >= enumerator->quadlet_count ||
+ count >= SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT)
+ return ERR_PTR(-EPROTO);
+ ++cursor;
+ ++count;
+ quadlet = *cursor;
+
+ if (!phy_packet_self_id_get_extended(quadlet) ||
+ sequence != phy_packet_self_id_extended_get_sequence(quadlet))
+ return ERR_PTR(-EPROTO);
+ ++sequence;
+ }
+
+ *quadlet_count = count;
+ self_id_sequence = enumerator->cursor;
+
+ enumerator->cursor += count;
+ enumerator->quadlet_count -= count;
+
+ return self_id_sequence;
+}
+
+#endif // _FIREWIRE_PHY_PACKET_DEFINITIONS_H
diff --git a/drivers/firewire/self-id-sequence-helper-test.c b/drivers/firewire/self-id-sequence-helper-test.c
new file mode 100644
index 000000000000..e8a435e20241
--- /dev/null
+++ b/drivers/firewire/self-id-sequence-helper-test.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// self-id-sequence-helper-test.c - An application of Kunit to test helpers of self ID sequence.
+//
+// Copyright (c) 2024 Takashi Sakamoto
+
+#include <kunit/test.h>
+
+#include "phy-packet-definitions.h"
+
+static void test_self_id_sequence_enumerator_valid(struct kunit *test)
+{
+ static const u32 valid_sequences[] = {
+ 0x00000000,
+ 0x00000001, 0x00800000,
+ 0x00000001, 0x00800001, 0x00900000,
+ 0x00000000,
+ };
+ struct self_id_sequence_enumerator enumerator;
+ const u32 *entry;
+ unsigned int quadlet_count;
+
+ enumerator.cursor = valid_sequences;
+ enumerator.quadlet_count = ARRAY_SIZE(valid_sequences);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
+ KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[0]);
+ KUNIT_EXPECT_EQ(test, quadlet_count, 1);
+ KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 6);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
+ KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[1]);
+ KUNIT_EXPECT_EQ(test, quadlet_count, 2);
+ KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 4);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
+ KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[3]);
+ KUNIT_EXPECT_EQ(test, quadlet_count, 3);
+ KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 1);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
+ KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[6]);
+ KUNIT_EXPECT_EQ(test, quadlet_count, 1);
+ KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 0);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
+ KUNIT_EXPECT_EQ(test, PTR_ERR(entry), -ENODATA);
+}
+
+static void test_self_id_sequence_enumerator_invalid(struct kunit *test)
+{
+ static const u32 invalid_sequences[] = {
+ 0x00000001,
+ };
+ struct self_id_sequence_enumerator enumerator;
+ const u32 *entry;
+ unsigned int count;
+
+ enumerator.cursor = invalid_sequences;
+ enumerator.quadlet_count = ARRAY_SIZE(invalid_sequences);
+
+ entry = self_id_sequence_enumerator_next(&enumerator, &count);
+ KUNIT_EXPECT_EQ(test, PTR_ERR(entry), -EPROTO);
+}
+
+static struct kunit_case self_id_sequence_helper_test_cases[] = {
+ KUNIT_CASE(test_self_id_sequence_enumerator_valid),
+ KUNIT_CASE(test_self_id_sequence_enumerator_invalid),
+ {}
+};
+
+static struct kunit_suite self_id_sequence_helper_test_suite = {
+ .name = "self-id-sequence-helper",
+ .test_cases = self_id_sequence_helper_test_cases,
+};
+kunit_test_suite(self_id_sequence_helper_test_suite);
+
+MODULE_DESCRIPTION("Unit test suite for helpers of self ID sequence");
+MODULE_LICENSE("GPL");
--
2.43.0