1

firewire: ohci: add static inline functions to serialize/deserialize data of AT DMA

In 1394 OHCI specification, the format of data for AT DMA is different from
the format of asynchronous packet in IEEE 1394 specification, in its spd
and srcBusID fields.

This commit adds some static inline functions to serialize/deserialize the
data of AT DMA.

Link: https://lore.kernel.org/r/20240802003606.109402-2-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
Takashi Sakamoto 2024-08-02 09:36:03 +09:00
parent 3593b38a13
commit 8db9d15571
2 changed files with 149 additions and 0 deletions

View File

@ -40,9 +40,43 @@ static void test_self_id_receive_buffer_deserialization(struct kunit *test)
KUNIT_EXPECT_EQ(test, 0xf38b, timestamp);
}
static void test_at_data_serdes(struct kunit *test)
{
static const __le32 expected[] = {
cpu_to_le32(0x00020e80),
cpu_to_le32(0xffc2ffff),
cpu_to_le32(0xe0000000),
};
__le32 quadlets[] = {0, 0, 0};
bool has_src_bus_id = ohci1394_at_data_get_src_bus_id(expected);
unsigned int speed = ohci1394_at_data_get_speed(expected);
unsigned int tlabel = ohci1394_at_data_get_tlabel(expected);
unsigned int retry = ohci1394_at_data_get_retry(expected);
unsigned int tcode = ohci1394_at_data_get_tcode(expected);
unsigned int destination_id = ohci1394_at_data_get_destination_id(expected);
u64 destination_offset = ohci1394_at_data_get_destination_offset(expected);
KUNIT_EXPECT_FALSE(test, has_src_bus_id);
KUNIT_EXPECT_EQ(test, 0x02, speed);
KUNIT_EXPECT_EQ(test, 0x03, tlabel);
KUNIT_EXPECT_EQ(test, 0x02, retry);
KUNIT_EXPECT_EQ(test, 0x08, tcode);
ohci1394_at_data_set_src_bus_id(quadlets, has_src_bus_id);
ohci1394_at_data_set_speed(quadlets, speed);
ohci1394_at_data_set_tlabel(quadlets, tlabel);
ohci1394_at_data_set_retry(quadlets, retry);
ohci1394_at_data_set_tcode(quadlets, tcode);
ohci1394_at_data_set_destination_id(quadlets, destination_id);
ohci1394_at_data_set_destination_offset(quadlets, destination_offset);
KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected));
}
static struct kunit_case ohci_serdes_test_cases[] = {
KUNIT_CASE(test_self_id_count_register_deserialization),
KUNIT_CASE(test_self_id_receive_buffer_deserialization),
KUNIT_CASE(test_at_data_serdes),
{}
};

View File

@ -154,6 +154,121 @@
#define OHCI1394_evt_flushed 0xf
// Asynchronous Transmit DMA.
//
// The content of first two quadlets of data for AT DMA is different from the header for IEEE 1394
// asynchronous packet.
#define OHCI1394_AT_DATA_Q0_srcBusID_MASK 0x00800000
#define OHCI1394_AT_DATA_Q0_srcBusID_SHIFT 23
#define OHCI1394_AT_DATA_Q0_spd_MASK 0x00070000
#define OHCI1394_AT_DATA_Q0_spd_SHIFT 16
#define OHCI1394_AT_DATA_Q0_tLabel_MASK 0x0000fc00
#define OHCI1394_AT_DATA_Q0_tLabel_SHIFT 10
#define OHCI1394_AT_DATA_Q0_rt_MASK 0x00000300
#define OHCI1394_AT_DATA_Q0_rt_SHIFT 8
#define OHCI1394_AT_DATA_Q0_tCode_MASK 0x000000f0
#define OHCI1394_AT_DATA_Q0_tCode_SHIFT 4
#define OHCI1394_AT_DATA_Q1_destinationId_MASK 0xffff0000
#define OHCI1394_AT_DATA_Q1_destinationId_SHIFT 16
#define OHCI1394_AT_DATA_Q1_destinationOffsetHigh_MASK 0x0000ffff
#define OHCI1394_AT_DATA_Q1_destinationOffsetHigh_SHIFT 0
#define OHCI1394_AT_DATA_Q1_rCode_MASK 0x0000f000
#define OHCI1394_AT_DATA_Q1_rCode_SHIFT 12
static inline bool ohci1394_at_data_get_src_bus_id(const __le32 *data)
{
return !!((data[0] & OHCI1394_AT_DATA_Q0_srcBusID_MASK) >> OHCI1394_AT_DATA_Q0_srcBusID_SHIFT);
}
static inline void ohci1394_at_data_set_src_bus_id(__le32 *data, bool src_bus_id)
{
data[0] &= cpu_to_le32(~OHCI1394_AT_DATA_Q0_srcBusID_MASK);
data[0] |= cpu_to_le32((src_bus_id << OHCI1394_AT_DATA_Q0_srcBusID_SHIFT) & OHCI1394_AT_DATA_Q0_srcBusID_MASK);
}
static inline unsigned int ohci1394_at_data_get_speed(const __le32 *data)
{
return (le32_to_cpu(data[0]) & OHCI1394_AT_DATA_Q0_spd_MASK) >> OHCI1394_AT_DATA_Q0_spd_SHIFT;
}
static inline void ohci1394_at_data_set_speed(__le32 *data, unsigned int scode)
{
data[0] &= cpu_to_le32(~OHCI1394_AT_DATA_Q0_spd_MASK);
data[0] |= cpu_to_le32((scode << OHCI1394_AT_DATA_Q0_spd_SHIFT) & OHCI1394_AT_DATA_Q0_spd_MASK);
}
static inline unsigned int ohci1394_at_data_get_tlabel(const __le32 *data)
{
return (le32_to_cpu(data[0]) & OHCI1394_AT_DATA_Q0_tLabel_MASK) >> OHCI1394_AT_DATA_Q0_tLabel_SHIFT;
}
static inline void ohci1394_at_data_set_tlabel(__le32 *data, unsigned int tlabel)
{
data[0] &= cpu_to_le32(~OHCI1394_AT_DATA_Q0_tLabel_MASK);
data[0] |= cpu_to_le32((tlabel << OHCI1394_AT_DATA_Q0_tLabel_SHIFT) & OHCI1394_AT_DATA_Q0_tLabel_MASK);
}
static inline unsigned int ohci1394_at_data_get_retry(const __le32 *data)
{
return (le32_to_cpu(data[0]) & OHCI1394_AT_DATA_Q0_rt_MASK) >> OHCI1394_AT_DATA_Q0_rt_SHIFT;
}
static inline void ohci1394_at_data_set_retry(__le32 *data, unsigned int retry)
{
data[0] &= cpu_to_le32(~OHCI1394_AT_DATA_Q0_rt_MASK);
data[0] |= cpu_to_le32((retry << OHCI1394_AT_DATA_Q0_rt_SHIFT) & OHCI1394_AT_DATA_Q0_rt_MASK);
}
static inline unsigned int ohci1394_at_data_get_tcode(const __le32 *data)
{
return (le32_to_cpu(data[0]) & OHCI1394_AT_DATA_Q0_tCode_MASK) >> OHCI1394_AT_DATA_Q0_tCode_SHIFT;
}
static inline void ohci1394_at_data_set_tcode(__le32 *data, unsigned int tcode)
{
data[0] &= cpu_to_le32(~OHCI1394_AT_DATA_Q0_tCode_MASK);
data[0] |= cpu_to_le32((tcode << OHCI1394_AT_DATA_Q0_tCode_SHIFT) & OHCI1394_AT_DATA_Q0_tCode_MASK);
}
static inline unsigned int ohci1394_at_data_get_destination_id(const __le32 *data)
{
return (le32_to_cpu(data[1]) & OHCI1394_AT_DATA_Q1_destinationId_MASK) >> OHCI1394_AT_DATA_Q1_destinationId_SHIFT;
}
static inline void ohci1394_at_data_set_destination_id(__le32 *data, unsigned int destination_id)
{
data[1] &= cpu_to_le32(~OHCI1394_AT_DATA_Q1_destinationId_MASK);
data[1] |= cpu_to_le32((destination_id << OHCI1394_AT_DATA_Q1_destinationId_SHIFT) & OHCI1394_AT_DATA_Q1_destinationId_MASK);
}
static inline u64 ohci1394_at_data_get_destination_offset(const __le32 *data)
{
u64 hi = (u64)((le32_to_cpu(data[1]) & OHCI1394_AT_DATA_Q1_destinationOffsetHigh_MASK) >> OHCI1394_AT_DATA_Q1_destinationOffsetHigh_SHIFT);
u64 lo = (u64)le32_to_cpu(data[2]);
return (hi << 32) | lo;
}
static inline void ohci1394_at_data_set_destination_offset(__le32 *data, u64 offset)
{
u32 hi = (u32)(offset >> 32);
u32 lo = (u32)(offset & 0x00000000ffffffff);
data[1] &= cpu_to_le32(~OHCI1394_AT_DATA_Q1_destinationOffsetHigh_MASK);
data[1] |= cpu_to_le32((hi << OHCI1394_AT_DATA_Q1_destinationOffsetHigh_SHIFT) & OHCI1394_AT_DATA_Q1_destinationOffsetHigh_MASK);
data[2] = cpu_to_le32(lo);
}
static inline unsigned int ohci1394_at_data_get_rcode(const __le32 *data)
{
return (le32_to_cpu(data[1]) & OHCI1394_AT_DATA_Q1_rCode_MASK) >> OHCI1394_AT_DATA_Q1_rCode_SHIFT;
}
static inline void ohci1394_at_data_set_rcode(__le32 *data, unsigned int rcode)
{
data[1] &= cpu_to_le32(~OHCI1394_AT_DATA_Q1_rCode_MASK);
data[1] |= cpu_to_le32((rcode << OHCI1394_AT_DATA_Q1_rCode_SHIFT) & OHCI1394_AT_DATA_Q1_rCode_MASK);
}
// Self-ID DMA.
#define OHCI1394_SelfIDCount_selfIDError_MASK 0x80000000