Thread: [PATCH 0/5] firewire: ohci: add tracepoints event for data of Self-ID DMA
Brought to you by:
aeb,
bencollins
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:46
|
Hi, In IEEE 1394, Self identification process is the last step at bus configuration process initiated by reset. In this step, all nodes at the bus broadcast self-ID packet according to the new topology. In 1394 OHCI, the contents of the self-ID packet stream are transmitted to host system by DMA. This is Self-ID DMA, and configured by two registers, signaled by an interrupt, has a format of buffer. Software handles the interrupt, then parse the contents of self-ID packet stream to detect all nodes in the bus. Finally it starts any type of operation in the bus. Both the timing to handle the interrupt and the data of DMA buffer are important as a first step to use the bus. This series of patches is to add a tracepoints event to trace the interrupt and the data of DMA buffer. It would be useful to diagnose some kind of issue related to the self-ID process; e.g. hardware quirks. I also expect it useful to investigate the timing issue between hardIRQ and softIRQ contexts to process the contents of self-ID packets. Takashi Sakamoto (5): firewire: ohci: use common macro to interpret be32 data in le32 buffer firewire: ohci: use static function to handle endian issue on PowerPC platform firewire: ohci: add static inline functions to deserialize for Self-ID DMA operation firewire: ohci: use inline functions to operate data of self-ID DMA firewire: ohci: add tracepoints event for data of Self-ID DMA drivers/firewire/.kunitconfig | 1 + drivers/firewire/Kconfig | 16 ++++++++ drivers/firewire/Makefile | 1 + drivers/firewire/ohci-serdes-test.c | 56 ++++++++++++++++++++++++++ drivers/firewire/ohci.c | 60 ++++++++++++++++++++-------- drivers/firewire/ohci.h | 43 +++++++++++++++++++- include/trace/events/firewire_ohci.h | 54 +++++++++++++++++++++++++ 7 files changed, 213 insertions(+), 18 deletions(-) create mode 100644 drivers/firewire/ohci-serdes-test.c -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:47
|
The 1394 OHCI driver configures the hardware to transfer the data quadlets of packet via DMA after converting it to little endian, therefore the data is typed as __le32. Nevertheless some actual hardware ignores the configuration. In the case, the data in DMA buffer is aligned to big endian (__be32). For the case in big-endian machine, the driver includes the following interpretation from __le32 to u32 (host-endian = __be32): * (__force __u32)(v) In include/linux/byteorder/generic.h, be32_to_cpu() is available. It is expanded to the following expression in 'include/uapi/linux/byteorder/big_endian.h': * (__force __u32)(__be32)(x) This commit replace the ad-hoc endian interpretation with the above. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index df16a8f4ee7f..a2d6d1d1ec2b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -876,7 +876,7 @@ static void ar_sync_buffers_for_cpu(struct ar_context *ctx, #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) #define cond_le32_to_cpu(v) \ - (ohci->quirks & QUIRK_BE_HEADERS ? (__force __u32)(v) : le32_to_cpu(v)) + (ohci->quirks & QUIRK_BE_HEADERS ? be32_to_cpu(v) : le32_to_cpu(v)) #else #define cond_le32_to_cpu(v) le32_to_cpu(v) #endif -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:53
|
It is preferable to use static function instead of functional macro in some points. It checks type of argument, but would be optimized to embedded code instead of function calls. This commit obsoletes the functional macro with the static function. Additionally this commit refactors quirk detection to ease the later work. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index a2d6d1d1ec2b..5b90ca72fa64 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -875,10 +875,25 @@ static void ar_sync_buffers_for_cpu(struct ar_context *ctx, } #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) -#define cond_le32_to_cpu(v) \ - (ohci->quirks & QUIRK_BE_HEADERS ? be32_to_cpu(v) : le32_to_cpu(v)) +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk) +{ + return has_be_header_quirk ? be32_to_cpu(value) : le32_to_cpu(value); +} + +static bool has_be_header_quirk(const struct fw_ohci *ohci) +{ + return !!(ohci->quirks & QUIRK_BE_HEADERS); +} #else -#define cond_le32_to_cpu(v) le32_to_cpu(v) +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk __maybe_unused) +{ + return le32_to_cpu(value); +} + +static bool has_be_header_quirk(const struct fw_ohci *ohci) +{ + return false; +} #endif static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) @@ -888,9 +903,9 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) u32 status, length, tcode; int evt; - p.header[0] = cond_le32_to_cpu(buffer[0]); - p.header[1] = cond_le32_to_cpu(buffer[1]); - p.header[2] = cond_le32_to_cpu(buffer[2]); + p.header[0] = cond_le32_to_cpu(buffer[0], has_be_header_quirk(ohci)); + p.header[1] = cond_le32_to_cpu(buffer[1], has_be_header_quirk(ohci)); + p.header[2] = cond_le32_to_cpu(buffer[2], has_be_header_quirk(ohci)); tcode = async_header_get_tcode(p.header); switch (tcode) { @@ -902,7 +917,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) break; case TCODE_READ_BLOCK_REQUEST : - p.header[3] = cond_le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3], has_be_header_quirk(ohci)); p.header_length = 16; p.payload_length = 0; break; @@ -911,7 +926,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_REQUEST: case TCODE_LOCK_RESPONSE: - p.header[3] = cond_le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3], has_be_header_quirk(ohci)); p.header_length = 16; p.payload_length = async_header_get_data_length(p.header); if (p.payload_length > MAX_ASYNC_PAYLOAD) { @@ -936,7 +951,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) /* FIXME: What to do about evt_* errors? */ length = (p.header_length + p.payload_length + 3) / 4; - status = cond_le32_to_cpu(buffer[length]); + status = cond_le32_to_cpu(buffer[length], has_be_header_quirk(ohci)); evt = (status >> 16) & 0x1f; p.ack = evt - 16; @@ -2030,12 +2045,12 @@ static void bus_reset_work(struct work_struct *work) return; } - generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff; + generation = (cond_le32_to_cpu(ohci->self_id[0], has_be_header_quirk(ohci)) >> 16) & 0xff; rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { - u32 id = cond_le32_to_cpu(ohci->self_id[i]); - u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]); + u32 id = cond_le32_to_cpu(ohci->self_id[i], has_be_header_quirk(ohci)); + u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1], has_be_header_quirk(ohci)); if (id != ~id2) { /* -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:53
|
In 1394 OHCI, the SelfIDComplete event occurs when the hardware has finished transmitting all of the self ID packets received during the bus initialization process to the host memory by DMA. This commit adds a tracepoints event for this event to trace the timing and packet data of Self-ID DMA. It is the part of following tracepoints events helpful to debug some events at bus reset; e.g. the issue addressed at a commit d0b06dc48fb1 ("firewire: core: use long bus reset on gap count error")[1]: * firewire_ohci:irqs * firewire_ohci:self_id_complete * firewire:bus_reset_handle * firewire:self_id_sequence They would be also helpful in the problem about invocation timing of hardIRQ/softIRQ contexts. We can often see this kind of problem with -rt kernel[2]. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d0b06dc48fb1 [2] https://lore.kernel.org/linux-rt-users/YAwPoaUZ1gTD5y+k@hmbx/ Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 11 +++++- include/trace/events/firewire_ohci.h | 54 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c95f26c74e2b..f8d880574c19 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -45,6 +45,8 @@ #include <trace/events/firewire.h> +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk); + #define CREATE_TRACE_POINTS #include <trace/events/firewire_ohci.h> @@ -2208,8 +2210,15 @@ static irqreturn_t irq_handler(int irq, void *data) if (event & OHCI1394_busReset) reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); - if (event & OHCI1394_selfIDComplete) + if (event & OHCI1394_selfIDComplete) { + if (trace_self_id_complete_enabled()) { + u32 reg = reg_read(ohci, OHCI1394_SelfIDCount); + + trace_self_id_complete(ohci->card.index, reg, ohci->self_id, + has_be_header_quirk(ohci)); + } queue_work(selfid_workqueue, &ohci->bus_reset_work); + } if (event & OHCI1394_RQPkt) tasklet_schedule(&ohci->ar_request_ctx.tasklet); diff --git a/include/trace/events/firewire_ohci.h b/include/trace/events/firewire_ohci.h index 483aeeb033af..4f9a7f2577f3 100644 --- a/include/trace/events/firewire_ohci.h +++ b/include/trace/events/firewire_ohci.h @@ -9,6 +9,8 @@ #include <linux/tracepoint.h> +// Some macros and helper functions are defined in 'drivers/firewire/ohci.c'. + TRACE_EVENT(irqs, TP_PROTO(unsigned int card_index, u32 events), TP_ARGS(card_index, events), @@ -42,6 +44,58 @@ TRACE_EVENT(irqs, ) ); +#define QUADLET_SIZE 4 + +#define SELF_ID_COUNT_IS_ERROR(reg) \ + (!!(((reg) & OHCI1394_SelfIDCount_selfIDError_MASK) >> OHCI1394_SelfIDCount_selfIDError_SHIFT)) + +#define SELF_ID_COUNT_GET_GENERATION(reg) \ + (((reg) & OHCI1394_SelfIDCount_selfIDGeneration_MASK) >> OHCI1394_SelfIDCount_selfIDGeneration_SHIFT) + +#define SELF_ID_RECEIVE_Q0_GET_GENERATION(quadlet) \ + (((quadlet) & OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT) + +#define SELF_ID_RECEIVE_Q0_GET_TIMESTAMP(quadlet) \ + (((quadlet) & OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT) + +TRACE_EVENT(self_id_complete, + TP_PROTO(unsigned int card_index, u32 reg, const __le32 *self_id_receive, bool has_be_header_quirk), + TP_ARGS(card_index, reg, self_id_receive, has_be_header_quirk), + TP_STRUCT__entry( + __field(u8, card_index) + __field(u32, reg) + __dynamic_array(u32, self_id_receive, ohci1394_self_id_count_get_size(reg)) + ), + TP_fast_assign( + __entry->card_index = card_index; + __entry->reg = reg; + { + u32 *ptr = __get_dynamic_array(self_id_receive); + int i; + + for (i = 0; i < __get_dynamic_array_len(self_id_receive) / QUADLET_SIZE; ++i) + ptr[i] = cond_le32_to_cpu(self_id_receive[i], has_be_header_quirk); + } + ), + TP_printk( + "card_index=%u is_error=%s generation_at_bus_reset=%u generation_at_completion=%u timestamp=0x%04x packet_data=%s", + __entry->card_index, + SELF_ID_COUNT_IS_ERROR(__entry->reg) ? "true" : "false", + SELF_ID_COUNT_GET_GENERATION(__entry->reg), + SELF_ID_RECEIVE_Q0_GET_GENERATION(((const u32 *)__get_dynamic_array(self_id_receive))[0]), + SELF_ID_RECEIVE_Q0_GET_TIMESTAMP(((const u32 *)__get_dynamic_array(self_id_receive))[0]), + __print_array(((const u32 *)__get_dynamic_array(self_id_receive)) + 1, + (__get_dynamic_array_len(self_id_receive) / QUADLET_SIZE) - 1, QUADLET_SIZE) + ) +); + +#undef SELF_ID_COUNT_IS_ERROR +#undef SELF_ID_COUNT_GET_GENERATION +#undef SELF_ID_RECEIVE_Q0_GET_GENERATION +#undef SELF_ID_RECEIVE_Q0_GET_TIMESTAMP + +#undef QUADLET_SIZE + #endif // _FIREWIRE_OHCI_TRACE_EVENT_H #include <trace/define_trace.h> -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-04 00:07:17
|
Hi, On Wed, Jul 03, 2024 at 07:20:34AM +0900, Takashi Sakamoto wrote: > In 1394 OHCI, the SelfIDComplete event occurs when the hardware has > finished transmitting all of the self ID packets received during the bus > initialization process to the host memory by DMA. > > This commit adds a tracepoints event for this event to trace the timing > and packet data of Self-ID DMA. It is the part of following tracepoints > events helpful to debug some events at bus reset; e.g. the issue addressed > at a commit d0b06dc48fb1 ("firewire: core: use long bus reset on gap count > error")[1]: > > * firewire_ohci:irqs > * firewire_ohci:self_id_complete > * firewire:bus_reset_handle > * firewire:self_id_sequence > > They would be also helpful in the problem about invocation timing of > hardIRQ/softIRQ contexts. We can often see this kind of problem with -rt > kernel[2]. Oops, I misunderstood. The handling of Self-ID DMA buffer is in hardIRQ and process (workqueue) contexts, thus the above issue is not the invocation timing of hardIRQ/softIRQ contexts. Let me correct it at the applied commit comment. > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d0b06dc48fb1 > [2] https://lore.kernel.org/linux-rt-users/YAwPoaUZ1gTD5y+k@hmbx/ > > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/ohci.c | 11 +++++- > include/trace/events/firewire_ohci.h | 54 ++++++++++++++++++++++++++++ > 2 files changed, 64 insertions(+), 1 deletion(-) Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:56
|
The code of 1394 OHCI driver includes hard-coded magic number to operate data of Self-ID DMA. This commit replaces them with the inline functions added/tested in the former commit. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 12 +++++++----- drivers/firewire/ohci.h | 1 - 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5b90ca72fa64..c95f26c74e2b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2003,7 +2003,7 @@ static void bus_reset_work(struct work_struct *work) struct fw_ohci *ohci = container_of(work, struct fw_ohci, bus_reset_work); int self_id_count, generation, new_generation, i, j; - u32 reg; + u32 reg, quadlet; void *free_rom = NULL; dma_addr_t free_rom_bus = 0; bool is_new_root; @@ -2028,7 +2028,7 @@ static void bus_reset_work(struct work_struct *work) ohci->is_root = is_new_root; reg = reg_read(ohci, OHCI1394_SelfIDCount); - if (reg & OHCI1394_SelfIDCount_selfIDError) { + if (ohci1394_self_id_count_is_error(reg)) { ohci_notice(ohci, "self ID receive error\n"); return; } @@ -2038,14 +2038,15 @@ static void bus_reset_work(struct work_struct *work) * the inverted quadlets and a header quadlet, we shift one * bit extra to get the actual number of self IDs. */ - self_id_count = (reg >> 3) & 0xff; + self_id_count = ohci1394_self_id_count_get_size(reg) >> 1; if (self_id_count > 252) { ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg); return; } - generation = (cond_le32_to_cpu(ohci->self_id[0], has_be_header_quirk(ohci)) >> 16) & 0xff; + quadlet = cond_le32_to_cpu(ohci->self_id[0], has_be_header_quirk(ohci)); + generation = ohci1394_self_id_receive_q0_get_generation(quadlet); rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { @@ -2102,7 +2103,8 @@ static void bus_reset_work(struct work_struct *work) * of self IDs. */ - new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; + reg = reg_read(ohci, OHCI1394_SelfIDCount); + new_generation = ohci1394_self_id_count_get_generation(reg); if (new_generation != generation) { ohci_notice(ohci, "new bus reset, discarding self ids\n"); return; diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h index d83fd4731d56..71c2ed84cafb 100644 --- a/drivers/firewire/ohci.h +++ b/drivers/firewire/ohci.h @@ -31,7 +31,6 @@ #define OHCI1394_HCControl_softReset 0x00010000 #define OHCI1394_SelfIDBuffer 0x064 #define OHCI1394_SelfIDCount 0x068 -#define OHCI1394_SelfIDCount_selfIDError 0x80000000 #define OHCI1394_IRMultiChanMaskHiSet 0x070 #define OHCI1394_IRMultiChanMaskHiClear 0x074 #define OHCI1394_IRMultiChanMaskLoSet 0x078 -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-02 22:20:55
|
The SelfI-ID is one type of DMAs defined in 1394 OHCI specification. It is operated by two registers, one interrupt, and has one format of buffer. This commit adds some static inline functions to deserialize the data in the buffer and registers. Some KUnit tests are also added to check their reliability. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/.kunitconfig | 1 + drivers/firewire/Kconfig | 16 +++++++++ drivers/firewire/Makefile | 1 + drivers/firewire/ohci-serdes-test.c | 56 +++++++++++++++++++++++++++++ drivers/firewire/ohci.h | 42 ++++++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 drivers/firewire/ohci-serdes-test.c diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig index 74259204fcdd..21b7e9eef63d 100644 --- a/drivers/firewire/.kunitconfig +++ b/drivers/firewire/.kunitconfig @@ -5,3 +5,4 @@ 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 +CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST=y diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 95e72e0b592b..905c82e26ce7 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -92,6 +92,22 @@ config FIREWIRE_OHCI To compile this driver as a module, say M here: The module will be called firewire-ohci. +config FIREWIRE_KUNIT_OHCI_SERDES_TEST + tristate "KUnit tests for serialization/deserialization of data in buffers/registers" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests to check serialization and deserialization + of data in buffers and registers defined in 1394 OHCI specification. + + 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_SBP2 tristate "Storage devices (SBP-2 protocol)" depends on FIREWIRE && SCSI diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index 21b975e0a387..1ff550e93a8c 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -19,3 +19,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 +obj-$(CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST) += ohci-serdes-test.o diff --git a/drivers/firewire/ohci-serdes-test.c b/drivers/firewire/ohci-serdes-test.c new file mode 100644 index 000000000000..304a09ff528e --- /dev/null +++ b/drivers/firewire/ohci-serdes-test.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// ohci-serdes-test.c - An application of Kunit to check serialization/deserialization of data in +// buffers and registers defined in 1394 OHCI specification. +// +// Copyright (c) 2024 Takashi Sakamoto + +#include <kunit/test.h> + +#include "ohci.h" + + +static void test_self_id_count_register_deserialization(struct kunit *test) +{ + const u32 expected = 0x803d0594; + + bool is_error = ohci1394_self_id_count_is_error(expected); + u8 generation = ohci1394_self_id_count_get_generation(expected); + u32 size = ohci1394_self_id_count_get_size(expected); + + KUNIT_EXPECT_TRUE(test, is_error); + KUNIT_EXPECT_EQ(test, 0x3d, generation); + KUNIT_EXPECT_EQ(test, 0x165, size); +} + +static void test_self_id_receive_buffer_deserialization(struct kunit *test) +{ + const u32 buffer[] = { + 0x0006f38b, + 0x807fcc56, + 0x7f8033a9, + 0x8145cc5e, + 0x7eba33a1, + }; + + u8 generation = ohci1394_self_id_receive_q0_get_generation(buffer[0]); + u16 timestamp = ohci1394_self_id_receive_q0_get_timestamp(buffer[0]); + + KUNIT_EXPECT_EQ(test, 0x6, generation); + KUNIT_EXPECT_EQ(test, 0xf38b, timestamp); +} + +static struct kunit_case ohci_serdes_test_cases[] = { + KUNIT_CASE(test_self_id_count_register_deserialization), + KUNIT_CASE(test_self_id_receive_buffer_deserialization), + {} +}; + +static struct kunit_suite ohci_serdes_test_suite = { + .name = "firewire-ohci-serdes", + .test_cases = ohci_serdes_test_cases, +}; +kunit_test_suite(ohci_serdes_test_suite); + +MODULE_DESCRIPTION("FireWire buffers and registers serialization/deserialization unit test suite"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h index c4d005a9901a..d83fd4731d56 100644 --- a/drivers/firewire/ohci.h +++ b/drivers/firewire/ohci.h @@ -156,4 +156,46 @@ #define OHCI1394_phy_tcode 0xe +// Self-ID DMA. + +#define OHCI1394_SelfIDCount_selfIDError_MASK 0x80000000 +#define OHCI1394_SelfIDCount_selfIDError_SHIFT 31 +#define OHCI1394_SelfIDCount_selfIDGeneration_MASK 0x00ff0000 +#define OHCI1394_SelfIDCount_selfIDGeneration_SHIFT 16 +#define OHCI1394_SelfIDCount_selfIDSize_MASK 0x000007fc +#define OHCI1394_SelfIDCount_selfIDSize_SHIFT 2 + +static inline bool ohci1394_self_id_count_is_error(u32 value) +{ + return !!((value & OHCI1394_SelfIDCount_selfIDError_MASK) >> OHCI1394_SelfIDCount_selfIDError_SHIFT); +} + +static inline u8 ohci1394_self_id_count_get_generation(u32 value) +{ + return (value & OHCI1394_SelfIDCount_selfIDGeneration_MASK) >> OHCI1394_SelfIDCount_selfIDGeneration_SHIFT; +} + +// In 1394 OHCI specification, the maximum size of self ID stream is 504 quadlets +// (= 63 devices * 4 self ID packets * 2 quadlets). The selfIDSize field accommodates it and its +// additional first quadlet, since the field is 9 bits (0x1ff = 511). +static inline u32 ohci1394_self_id_count_get_size(u32 value) +{ + return (value & OHCI1394_SelfIDCount_selfIDSize_MASK) >> OHCI1394_SelfIDCount_selfIDSize_SHIFT; +} + +#define OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK 0x00ff0000 +#define OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT 16 +#define OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK 0x0000ffff +#define OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT 0 + +static inline u8 ohci1394_self_id_receive_q0_get_generation(u32 quadlet0) +{ + return (quadlet0 & OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT; +} + +static inline u16 ohci1394_self_id_receive_q0_get_timestamp(u32 quadlet0) +{ + return (quadlet0 & OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT; +} + #endif /* _FIREWIRE_OHCI_H */ -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-07-03 23:30:59
|
On Wed, Jul 03, 2024 at 07:20:29AM +0900, Takashi Sakamoto wrote: > Hi, > > In IEEE 1394, Self identification process is the last step at > bus configuration process initiated by reset. In this step, all nodes at > the bus broadcast self-ID packet according to the new topology. In 1394 > OHCI, the contents of the self-ID packet stream are transmitted to host > system by DMA. This is Self-ID DMA, and configured by two registers, > signaled by an interrupt, has a format of buffer. > > Software handles the interrupt, then parse the contents of self-ID packet > stream to detect all nodes in the bus. Finally it starts any type of > operation in the bus. Both the timing to handle the interrupt and the > data of DMA buffer are important as a first step to use the bus. > > This series of patches is to add a tracepoints event to trace the > interrupt and the data of DMA buffer. It would be useful to diagnose > some kind of issue related to the self-ID process; e.g. hardware quirks. > I also expect it useful to investigate the timing issue between hardIRQ > and softIRQ contexts to process the contents of self-ID packets. > > Takashi Sakamoto (5): > firewire: ohci: use common macro to interpret be32 data in le32 buffer > firewire: ohci: use static function to handle endian issue on PowerPC > platform > firewire: ohci: add static inline functions to deserialize for Self-ID > DMA operation > firewire: ohci: use inline functions to operate data of self-ID DMA > firewire: ohci: add tracepoints event for data of Self-ID DMA > > drivers/firewire/.kunitconfig | 1 + > drivers/firewire/Kconfig | 16 ++++++++ > drivers/firewire/Makefile | 1 + > drivers/firewire/ohci-serdes-test.c | 56 ++++++++++++++++++++++++++ > drivers/firewire/ohci.c | 60 ++++++++++++++++++++-------- > drivers/firewire/ohci.h | 43 +++++++++++++++++++- > include/trace/events/firewire_ohci.h | 54 +++++++++++++++++++++++++ > 7 files changed, 213 insertions(+), 18 deletions(-) > create mode 100644 drivers/firewire/ohci-serdes-test.c Applied to for-next branch. Regards Takashi Sakamoto |