firewire: core: add tracepoints events for asynchronous outbound request
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 29 Apr 2024 04:32:15 +0000 (13:32 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 6 May 2024 02:06:05 +0000 (11:06 +0900)
In a view of core transaction service, the asynchronous outbound request
consists of two stages; initiation and completion. This commit adds a pair
of event for them.

The following example is for asynchronous lock request with compare_swap
code to offset 0x'ffff'f000'0904 in node 0xffc0.

async_request_outbound_initiate: \
  transaction=0xffff955fc6a07a10 generation=5 scode=2 dst_id=0xffc0 \
  tlabel=54 tcode=9 src_id=0xffc1 offset=0xfffff0000904 \
  header={0xffc0d990,0xffc1ffff,0xf0000904,0x80002}
  data={0x80,0x940181}
async_request_outbound_complete: \
  transaction=0xffff955fc6a07a10 generation=5 scode=2 status=2 \
  timestamp=0xd887

Link: https://lore.kernel.org/r/20240429043218.609398-3-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
drivers/firewire/core-transaction.c
include/trace/events/firewire.h

index 3ecb0b945083c6501836e43bc954dce1affdd5ae..c9318024386f8c96ae608db90cbcc88dcc904044 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/byteorder.h>
 
 #include "core.h"
+#include <trace/events/firewire.h>
 #include "packet-header-definitions.h"
 
 #define HEADER_DESTINATION_IS_BROADCAST(header) \
@@ -173,6 +174,9 @@ static void transmit_complete_callback(struct fw_packet *packet,
        struct fw_transaction *t =
            container_of(packet, struct fw_transaction, packet);
 
+       trace_async_request_outbound_complete((uintptr_t)t, packet->generation, packet->speed,
+                                             status, packet->timestamp);
+
        switch (status) {
        case ACK_COMPLETE:
                close_transaction(t, card, RCODE_COMPLETE, packet->timestamp);
@@ -394,6 +398,9 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
 
        spin_unlock_irqrestore(&card->lock, flags);
 
+       trace_async_request_outbound_initiate((uintptr_t)t, generation, speed, t->packet.header, payload,
+                                             tcode_is_read_request(tcode) ? 0 : length / 4);
+
        card->driver->send_request(card, &t->packet);
 }
 EXPORT_SYMBOL_GPL(__fw_send_request);
index bc55eaabf695f4a588d27c4a1d6cff102a87bc4f..063695874cfb11eb99ca99ee9bd650cd90852817 100644 (file)
@@ -7,8 +7,109 @@
 #define _FIREWIRE_TRACE_EVENT_H
 
 #include <linux/tracepoint.h>
+#include <linux/firewire.h>
 
-// Placeholder for future use.
+#include <linux/firewire-constants.h>
+
+#include "../../../drivers/firewire/packet-header-definitions.h"
+
+// The content of TP_printk field is preprocessed, then put to the module binary.
+#define ASYNC_HEADER_GET_DESTINATION(header)   \
+       (((header)[0] & ASYNC_HEADER_Q0_DESTINATION_MASK) >> ASYNC_HEADER_Q0_DESTINATION_SHIFT)
+
+#define ASYNC_HEADER_GET_TLABEL(header)        \
+       (((header)[0] & ASYNC_HEADER_Q0_TLABEL_MASK) >> ASYNC_HEADER_Q0_TLABEL_SHIFT)
+
+#define ASYNC_HEADER_GET_TCODE(header) \
+       (((header)[0] & ASYNC_HEADER_Q0_TCODE_MASK) >> ASYNC_HEADER_Q0_TCODE_SHIFT)
+
+#define ASYNC_HEADER_GET_SOURCE(header)        \
+       (((header)[1] & ASYNC_HEADER_Q1_SOURCE_MASK) >> ASYNC_HEADER_Q1_SOURCE_SHIFT)
+
+#define ASYNC_HEADER_GET_OFFSET(header)        \
+       ((((unsigned long long)((header)[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK)) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) << 32)| \
+       (header)[2]
+
+#define QUADLET_SIZE   4
+
+DECLARE_EVENT_CLASS(async_outbound_initiate_template,
+       TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count),
+       TP_ARGS(transaction, generation, scode, header, data, data_count),
+       TP_STRUCT__entry(
+               __field(u64, transaction)
+               __field(u8, generation)
+               __field(u8, scode)
+               __array(u32, header, ASYNC_HEADER_QUADLET_COUNT)
+               __dynamic_array(u32, data, data_count)
+       ),
+       TP_fast_assign(
+               __entry->transaction = transaction;
+               __entry->generation = generation;
+               __entry->scode = scode;
+               memcpy(__entry->header, header, QUADLET_SIZE * ASYNC_HEADER_QUADLET_COUNT);
+               memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data));
+       ),
+       // This format is for the request subaction.
+       TP_printk(
+               "transaction=0x%llx generation=%u scode=%u dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x offset=0x%012llx header=%s data=%s",
+               __entry->transaction,
+               __entry->generation,
+               __entry->scode,
+               ASYNC_HEADER_GET_DESTINATION(__entry->header),
+               ASYNC_HEADER_GET_TLABEL(__entry->header),
+               ASYNC_HEADER_GET_TCODE(__entry->header),
+               ASYNC_HEADER_GET_SOURCE(__entry->header),
+               ASYNC_HEADER_GET_OFFSET(__entry->header),
+               __print_array(__entry->header, ASYNC_HEADER_QUADLET_COUNT, QUADLET_SIZE),
+               __print_array(__get_dynamic_array(data),
+                             __get_dynamic_array_len(data) / QUADLET_SIZE, QUADLET_SIZE)
+       )
+);
+
+// The value of status is one of ack codes and rcodes specific to Linux FireWire subsystem.
+DECLARE_EVENT_CLASS(async_outbound_complete_template,
+       TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp),
+       TP_ARGS(transaction, generation, scode, status, timestamp),
+       TP_STRUCT__entry(
+               __field(u64, transaction)
+               __field(u8, generation)
+               __field(u8, scode)
+               __field(u8, status)
+               __field(u16, timestamp)
+       ),
+       TP_fast_assign(
+               __entry->transaction = transaction;
+               __entry->generation = generation;
+               __entry->scode = scode;
+               __entry->status = status;
+               __entry->timestamp = timestamp;
+       ),
+       TP_printk(
+               "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x",
+               __entry->transaction,
+               __entry->generation,
+               __entry->scode,
+               __entry->status,
+               __entry->timestamp
+       )
+);
+
+DEFINE_EVENT(async_outbound_initiate_template, async_request_outbound_initiate,
+       TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count),
+       TP_ARGS(transaction, generation, scode, header, data, data_count)
+);
+
+DEFINE_EVENT(async_outbound_complete_template, async_request_outbound_complete,
+       TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp),
+       TP_ARGS(transaction, generation, scode, status, timestamp)
+);
+
+#undef ASYNC_HEADER_GET_DESTINATION
+#undef ASYNC_HEADER_GET_TLABEL
+#undef ASYNC_HEADER_GET_TCODE
+#undef ASYNC_HEADER_GET_SOURCE
+#undef ASYNC_HEADER_GET_OFFSET
+#undef QUADLET_SIZE
 
 #endif // _FIREWIRE_TRACE_EVENT_H