firewire: core: add enumerator of self ID sequences and its KUnit test
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Wed, 5 Jun 2024 23:51:45 +0000 (08:51 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sun, 16 Jun 2024 23:37:02 +0000 (08:37 +0900)
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.

Link: https://lore.kernel.org/r/20240605235155.116468-2-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
drivers/firewire/.kunitconfig
drivers/firewire/Kconfig
drivers/firewire/Makefile
drivers/firewire/phy-packet-definitions.h [new file with mode: 0644]
drivers/firewire/self-id-sequence-helper-test.c [new file with mode: 0644]

index 60d9e7c..7425920 100644 (file)
@@ -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
index 5268b3f..95e72e0 100644 (file)
@@ -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
index 75c47d0..21b975e 100644 (file)
@@ -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 (file)
index 0000000..479bb34
--- /dev/null
@@ -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 (file)
index 0000000..e8a435e
--- /dev/null
@@ -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");