[PATCH 1/2] firewire: core: add tests for serialization/deserialization of phy config packet

From: Takashi Sakamoto
Date: Thu Jun 06 2024 - 19:52:01 EST


In the protocol of IEEE 1394, phy configuration packet is broadcasted to
the bus to configure all PHYs residing on the bus. It includes two
purposes; selecting root node and optimizing gap count.

This commit adds some helper function to serialize/deserialize the
content of phy configuration packet, as well as some KUnit tests for it.

Signed-off-by: Takashi Sakamoto <o-takashi@xxxxxxxxxxxxx>
---
drivers/firewire/packet-serdes-test.c | 79 +++++++++++++++++++++++
drivers/firewire/phy-packet-definitions.h | 55 ++++++++++++++++
2 files changed, 134 insertions(+)

diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c
index 65cfbf1baee7..35b966eec8a5 100644
--- a/drivers/firewire/packet-serdes-test.c
+++ b/drivers/firewire/packet-serdes-test.c
@@ -248,6 +248,29 @@ static void deserialize_phy_packet_self_id_extended(u32 quadlet, unsigned int *p
*has_more_packets = phy_packet_self_id_get_more_packets(quadlet);
}

+static void serialize_phy_packet_phy_config(u32 *quadlet, unsigned int packet_identifier,
+ unsigned int root_id, bool has_force_root_node,
+ bool has_gap_count_optimization, unsigned int gap_count)
+{
+ phy_packet_set_packet_identifier(quadlet, packet_identifier);
+ phy_packet_phy_config_set_root_id(quadlet, root_id);
+ phy_packet_phy_config_set_force_root_node(quadlet, has_force_root_node);
+ phy_packet_phy_config_set_gap_count_optimization(quadlet, has_gap_count_optimization);
+ phy_packet_phy_config_set_gap_count(quadlet, gap_count);
+}
+
+static void deserialize_phy_packet_phy_config(u32 quadlet, unsigned int *packet_identifier,
+ unsigned int *root_id, bool *has_force_root_node,
+ bool *has_gap_count_optimization,
+ unsigned int *gap_count)
+{
+ *packet_identifier = phy_packet_get_packet_identifier(quadlet);
+ *root_id = phy_packet_phy_config_get_root_id(quadlet);
+ *has_force_root_node = phy_packet_phy_config_get_force_root_node(quadlet);
+ *has_gap_count_optimization = phy_packet_phy_config_get_gap_count_optimization(quadlet);
+ *gap_count = phy_packet_phy_config_get_gap_count(quadlet);
+}
+
static void test_async_header_write_quadlet_request(struct kunit *test)
{
static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = {
@@ -811,6 +834,60 @@ static void test_phy_packet_self_id_zero_and_one(struct kunit *test)
KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected));
}

+static void test_phy_packet_phy_config_force_root_node(struct kunit *test)
+{
+ const u32 expected = 0x02800000;
+ u32 quadlet = 0;
+
+ unsigned int packet_identifier;
+ unsigned int root_id;
+ bool has_force_root_node;
+ bool has_gap_count_optimization;
+ unsigned int gap_count;
+
+ deserialize_phy_packet_phy_config(expected, &packet_identifier, &root_id,
+ &has_force_root_node, &has_gap_count_optimization,
+ &gap_count);
+
+ KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG, packet_identifier);
+ KUNIT_EXPECT_EQ(test, 0x02, root_id);
+ KUNIT_EXPECT_TRUE(test, has_force_root_node);
+ KUNIT_EXPECT_FALSE(test, has_gap_count_optimization);
+ KUNIT_EXPECT_EQ(test, 0, gap_count);
+
+ serialize_phy_packet_phy_config(&quadlet, packet_identifier, root_id, has_force_root_node,
+ has_gap_count_optimization, gap_count);
+
+ KUNIT_EXPECT_EQ(test, quadlet, expected);
+}
+
+static void test_phy_packet_phy_config_gap_count_optimization(struct kunit *test)
+{
+ const u32 expected = 0x034f0000;
+ u32 quadlet = 0;
+
+ unsigned int packet_identifier;
+ unsigned int root_id;
+ bool has_force_root_node;
+ bool has_gap_count_optimization;
+ unsigned int gap_count;
+
+ deserialize_phy_packet_phy_config(expected, &packet_identifier, &root_id,
+ &has_force_root_node, &has_gap_count_optimization,
+ &gap_count);
+
+ KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG, packet_identifier);
+ KUNIT_EXPECT_EQ(test, 0x03, root_id);
+ KUNIT_EXPECT_FALSE(test, has_force_root_node);
+ KUNIT_EXPECT_TRUE(test, has_gap_count_optimization);
+ KUNIT_EXPECT_EQ(test, 0x0f, gap_count);
+
+ serialize_phy_packet_phy_config(&quadlet, packet_identifier, root_id, has_force_root_node,
+ has_gap_count_optimization, gap_count);
+
+ KUNIT_EXPECT_EQ(test, quadlet, expected);
+}
+
static struct kunit_case packet_serdes_test_cases[] = {
KUNIT_CASE(test_async_header_write_quadlet_request),
KUNIT_CASE(test_async_header_write_block_request),
@@ -825,6 +902,8 @@ static struct kunit_case packet_serdes_test_cases[] = {
KUNIT_CASE(test_phy_packet_self_id_zero_case0),
KUNIT_CASE(test_phy_packet_self_id_zero_case1),
KUNIT_CASE(test_phy_packet_self_id_zero_and_one),
+ KUNIT_CASE(test_phy_packet_phy_config_force_root_node),
+ KUNIT_CASE(test_phy_packet_phy_config_gap_count_optimization),
{}
};

diff --git a/drivers/firewire/phy-packet-definitions.h b/drivers/firewire/phy-packet-definitions.h
index 8f78494ad371..03c7c606759f 100644
--- a/drivers/firewire/phy-packet-definitions.h
+++ b/drivers/firewire/phy-packet-definitions.h
@@ -21,6 +21,61 @@ static inline void phy_packet_set_packet_identifier(u32 *quadlet, unsigned int p
*quadlet |= (packet_identifier << PACKET_IDENTIFIER_SHIFT) & PACKET_IDENTIFIER_MASK;
}

+#define PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG 0
+
+#define PHY_CONFIG_ROOT_ID_MASK 0x3f000000
+#define PHY_CONFIG_ROOT_ID_SHIFT 24
+#define PHY_CONFIG_FORCE_ROOT_NODE_MASK 0x00800000
+#define PHY_CONFIG_FORCE_ROOT_NODE_SHIFT 23
+#define PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK 0x00400000
+#define PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT 22
+#define PHY_CONFIG_GAP_COUNT_MASK 0x003f0000
+#define PHY_CONFIG_GAP_COUNT_SHIFT 16
+
+static inline unsigned int phy_packet_phy_config_get_root_id(u32 quadlet)
+{
+ return (quadlet & PHY_CONFIG_ROOT_ID_MASK) >> PHY_CONFIG_ROOT_ID_SHIFT;
+}
+
+static inline void phy_packet_phy_config_set_root_id(u32 *quadlet, unsigned int root_id)
+{
+ *quadlet &= ~PHY_CONFIG_ROOT_ID_MASK;
+ *quadlet |= (root_id << PHY_CONFIG_ROOT_ID_SHIFT) & PHY_CONFIG_ROOT_ID_MASK;
+}
+
+static inline bool phy_packet_phy_config_get_force_root_node(u32 quadlet)
+{
+ return (quadlet & PHY_CONFIG_FORCE_ROOT_NODE_MASK) >> PHY_CONFIG_FORCE_ROOT_NODE_SHIFT;
+}
+
+static inline void phy_packet_phy_config_set_force_root_node(u32 *quadlet, bool has_force_root_node)
+{
+ *quadlet &= ~PHY_CONFIG_FORCE_ROOT_NODE_MASK;
+ *quadlet |= (has_force_root_node << PHY_CONFIG_FORCE_ROOT_NODE_SHIFT) & PHY_CONFIG_FORCE_ROOT_NODE_MASK;
+}
+
+static inline bool phy_packet_phy_config_get_gap_count_optimization(u32 quadlet)
+{
+ return (quadlet & PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK) >> PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT;
+}
+
+static inline void phy_packet_phy_config_set_gap_count_optimization(u32 *quadlet, bool has_gap_count_optimization)
+{
+ *quadlet &= ~PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK;
+ *quadlet |= (has_gap_count_optimization << PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT) & PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK;
+}
+
+static inline unsigned int phy_packet_phy_config_get_gap_count(u32 quadlet)
+{
+ return (quadlet & PHY_CONFIG_GAP_COUNT_MASK) >> PHY_CONFIG_GAP_COUNT_SHIFT;
+}
+
+static inline void phy_packet_phy_config_set_gap_count(u32 *quadlet, unsigned int gap_count)
+{
+ *quadlet &= ~PHY_CONFIG_GAP_COUNT_MASK;
+ *quadlet |= (gap_count << PHY_CONFIG_GAP_COUNT_SHIFT) & PHY_CONFIG_GAP_COUNT_MASK;
+}
+
#define PHY_PACKET_PACKET_IDENTIFIER_SELF_ID 2

#define SELF_ID_PHY_ID_MASK 0x3f000000
--
2.43.0