Commit baf9d20b authored by Takashi Sakamoto's avatar Takashi Sakamoto

firewire: core: add common inline functions to serialize/deserialize self ID packet

Within FireWire subsystem, the serializations and deserializations of phy
packet are implemented in several parts. They includes some redundancies.

This commit adds a series of helper functions for the serializations and
deserializations of self ID packet with a Kunit test suite.

Link: https://lore.kernel.org/r/20240605235155.116468-8-o-takashi@sakamocchi.jpSigned-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
parent a16931ac
......@@ -10,6 +10,7 @@
#include <linux/firewire-constants.h>
#include "packet-header-definitions.h"
#include "phy-packet-definitions.h"
static void serialize_async_header_common(u32 header[ASYNC_HEADER_QUADLET_COUNT],
unsigned int dst_id, unsigned int tlabel,
......@@ -187,6 +188,66 @@ static void deserialize_isoc_header(u32 header, unsigned int *data_length, unsig
*sy = isoc_header_get_sy(header);
}
static void serialize_phy_packet_self_id_zero(u32 *quadlet, unsigned int packet_identifier,
unsigned int phy_id, bool extended,
bool link_is_active, unsigned int gap_count,
unsigned int scode, bool is_contender,
unsigned int power_class, bool is_initiated_reset,
bool has_more_packets)
{
phy_packet_set_packet_identifier(quadlet, packet_identifier);
phy_packet_self_id_set_phy_id(quadlet, phy_id);
phy_packet_self_id_set_extended(quadlet, extended);
phy_packet_self_id_zero_set_link_active(quadlet, link_is_active);
phy_packet_self_id_zero_set_gap_count(quadlet, gap_count);
phy_packet_self_id_zero_set_scode(quadlet, scode);
phy_packet_self_id_zero_set_contender(quadlet, is_contender);
phy_packet_self_id_zero_set_power_class(quadlet, power_class);
phy_packet_self_id_zero_set_initiated_reset(quadlet, is_initiated_reset);
phy_packet_self_id_set_more_packets(quadlet, has_more_packets);
}
static void deserialize_phy_packet_self_id_zero(u32 quadlet, unsigned int *packet_identifier,
unsigned int *phy_id, bool *extended,
bool *link_is_active, unsigned int *gap_count,
unsigned int *scode, bool *is_contender,
unsigned int *power_class,
bool *is_initiated_reset, bool *has_more_packets)
{
*packet_identifier = phy_packet_get_packet_identifier(quadlet);
*phy_id = phy_packet_self_id_get_phy_id(quadlet);
*extended = phy_packet_self_id_get_extended(quadlet);
*link_is_active = phy_packet_self_id_zero_get_link_active(quadlet);
*gap_count = phy_packet_self_id_zero_get_gap_count(quadlet);
*scode = phy_packet_self_id_zero_get_scode(quadlet);
*is_contender = phy_packet_self_id_zero_get_contender(quadlet);
*power_class = phy_packet_self_id_zero_get_power_class(quadlet);
*is_initiated_reset = phy_packet_self_id_zero_get_initiated_reset(quadlet);
*has_more_packets = phy_packet_self_id_get_more_packets(quadlet);
}
static void serialize_phy_packet_self_id_extended(u32 *quadlet, unsigned int packet_identifier,
unsigned int phy_id, bool extended,
unsigned int sequence, bool has_more_packets)
{
phy_packet_set_packet_identifier(quadlet, packet_identifier);
phy_packet_self_id_set_phy_id(quadlet, phy_id);
phy_packet_self_id_set_extended(quadlet, extended);
phy_packet_self_id_extended_set_sequence(quadlet, sequence);
phy_packet_self_id_set_more_packets(quadlet, has_more_packets);
}
static void deserialize_phy_packet_self_id_extended(u32 quadlet, unsigned int *packet_identifier,
unsigned int *phy_id, bool *extended,
unsigned int *sequence, bool *has_more_packets)
{
*packet_identifier = phy_packet_get_packet_identifier(quadlet);
*phy_id = phy_packet_self_id_get_phy_id(quadlet);
*extended = phy_packet_self_id_get_extended(quadlet);
*sequence = phy_packet_self_id_extended_get_sequence(quadlet);
*has_more_packets = phy_packet_self_id_get_more_packets(quadlet);
}
static void test_async_header_write_quadlet_request(struct kunit *test)
{
static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = {
......@@ -559,6 +620,197 @@ static void test_isoc_header(struct kunit *test)
KUNIT_EXPECT_EQ(test, header, expected);
}
static void test_phy_packet_self_id_zero_case0(struct kunit *test)
{
// TSB41AB1/2 with 1 port.
const u32 expected[] = {0x80458c80};
u32 quadlets[] = {0};
unsigned int packet_identifier;
unsigned int phy_id;
bool extended;
bool link_is_active;
unsigned int gap_count;
unsigned int scode;
bool is_contender;
unsigned int power_class;
enum phy_packet_self_id_port_status port_status[3];
bool is_initiated_reset;
bool has_more_packets;
unsigned int port_index;
deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended,
&link_is_active, &gap_count, &scode, &is_contender,
&power_class, &is_initiated_reset, &has_more_packets);
KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier);
KUNIT_EXPECT_EQ(test, 0, phy_id);
KUNIT_EXPECT_FALSE(test, extended);
KUNIT_EXPECT_TRUE(test, link_is_active);
KUNIT_EXPECT_EQ(test, 0x05, gap_count);
KUNIT_EXPECT_EQ(test, SCODE_400, scode);
KUNIT_EXPECT_TRUE(test, is_contender);
KUNIT_EXPECT_EQ(test, 0x4, power_class);
KUNIT_EXPECT_FALSE(test, is_initiated_reset);
KUNIT_EXPECT_FALSE(test, has_more_packets);
serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended,
link_is_active, gap_count, scode, is_contender,
power_class, is_initiated_reset, has_more_packets);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
port_status[port_index] =
self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index);
}
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[0]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[1]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[2]);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index,
port_status[port_index]);
}
KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected));
}
static void test_phy_packet_self_id_zero_case1(struct kunit *test)
{
// XIO2213 and TSB81BA3E with 3 ports.
const u32 expected[] = {0x817fcc5e};
u32 quadlets[] = {0};
unsigned int packet_identifier;
unsigned int phy_id;
bool extended;
bool link_is_active;
unsigned int gap_count;
unsigned int scode;
bool is_contender;
unsigned int power_class;
enum phy_packet_self_id_port_status port_status[3];
bool is_initiated_reset;
bool has_more_packets;
unsigned int port_index;
deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended,
&link_is_active, &gap_count, &scode, &is_contender,
&power_class, &is_initiated_reset, &has_more_packets);
KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier);
KUNIT_EXPECT_EQ(test, 1, phy_id);
KUNIT_EXPECT_FALSE(test, extended);
KUNIT_EXPECT_TRUE(test, link_is_active);
KUNIT_EXPECT_EQ(test, 0x3f, gap_count);
KUNIT_EXPECT_EQ(test, SCODE_800, scode);
KUNIT_EXPECT_TRUE(test, is_contender);
KUNIT_EXPECT_EQ(test, 0x4, power_class);
KUNIT_EXPECT_TRUE(test, is_initiated_reset);
KUNIT_EXPECT_FALSE(test, has_more_packets);
serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended,
link_is_active, gap_count, scode, is_contender,
power_class, is_initiated_reset, has_more_packets);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
port_status[port_index] =
self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index);
}
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[0]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[1]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[2]);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index,
port_status[port_index]);
}
KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected));
}
static void test_phy_packet_self_id_zero_and_one(struct kunit *test)
{
// TSB41LV06A with 6 ports.
const u32 expected[] = {
0x803f8459,
0x80815000,
};
u32 quadlets[] = {0, 0};
unsigned int packet_identifier;
unsigned int phy_id;
bool extended;
bool link_is_active;
unsigned int gap_count;
unsigned int scode;
bool is_contender;
unsigned int power_class;
enum phy_packet_self_id_port_status port_status[11];
bool is_initiated_reset;
bool has_more_packets;
unsigned int sequence;
unsigned int port_index;
deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended,
&link_is_active, &gap_count, &scode, &is_contender,
&power_class, &is_initiated_reset, &has_more_packets);
KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier);
KUNIT_EXPECT_EQ(test, 0, phy_id);
KUNIT_EXPECT_FALSE(test, extended);
KUNIT_EXPECT_FALSE(test, link_is_active);
KUNIT_EXPECT_EQ(test, 0x3f, gap_count);
KUNIT_EXPECT_EQ(test, SCODE_400, scode);
KUNIT_EXPECT_FALSE(test, is_contender);
KUNIT_EXPECT_EQ(test, 0x4, power_class);
KUNIT_EXPECT_FALSE(test, is_initiated_reset);
KUNIT_EXPECT_TRUE(test, has_more_packets);
serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended,
link_is_active, gap_count, scode, is_contender,
power_class, is_initiated_reset, has_more_packets);
deserialize_phy_packet_self_id_extended(expected[1], &packet_identifier, &phy_id, &extended,
&sequence, &has_more_packets);
KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier);
KUNIT_EXPECT_EQ(test, 0, phy_id);
KUNIT_EXPECT_TRUE(test, extended);
KUNIT_EXPECT_EQ(test, 0, sequence);
KUNIT_EXPECT_FALSE(test, has_more_packets);
serialize_phy_packet_self_id_extended(&quadlets[1], packet_identifier, phy_id, extended,
sequence, has_more_packets);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
port_status[port_index] =
self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index);
}
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[0]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[1]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[2]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[3]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[4]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[5]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[6]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[7]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[8]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[9]);
KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[10]);
for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) {
self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index,
port_status[port_index]);
}
KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(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),
......@@ -570,6 +822,9 @@ static struct kunit_case packet_serdes_test_cases[] = {
KUNIT_CASE(test_async_header_lock_request),
KUNIT_CASE(test_async_header_lock_response),
KUNIT_CASE(test_isoc_header),
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),
{}
};
......
......@@ -7,11 +7,42 @@
#ifndef _FIREWIRE_PHY_PACKET_DEFINITIONS_H
#define _FIREWIRE_PHY_PACKET_DEFINITIONS_H
#define PACKET_IDENTIFIER_MASK 0xc0000000
#define PACKET_IDENTIFIER_SHIFT 30
static inline unsigned int phy_packet_get_packet_identifier(u32 quadlet)
{
return (quadlet & PACKET_IDENTIFIER_MASK) >> PACKET_IDENTIFIER_SHIFT;
}
static inline void phy_packet_set_packet_identifier(u32 *quadlet, unsigned int packet_identifier)
{
*quadlet &= ~PACKET_IDENTIFIER_MASK;
*quadlet |= (packet_identifier << PACKET_IDENTIFIER_SHIFT) & PACKET_IDENTIFIER_MASK;
}
#define PHY_PACKET_PACKET_IDENTIFIER_SELF_ID 2
#define SELF_ID_PHY_ID_MASK 0x3f000000
#define SELF_ID_PHY_ID_SHIFT 24
#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_ZERO_LINK_ACTIVE_MASK 0x00400000
#define SELF_ID_ZERO_LINK_ACTIVE_SHIFT 22
#define SELF_ID_ZERO_GAP_COUNT_MASK 0x003f0000
#define SELF_ID_ZERO_GAP_COUNT_SHIFT 16
#define SELF_ID_ZERO_SCODE_MASK 0x0000c000
#define SELF_ID_ZERO_SCODE_SHIFT 14
#define SELF_ID_ZERO_CONTENDER_MASK 0x00000800
#define SELF_ID_ZERO_CONTENDER_SHIFT 11
#define SELF_ID_ZERO_POWER_CLASS_MASK 0x00000700
#define SELF_ID_ZERO_POWER_CLASS_SHIFT 8
#define SELF_ID_ZERO_INITIATED_RESET_MASK 0x00000002
#define SELF_ID_ZERO_INITIATED_RESET_SHIFT 1
#define SELF_ID_EXTENDED_SEQUENCE_MASK 0x00700000
#define SELF_ID_EXTENDED_SEQUENCE_SHIFT 20
......@@ -19,21 +50,116 @@
#define SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT 4
static inline unsigned int phy_packet_self_id_get_phy_id(u32 quadlet)
{
return (quadlet & SELF_ID_PHY_ID_MASK) >> SELF_ID_PHY_ID_SHIFT;
}
static inline void phy_packet_self_id_set_phy_id(u32 *quadlet, unsigned int phy_id)
{
*quadlet &= ~SELF_ID_PHY_ID_MASK;
*quadlet |= (phy_id << SELF_ID_PHY_ID_SHIFT) & SELF_ID_PHY_ID_MASK;
}
static inline bool phy_packet_self_id_get_extended(u32 quadlet)
{
return (quadlet & SELF_ID_EXTENDED_MASK) >> SELF_ID_EXTENDED_SHIFT;
}
static inline void phy_packet_self_id_set_extended(u32 *quadlet, bool extended)
{
*quadlet &= ~SELF_ID_EXTENDED_MASK;
*quadlet |= (extended << SELF_ID_EXTENDED_SHIFT) & SELF_ID_EXTENDED_MASK;
}
static inline bool phy_packet_self_id_zero_get_link_active(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_LINK_ACTIVE_MASK) >> SELF_ID_ZERO_LINK_ACTIVE_SHIFT;
}
static inline void phy_packet_self_id_zero_set_link_active(u32 *quadlet, bool is_active)
{
*quadlet &= ~SELF_ID_ZERO_LINK_ACTIVE_MASK;
*quadlet |= (is_active << SELF_ID_ZERO_LINK_ACTIVE_SHIFT) & SELF_ID_ZERO_LINK_ACTIVE_MASK;
}
static inline unsigned int phy_packet_self_id_zero_get_gap_count(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_GAP_COUNT_MASK) >> SELF_ID_ZERO_GAP_COUNT_SHIFT;
}
static inline void phy_packet_self_id_zero_set_gap_count(u32 *quadlet, unsigned int gap_count)
{
*quadlet &= ~SELF_ID_ZERO_GAP_COUNT_MASK;
*quadlet |= (gap_count << SELF_ID_ZERO_GAP_COUNT_SHIFT) & SELF_ID_ZERO_GAP_COUNT_MASK;
}
static inline unsigned int phy_packet_self_id_zero_get_scode(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_SCODE_MASK) >> SELF_ID_ZERO_SCODE_SHIFT;
}
static inline void phy_packet_self_id_zero_set_scode(u32 *quadlet, unsigned int speed)
{
*quadlet &= ~SELF_ID_ZERO_SCODE_MASK;
*quadlet |= (speed << SELF_ID_ZERO_SCODE_SHIFT) & SELF_ID_ZERO_SCODE_MASK;
}
static inline bool phy_packet_self_id_zero_get_contender(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_CONTENDER_MASK) >> SELF_ID_ZERO_CONTENDER_SHIFT;
}
static inline void phy_packet_self_id_zero_set_contender(u32 *quadlet, bool is_contender)
{
*quadlet &= ~SELF_ID_ZERO_CONTENDER_MASK;
*quadlet |= (is_contender << SELF_ID_ZERO_CONTENDER_SHIFT) & SELF_ID_ZERO_CONTENDER_MASK;
}
static inline unsigned int phy_packet_self_id_zero_get_power_class(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_POWER_CLASS_MASK) >> SELF_ID_ZERO_POWER_CLASS_SHIFT;
}
static inline void phy_packet_self_id_zero_set_power_class(u32 *quadlet, unsigned int power_class)
{
*quadlet &= ~SELF_ID_ZERO_POWER_CLASS_MASK;
*quadlet |= (power_class << SELF_ID_ZERO_POWER_CLASS_SHIFT) & SELF_ID_ZERO_POWER_CLASS_MASK;
}
static inline bool phy_packet_self_id_zero_get_initiated_reset(u32 quadlet)
{
return (quadlet & SELF_ID_ZERO_INITIATED_RESET_MASK) >> SELF_ID_ZERO_INITIATED_RESET_SHIFT;
}
static inline void phy_packet_self_id_zero_set_initiated_reset(u32 *quadlet, bool is_initiated_reset)
{
*quadlet &= ~SELF_ID_ZERO_INITIATED_RESET_MASK;
*quadlet |= (is_initiated_reset << SELF_ID_ZERO_INITIATED_RESET_SHIFT) & SELF_ID_ZERO_INITIATED_RESET_MASK;
}
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 void phy_packet_self_id_set_more_packets(u32 *quadlet, bool is_more_packets)
{
*quadlet &= ~SELF_ID_MORE_PACKETS_MASK;
*quadlet |= (is_more_packets << SELF_ID_MORE_PACKETS_SHIFT) & SELF_ID_MORE_PACKETS_MASK;
}
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;
}
static inline void phy_packet_self_id_extended_set_sequence(u32 *quadlet, unsigned int sequence)
{
*quadlet &= ~SELF_ID_EXTENDED_SEQUENCE_MASK;
*quadlet |= (sequence << SELF_ID_EXTENDED_SHIFT) & SELF_ID_EXTENDED_SEQUENCE_MASK;
}
struct self_id_sequence_enumerator {
const u32 *cursor;
unsigned int quadlet_count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment