linux1394-devel Mailing List for IEEE 1394 for Linux (Page 9)
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
(39) |
Apr
(154) |
May
(172) |
Jun
(237) |
Jul
(127) |
Aug
(135) |
Sep
(193) |
Oct
(175) |
Nov
(173) |
Dec
(148) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(161) |
Feb
(225) |
Mar
(193) |
Apr
(158) |
May
(179) |
Jun
(292) |
Jul
(146) |
Aug
(134) |
Sep
(185) |
Oct
(190) |
Nov
(149) |
Dec
(161) |
2002 |
Jan
(186) |
Feb
(236) |
Mar
(254) |
Apr
(207) |
May
(189) |
Jun
(182) |
Jul
(202) |
Aug
(155) |
Sep
(149) |
Oct
(449) |
Nov
(191) |
Dec
(108) |
2003 |
Jan
(174) |
Feb
(242) |
Mar
(243) |
Apr
(255) |
May
(202) |
Jun
(290) |
Jul
(237) |
Aug
(178) |
Sep
(101) |
Oct
(153) |
Nov
(144) |
Dec
(95) |
2004 |
Jan
(162) |
Feb
(278) |
Mar
(282) |
Apr
(152) |
May
(127) |
Jun
(138) |
Jul
(94) |
Aug
(63) |
Sep
(64) |
Oct
(150) |
Nov
(102) |
Dec
(197) |
2005 |
Jan
(102) |
Feb
(172) |
Mar
(89) |
Apr
(158) |
May
(139) |
Jun
(160) |
Jul
(288) |
Aug
(89) |
Sep
(201) |
Oct
(92) |
Nov
(190) |
Dec
(139) |
2006 |
Jan
(121) |
Feb
(204) |
Mar
(133) |
Apr
(134) |
May
(91) |
Jun
(226) |
Jul
(122) |
Aug
(101) |
Sep
(144) |
Oct
(141) |
Nov
|
Dec
|
2023 |
Jan
(19) |
Feb
(1) |
Mar
(5) |
Apr
(5) |
May
(33) |
Jun
(17) |
Jul
|
Aug
|
Sep
(3) |
Oct
(1) |
Nov
(5) |
Dec
(40) |
2024 |
Jan
(26) |
Feb
(14) |
Mar
(26) |
Apr
(46) |
May
(17) |
Jun
(47) |
Jul
(23) |
Aug
(72) |
Sep
(33) |
Oct
|
Nov
|
Dec
|
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:41
|
In a view of core transaction service, the asynchronous outbound response consists of two stages; initiation and completion. This commit adds a pair of events for the asynchronous outbound response. The following example is for asynchronous write quadlet request as IEC 61883-1 FCP response to node 0xffc1. async_response_outbound_initiate: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 dst_id=0xffc1 \ tlabel=25 tcode=2 src_id=0xffc0 rcode=0 \ header={0xffc16420,0xffc00000,0x0,0x0} data={} async_response_outbound_complete: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 status=1 \ timestamp=0x0000 Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 23 ++++++++++++++++------- include/trace/events/firewire.h | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 8c13f996a938..0e49ebf52500 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -668,6 +668,9 @@ static void free_response_callback(struct fw_packet *packet, { struct fw_request *request = container_of(packet, struct fw_request, response); + trace_async_response_outbound_complete((uintptr_t)request, packet->generation, + packet->speed, status, packet->timestamp); + // Decrease the reference count since not at in-flight. fw_request_put(request); @@ -850,6 +853,9 @@ static struct fw_request *allocate_request(struct fw_card *card, void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) { + u32 *data = NULL; + unsigned int data_length = 0; + /* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || HEADER_DESTINATION_IS_BROADCAST(request->request_header)) { @@ -857,17 +863,20 @@ void fw_send_response(struct fw_card *card, return; } - if (rcode == RCODE_COMPLETE) - fw_fill_response(&request->response, request->request_header, - rcode, request->data, - fw_get_response_length(request)); - else - fw_fill_response(&request->response, request->request_header, - rcode, NULL, 0); + if (rcode == RCODE_COMPLETE) { + data = request->data; + data_length = fw_get_response_length(request); + } + + fw_fill_response(&request->response, request->request_header, rcode, data, data_length); // Increase the reference count so that the object is kept during in-flight. fw_request_get(request); + trace_async_response_outbound_initiate((uintptr_t)request, request->response.generation, + request->response.speed, request->response.header, + data, data ? data_length / 4 : 0); + card->driver->send_response(card, &request->response); } EXPORT_SYMBOL(fw_send_response); diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index a30cebed119a..d4688e341837 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -174,6 +174,30 @@ DEFINE_EVENT_PRINT(async_inbound_template, async_request_inbound, ) ); +DEFINE_EVENT_PRINT(async_outbound_initiate_template, async_response_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), + TP_printk( + "transaction=0x%llx generation=%u scode=%u dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x rcode=%u 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_RCODE(__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) + ) +); + +DEFINE_EVENT(async_outbound_complete_template, async_response_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 -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:40
|
This commit adds an event for asynchronous inbound request. The following example is for asynchronous block write request as IEC 61883-1 FCP request from node 0xffc1. async_request_inbound: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 status=2 \ timestamp=0x00b3 dst_id=0xffc0 tlabel=19 tcode=1 src_id=0xffc1 \ offset=0xfffff0000d00 header={0xffc04d10,0xffc1ffff,0xf0000d00,0x80000} \ data={0x19ff08,0xffff0090} Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 8 +++++++- include/trace/events/firewire.h | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 56510d305564..8c13f996a938 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -973,11 +973,13 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) { struct fw_request *request; unsigned long long offset; + unsigned int tcode; if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (tcode_is_link_internal(async_header_get_tcode(p->header))) { + tcode = async_header_get_tcode(p->header); + if (tcode_is_link_internal(tcode)) { fw_cdev_handle_phy_packet(card, p); return; } @@ -988,6 +990,10 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) return; } + trace_async_request_inbound((uintptr_t)request, p->generation, p->speed, p->ack, + p->timestamp, p->header, request->data, + tcode_is_read_request(tcode) ? 0 : request->length / 4); + offset = async_header_get_offset(p->header); if (!is_in_fcp_region(offset, request->length)) diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 2d5f6b196a22..a30cebed119a 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -153,6 +153,27 @@ DEFINE_EVENT(async_inbound_template, async_response_inbound, TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count) ); +DEFINE_EVENT_PRINT(async_inbound_template, async_request_inbound, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count), + TP_printk( + "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x 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, + __entry->status, + __entry->timestamp, + 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) + ) +); + #undef ASYNC_HEADER_GET_DESTINATION #undef ASYNC_HEADER_GET_TLABEL #undef ASYNC_HEADER_GET_TCODE -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:39
|
In the transaction of IEEE 1394, the node to receive the asynchronous request transfers any response packet to the requester except for the unified transaction. This commit adds an event for the inbound packet. Note that the code to decode the packet header is moved, against the note about the sanity check. The following example is for asynchronous lock response with compare_and_swap code. async_response_inbound: \ transaction=0xffff955fc6a07a10 generation=5 scode=2 status=1 \ timestamp=0x0089 dst_id=0xffc1 tlabel=54 tcode=11 src_id=0xffc0 \ rcode=0 header={0xffc1d9b0,0xffc00000,0x0,0x40002} data={0x50800080} Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 55 +++++++++++++++-------------- include/trace/events/firewire.h | 50 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index c9318024386f..56510d305564 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1011,32 +1011,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) source = async_header_get_source(p->header); rcode = async_header_get_rcode(p->header); - spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(iter, &card->transaction_list, link) { - if (iter->node_id == source && iter->tlabel == tlabel) { - if (!try_cancel_split_timeout(iter)) { - spin_unlock_irqrestore(&card->lock, flags); - goto timed_out; - } - list_del_init(&iter->link); - card->tlabel_mask &= ~(1ULL << iter->tlabel); - t = iter; - break; - } - } - spin_unlock_irqrestore(&card->lock, flags); - - if (!t) { - timed_out: - fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", - source, tlabel); - return; - } - - /* - * FIXME: sanity check packet, is length correct, does tcodes - * and addresses match. - */ + // FIXME: sanity check packet, is length correct, does tcodes + // and addresses match to the transaction request queried later. + // + // For the tracepoints event, let us decode the header here against the concern. switch (tcode) { case TCODE_READ_QUADLET_RESPONSE: @@ -1062,6 +1040,31 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(iter, &card->transaction_list, link) { + if (iter->node_id == source && iter->tlabel == tlabel) { + if (!try_cancel_split_timeout(iter)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } + list_del_init(&iter->link); + card->tlabel_mask &= ~(1ULL << iter->tlabel); + t = iter; + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + trace_async_response_inbound((uintptr_t)t, p->generation, p->speed, p->ack, p->timestamp, + p->header, data, data_length / 4); + + if (!t) { + timed_out: + fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", + source, tlabel); + return; + } + /* * The response handler may be executed while the request handler * is still pending. Cancel the request handler. diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 063695874cfb..2d5f6b196a22 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -30,6 +30,9 @@ ((((unsigned long long)((header)[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK)) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) << 32)| \ (header)[2] +#define ASYNC_HEADER_GET_RCODE(header) \ + (((header)[1] & ASYNC_HEADER_Q1_RCODE_MASK) >> ASYNC_HEADER_Q1_RCODE_SHIFT) + #define QUADLET_SIZE 4 DECLARE_EVENT_CLASS(async_outbound_initiate_template, @@ -94,6 +97,47 @@ DECLARE_EVENT_CLASS(async_outbound_complete_template, ) ); +// The value of status is one of ack codes and rcodes specific to Linux FireWire subsystem. +DECLARE_EVENT_CLASS(async_inbound_template, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, generation) + __field(u8, scode) + __field(u8, status) + __field(u8, timestamp) + __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; + __entry->status = status; + __entry->timestamp = timestamp; + 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 response subaction. + TP_printk( + "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x rcode=%u header=%s data=%s", + __entry->transaction, + __entry->generation, + __entry->scode, + __entry->status, + __entry->timestamp, + 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_RCODE(__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) + ) +); + 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) @@ -104,11 +148,17 @@ DEFINE_EVENT(async_outbound_complete_template, async_request_outbound_complete, TP_ARGS(transaction, generation, scode, status, timestamp) ); +DEFINE_EVENT(async_inbound_template, async_response_inbound, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count) +); + #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 ASYNC_HEADER_GET_RCODE #undef QUADLET_SIZE #endif // _FIREWIRE_TRACE_EVENT_H -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:34
|
Hi, The series of changes in this patchse is to revise the previous RFC: https://lore.kernel.org/lkml/202...@sa.../ In a view of IEEE 1394 bus, the main function of kernel core is to provide transaction service to the bus. It is helpful to have some mechanisms to trace any action of the service. This series of changes adds some tracepoints events for the purpose. It adds the following tracepoints events via 'firewire' subsystem: * For outbound transactions (e.g. initiated by user process) * async_request_outbound_initiate * async_request_outbound_complete * async_response_inbound * For inbound transactions (e.g. initiated by the other nodes in the bus) * async_request_inbound * async_response_outbound_initiate * async_response_outbound_complete When probing these tracepoints events, the content of 'struct fw_packet' passed between the core function and 1394 OHCI driver is recorded with the fields of header and packet data. For example of the outbound split transaction: async_request_outbound_initiate: \ transaction=0xffff955fc6a07b30 generation=5 scode=2 dst_id=0xffc0 \ tlabel=18 tcode=9 src_id=0xffc1 offset=0xfffff0000984 \ header={0xffc04990,0xffc1ffff,0xf0000984,0x80002} data={0x81,0x80} async_request_outbound_complete: \ transaction=0xffff955fc6a07b30 generation=5 scode=2 status=2 \ timestamp=0xeabf async_response_inbound: \ transaction=0xffff955fc6a07b30 generation=5 scode=2 status=1 \ timestamp=0xeac2 dst_id=0xffc1 tlabel=18 tcode=11 src_id=0xffc0 \ rcode=0 header={0xffc149b0,0xffc00000,0x0,0x40002} data={0x81} Takashi Sakamoto (5): firewire: core: add support for Linux kernel tracepoints firewire: core: add tracepoints events for asynchronous outbound request firewire: core: add tracepoints event for asynchronous inbound response firewire: core: add tracepoint event for asynchronous inbound request firewire: core: add tracepoints events for asynchronous outbound response drivers/firewire/Makefile | 2 +- drivers/firewire/core-trace.c | 5 + drivers/firewire/core-transaction.c | 93 +++++++----- include/trace/events/firewire.h | 211 ++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 35 deletions(-) create mode 100644 drivers/firewire/core-trace.c create mode 100644 include/trace/events/firewire.h -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:33
|
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 Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 7 ++ include/trace/events/firewire.h | 103 +++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 3ecb0b945083..c9318024386f 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -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); diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index bc55eaabf695..063695874cfb 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -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 -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 04:32:31
|
The Linux Kernel Tracepoints framework is enough useful to trace packet data inbound to and outbound from core. This commit adds firewire subsystem to use the framework. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/Makefile | 2 +- drivers/firewire/core-trace.c | 5 +++++ include/trace/events/firewire.h | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 drivers/firewire/core-trace.c create mode 100644 include/trace/events/firewire.h diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index bbde29a0fba6..013e1f2641bd 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -3,7 +3,7 @@ # Makefile for the Linux IEEE 1394 implementation # -firewire-core-y += core-card.o core-cdev.o core-device.o \ +firewire-core-y += core-trace.o core-card.o core-cdev.o core-device.o \ core-iso.o core-topology.o core-transaction.o firewire-ohci-y += ohci.o firewire-sbp2-y += sbp2.o diff --git a/drivers/firewire/core-trace.c b/drivers/firewire/core-trace.c new file mode 100644 index 000000000000..96cbd9d384dc --- /dev/null +++ b/drivers/firewire/core-trace.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define CREATE_TRACE_POINTS +#include <trace/events/firewire.h> diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h new file mode 100644 index 000000000000..bc55eaabf695 --- /dev/null +++ b/include/trace/events/firewire.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define TRACE_SYSTEM firewire + +#if !defined(_FIREWIRE_TRACE_EVENT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _FIREWIRE_TRACE_EVENT_H + +#include <linux/tracepoint.h> + +// Placeholder for future use. + +#endif // _FIREWIRE_TRACE_EVENT_H + +#include <trace/define_trace.h> -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-29 01:26:33
|
P.S. the content of configuration ROM can be dumped by config-rom-pretty-printer in linux-firewire-utils. The node of your device has: guid: 0x22e0001800000 vendor_id: 0x00022e model_id: 0x800006 It includes one unit: specifier id: 0x00022e version: 0x800006 model_id: 0x00022e It is odd that the node and unit has the different values for their model_id fields. I think Tascam programmer applied the wrong configuration to them when developing dice firmware Note that ALSA dice driver is bound to the unit, thus both vendor_id and model_id should be 0x00022e. $ config-rom-pretty-printer < audio_and_music/dice/tascam-iffw2.img ROM header and bus information block ----------------------------------------------------------------- 1024 04042ec6 bus_info_length 4, crc_length 4, crc 11974 1028 31333934 bus_name "1394" 1032 e0ff8112 irmc 1, cmc 1, isc 1, bmc 0, pmc 0, cyc_clk_acc 255, max_rec 8 (512), max_rom 1, gen 1, spd 2 (S400) 1036 00022e00 company_id 00022e | 1040 01800000 device_id 0025165824 | EUI-64 0613527513464832 root directory ----------------------------------------------------------------- 1044 0006f261 directory_length 6, crc 62049 1048 0300022e vendor 1052 8100000a --> descriptor leaf at 1092 1056 17800006 model 1060 8100000d --> descriptor leaf at 1112 1064 0c0087c0 node capabilities: per IEEE 1394 1068 d1000001 --> unit directory at 1072 unit directory at 1072 ----------------------------------------------------------------- 1072 000411c4 directory_length 4, crc 4548 1076 1200022e specifier id 1080 13800006 version 1084 1700022e model 1088 8100000d --> descriptor leaf at 1140 descriptor leaf at 1092 ----------------------------------------------------------------- 1092 0004a79e leaf_length 4, crc 42910 1096 00000000 textual descriptor 1100 00000000 minimal ASCII 1104 54415343 "TASC" 1108 414d0000 "AM" descriptor leaf at 1112 ----------------------------------------------------------------- 1112 00066bda leaf_length 6, crc 27610 1116 00000000 textual descriptor 1120 00000000 minimal ASCII 1124 49462d46 "IF-F" 1128 572f444d "W/DM" 1132 206d6b49 " mkI" 1136 49000000 "I" descriptor leaf at 1140 ----------------------------------------------------------------- 1140 00066bda leaf_length 6, crc 27610 1144 00000000 textual descriptor 1148 00000000 minimal ASCII 1152 49462d46 "IF-F" 1156 572f444d "W/DM" 1160 206d6b49 " mkI" 1164 49000000 "I" Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-04-29 01:06:17
|
Hi, On Sun, Apr 28, 2024 at 05:22:29PM +0200, Joerg M. Sigle wrote: > > 1. The image of configuration ROM > > ... > Please see the attachment. Okay. I made a PR to systemd project according to the content of image. https://github.com/systemd/systemd/pull/32542 When you put the entry in your system following to 'man hwdb' (e.g. under /etc directory), restart udev daemon, and logout/login, the access permission to '/dev/fw1' is configured to what we expect automatically, independent of the installation of libffado2 rule. (requiring systemd v249 or later). If you agree with CC0 for the copyright of image, I would like to push it to my collection, Just for safe, Do you mind it? https://github.com/takaswie/am-config-roms/ > > 2. General section information in Wavefront DiceII ASIC > > ... > > $ firewire-request /dev/fw1 read 0xffffe0000000 0x28 > > root@think3 So Apr 28 14:56:23 /usr/src/ffado/linux-firewire-utils-0.5.1 > # firewire-request /dev/fw1 read 0xffffe0000000 0x28 > result: 000: 00 00 00 0a 00 00 00 82 00 00 00 8c 00 00 00 8e ................ > result: 010: 00 00 01 1a 00 00 01 1a 00 00 00 00 00 00 00 00 ................ > result: 020: 00 00 00 00 00 00 00 00 ........ Good. The general section consists of the following information: 000: 00 00 00 0a 00 00 00 82: global section offset 0x28, size 0x208 008: 00 00 00 8c 00 00 00 8e: tx stream section offset 0x230, size 0x238 010: 00 00 01 1a 00 00 01 1a: rx stream section offset 0x468, size 0x468 018: 00 00 00 00 00 00 00 00: extended status of sync is not supported. 020: 00 00 00 00 00 00 00 00: reserved fields. You can retrieve the content of each section by read access to the offset plus 0xffffe0000000 and the size. For example of tx stream section: $ firewire-request /dev/fw1 read 0xffffe0000230 0x238 The tx/rx sections tell software about the stream formats and configurations. Well, my concern is the spontaneous change of these two sections by mixer settings of tx/rx channels. As I mentioned, your device has two modes (16 channels and 32 channels) per each, at least according to the manual. The description in the manual reminds me that these two sections have a quirk which I do not expect for Dice devices. Thanks Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:19
|
The packet for Asynchronous Streaming Packet includes the same header fields as the isochronous packet has. It is helpful to have some helper functions to serialize/deserialize them. This commit adds such helper functions with their test. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/packet-header-definitions.h | 66 ++++++++++++++++++++ drivers/firewire/packet-serdes-test.c | 44 +++++++++++++ 2 files changed, 110 insertions(+) diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h index 83e550427706..ab9d0fa790d4 100644 --- a/drivers/firewire/packet-header-definitions.h +++ b/drivers/firewire/packet-header-definitions.h @@ -165,4 +165,70 @@ static inline void async_header_set_extended_tcode(u32 header[ASYNC_HEADER_QUADL header[3] |= (((u32)extended_tcode) << ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT) & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; } +#define ISOC_HEADER_DATA_LENGTH_SHIFT 16 +#define ISOC_HEADER_DATA_LENGTH_MASK 0xffff0000 +#define ISOC_HEADER_TAG_SHIFT 14 +#define ISOC_HEADER_TAG_MASK 0x0000c000 +#define ISOC_HEADER_CHANNEL_SHIFT 8 +#define ISOC_HEADER_CHANNEL_MASK 0x00003f00 +#define ISOC_HEADER_TCODE_SHIFT 4 +#define ISOC_HEADER_TCODE_MASK 0x000000f0 +#define ISOC_HEADER_SY_SHIFT 0 +#define ISOC_HEADER_SY_MASK 0x0000000f + +static inline unsigned int isoc_header_get_data_length(u32 header) +{ + return (header & ISOC_HEADER_DATA_LENGTH_MASK) >> ISOC_HEADER_DATA_LENGTH_SHIFT; +} + +static inline unsigned int isoc_header_get_tag(u32 header) +{ + return (header & ISOC_HEADER_TAG_MASK) >> ISOC_HEADER_TAG_SHIFT; +} + +static inline unsigned int isoc_header_get_channel(u32 header) +{ + return (header & ISOC_HEADER_CHANNEL_MASK) >> ISOC_HEADER_CHANNEL_SHIFT; +} + +static inline unsigned int isoc_header_get_tcode(u32 header) +{ + return (header & ISOC_HEADER_TCODE_MASK) >> ISOC_HEADER_TCODE_SHIFT; +} + +static inline unsigned int isoc_header_get_sy(u32 header) +{ + return (header & ISOC_HEADER_SY_MASK) >> ISOC_HEADER_SY_SHIFT; +} + +static inline void isoc_header_set_data_length(u32 *header, unsigned int data_length) +{ + *header &= ~ISOC_HEADER_DATA_LENGTH_MASK; + *header |= (((u32)data_length) << ISOC_HEADER_DATA_LENGTH_SHIFT) & ISOC_HEADER_DATA_LENGTH_MASK; +} + +static inline void isoc_header_set_tag(u32 *header, unsigned int tag) +{ + *header &= ~ISOC_HEADER_TAG_MASK; + *header |= (((u32)tag) << ISOC_HEADER_TAG_SHIFT) & ISOC_HEADER_TAG_MASK; +} + +static inline void isoc_header_set_channel(u32 *header, unsigned int channel) +{ + *header &= ~ISOC_HEADER_CHANNEL_MASK; + *header |= (((u32)channel) << ISOC_HEADER_CHANNEL_SHIFT) & ISOC_HEADER_CHANNEL_MASK; +} + +static inline void isoc_header_set_tcode(u32 *header, unsigned int tcode) +{ + *header &= ~ISOC_HEADER_TCODE_MASK; + *header |= (((u32)tcode) << ISOC_HEADER_TCODE_SHIFT) & ISOC_HEADER_TCODE_MASK; +} + +static inline void isoc_header_set_sy(u32 *header, unsigned int sy) +{ + *header &= ~ISOC_HEADER_SY_MASK; + *header |= (((u32)sy) << ISOC_HEADER_SY_SHIFT) & ISOC_HEADER_SY_MASK; +} + #endif // _FIREWIRE_PACKET_HEADER_DEFINITIONS_H diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c index 299e9f908463..f93c966e794d 100644 --- a/drivers/firewire/packet-serdes-test.c +++ b/drivers/firewire/packet-serdes-test.c @@ -167,6 +167,26 @@ static void deserialize_async_header_block_response(const u32 header[ASYNC_HEADE *extended_tcode = async_header_get_extended_tcode(header); } +static void serialize_isoc_header(u32 *header, unsigned int data_length, unsigned int tag, + unsigned int channel, unsigned int tcode, unsigned int sy) +{ + isoc_header_set_data_length(header, data_length); + isoc_header_set_tag(header, tag); + isoc_header_set_channel(header, channel); + isoc_header_set_tcode(header, tcode); + isoc_header_set_sy(header, sy); +} + +static void deserialize_isoc_header(u32 header, unsigned int *data_length, unsigned int *tag, + unsigned int *channel, unsigned int *tcode, unsigned int *sy) +{ + *data_length = isoc_header_get_data_length(header); + *tag = isoc_header_get_tag(header); + *channel = isoc_header_get_channel(header); + *tcode = isoc_header_get_tcode(header); + *sy = isoc_header_get_sy(header); +} + static void test_async_header_write_quadlet_request(struct kunit *test) { static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { @@ -515,6 +535,29 @@ static void test_async_header_lock_response(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); } +static void test_isoc_header(struct kunit *test) +{ + const u32 expected = 0x00d08dec; + u32 header = 0; + + unsigned int data_length; + unsigned int tag; + unsigned int channel; + unsigned int tcode; + unsigned int sy; + + deserialize_isoc_header(expected, &data_length, &tag, &channel, &tcode, &sy); + + KUNIT_EXPECT_EQ(test, 0xd0, data_length); + KUNIT_EXPECT_EQ(test, 0x02, tag); + KUNIT_EXPECT_EQ(test, 0x0d, channel); + KUNIT_EXPECT_EQ(test, 0x0e, tcode); + KUNIT_EXPECT_EQ(test, 0x0c, sy); + + serialize_isoc_header(&header, data_length, tag, channel, tcode, sy); + + KUNIT_EXPECT_EQ(test, header, expected); +} static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_write_quadlet_request), @@ -526,6 +569,7 @@ static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_read_block_response), KUNIT_CASE(test_async_header_lock_request), KUNIT_CASE(test_async_header_lock_response), + KUNIT_CASE(test_isoc_header), {} }; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:16
|
This commit replaces the local macros with the common inline functions to serialize the packer header for Asynchronous Streaming Packet. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 45ea15342ab8..3ecb0b945083 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -31,9 +31,6 @@ #include "core.h" #include "packet-header-definitions.h" -#define HEADER_TCODE(tcode) ((tcode) << 4) -#define HEADER_DATA_LENGTH(length) ((length) << 16) - #define HEADER_DESTINATION_IS_BROADCAST(header) \ ((async_header_get_destination(header) & 0x3f) == 0x3f) @@ -215,10 +212,11 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, int ext_tcode; if (tcode == TCODE_STREAM_DATA) { - packet->header[0] = - HEADER_DATA_LENGTH(length) | - destination_id | - HEADER_TCODE(TCODE_STREAM_DATA); + // The value of destination_id argument should include tag, channel, and sy fields + // as isochronous packet header has. + packet->header[0] = destination_id; + isoc_header_set_data_length(packet->header, length); + isoc_header_set_tcode(packet->header, TCODE_STREAM_DATA); packet->header_length = 4; packet->payload = payload; packet->payload_length = length; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:15
|
This commit replaces the hard-coded values with the common inline functions to serialize and deserialize the header of asynchronous packet. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5f702f56ac7b..be8ede492ead 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -517,14 +517,14 @@ static const char *tcodes[] = { static void log_ar_at_event(struct fw_ohci *ohci, char dir, int speed, u32 *header, int evt) { - int tcode = header[0] >> 4 & 0xf; + int tcode = async_header_get_tcode(header); char specific[12]; if (likely(!(param_debug & OHCI_PARAM_DEBUG_AT_AR))) return; if (unlikely(evt >= ARRAY_SIZE(evts))) - evt = 0x1f; + evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n", @@ -539,7 +539,8 @@ static void log_ar_at_event(struct fw_ohci *ohci, break; case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: snprintf(specific, sizeof(specific), " %x,%x", - header[3] >> 16, header[3] & 0xffff); + async_header_get_data_length(header), + async_header_get_extended_tcode(header)); break; default: specific[0] = '\0'; @@ -556,17 +557,17 @@ static void log_ar_at_event(struct fw_ohci *ohci, break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: ohci_notice(ohci, - "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %04x%08x%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], header[1] & 0xffff, header[2], specific); + "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %012llx%s\n", + dir, speed, async_header_get_tlabel(header), + async_header_get_source(header), async_header_get_destination(header), + evts[evt], tcodes[tcode], async_header_get_offset(header), specific); break; default: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], specific); + dir, speed, async_header_get_tlabel(header), + async_header_get_source(header), async_header_get_destination(header), + evts[evt], tcodes[tcode], specific); } } @@ -854,7 +855,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.header[1] = cond_le32_to_cpu(buffer[1]); p.header[2] = cond_le32_to_cpu(buffer[2]); - tcode = (p.header[0] >> 4) & 0x0f; + tcode = async_header_get_tcode(p.header); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_READ_QUADLET_RESPONSE: @@ -875,7 +876,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) case TCODE_LOCK_RESPONSE: p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; - p.payload_length = p.header[3] >> 16; + p.payload_length = async_header_get_data_length(p.header); if (p.payload_length > MAX_ASYNC_PAYLOAD) { ar_context_abort(ctx, "invalid packet length"); return NULL; @@ -912,8 +913,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) * Several controllers, notably from NEC and VIA, forget to * write ack_complete status at PHY packet reception. */ - if (evt == OHCI1394_evt_no_status && - (p.header[0] & 0xff) == (OHCI1394_phy_tcode << 4)) + if (evt == OHCI1394_evt_no_status && tcode == OHCI1394_phy_tcode) p.ack = ACK_COMPLETE; /* @@ -1354,7 +1354,7 @@ static int at_context_queue_packet(struct context *ctx, * accordingly. */ - tcode = (packet->header[0] >> 4) & 0x0f; + tcode = async_header_get_tcode(packet->header); header = (__le32 *) &d[1]; switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:12
|
This commit declares the helper functions to check tcode to obsolete the functional macros. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 4 ++-- drivers/firewire/core.h | 21 ++++++++++++++------- drivers/firewire/ohci.c | 6 +++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index a113f801cf33..45ea15342ab8 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -972,7 +972,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (TCODE_IS_LINK_INTERNAL(async_header_get_tcode(p->header))) { + if (tcode_is_link_internal(async_header_get_tcode(p->header))) { fw_cdev_handle_phy_packet(card, p); return; } @@ -1109,7 +1109,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request { int start; - if (!TCODE_IS_READ_REQUEST(tcode)) { + if (!tcode_is_read_request(tcode)) { fw_send_response(card, request, RCODE_TYPE_ERROR); return; } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index ff96e5456b5d..5097c7a270b4 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -225,13 +225,20 @@ static inline bool is_next_generation(int new_generation, int old_generation) #define TCODE_LINK_INTERNAL 0xe -#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) -#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) -#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == TCODE_LINK_INTERNAL) -#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) -#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) -#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) -#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0) +static inline bool tcode_is_read_request(unsigned int tcode) +{ + return (tcode & ~1u) == 4u; +} + +static inline bool tcode_is_block_packet(unsigned int tcode) +{ + return (tcode & 1u) != 0u; +} + +static inline bool tcode_is_link_internal(unsigned int tcode) +{ + return (tcode == TCODE_LINK_INTERNAL); +} #define LOCAL_BUS 0xffc0 diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 4811e3255ca8..6116153f0ce6 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1382,7 +1382,7 @@ static int at_context_queue_packet(struct context *ctx, (packet->header[0] & 0xffff0000)); header[2] = cpu_to_le32(packet->header[2]); - if (TCODE_IS_BLOCK_PACKET(tcode)) + if (tcode_is_block_packet(tcode)) header[3] = cpu_to_le32(packet->header[3]); else header[3] = (__force __le32) packet->header[3]; @@ -1568,7 +1568,7 @@ static void handle_local_rom(struct fw_ohci *ohci, int tcode, length, i; tcode = async_header_get_tcode(packet->header); - if (TCODE_IS_BLOCK_PACKET(tcode)) + if (tcode_is_block_packet(tcode)) length = async_header_get_data_length(packet->header); else length = 4; @@ -1577,7 +1577,7 @@ static void handle_local_rom(struct fw_ohci *ohci, if (i + length > CONFIG_ROM_SIZE) { fw_fill_response(&response, packet->header, RCODE_ADDRESS_ERROR, NULL, 0); - } else if (!TCODE_IS_READ_REQUEST(tcode)) { + } else if (!tcode_is_read_request(tcode)) { fw_fill_response(&response, packet->header, RCODE_TYPE_ERROR, NULL, 0); } else { -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:09
|
In the helper function for logging in 1394 ohci driver includes the hard-coded variables for transaction code. They can be replaced with the enumerations in UAPI header. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index be8ede492ead..4811e3255ca8 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -533,11 +533,17 @@ static void log_ar_at_event(struct fw_ohci *ohci, } switch (tcode) { - case 0x0: case 0x6: case 0x8: + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_READ_QUADLET_RESPONSE: + case TCODE_CYCLE_START: snprintf(specific, sizeof(specific), " = %08x", be32_to_cpu((__force __be32)header[3])); break; - case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_LOCK_RESPONSE: snprintf(specific, sizeof(specific), " %x,%x", async_header_get_data_length(header), async_header_get_extended_tcode(header)); @@ -547,7 +553,7 @@ static void log_ar_at_event(struct fw_ohci *ohci, } switch (tcode) { - case 0xa: + case TCODE_STREAM_DATA: ohci_notice(ohci, "A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); break; @@ -555,7 +561,11 @@ static void log_ar_at_event(struct fw_ohci *ohci, ohci_notice(ohci, "A%c %s, PHY %08x %08x\n", dir, evts[evt], header[1], header[2]); break; - case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_LOCK_REQUEST: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %012llx%s\n", dir, speed, async_header_get_tlabel(header), -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:06
|
This commit uses the common inline functions to serialize and deserialize header of asynchronous packet. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index e4ad624c60cb..5f702f56ac7b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -40,6 +40,7 @@ #include "core.h" #include "ohci.h" +#include "packet-header-definitions.h" #define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) #define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) @@ -1550,21 +1551,15 @@ static int handle_at_packet(struct context *context, return 1; } -#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) -#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) -#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - static void handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) { struct fw_packet response; int tcode, length, i; - tcode = HEADER_GET_TCODE(packet->header[0]); + tcode = async_header_get_tcode(packet->header); if (TCODE_IS_BLOCK_PACKET(tcode)) - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + length = async_header_get_data_length(packet->header); else length = 4; @@ -1591,10 +1586,10 @@ static void handle_local_lock(struct fw_ohci *ohci, __be32 *payload, lock_old; u32 lock_arg, lock_data; - tcode = HEADER_GET_TCODE(packet->header[0]); - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + tcode = async_header_get_tcode(packet->header); + length = async_header_get_data_length(packet->header); payload = packet->payload; - ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]); + ext_tcode = async_header_get_extended_tcode(packet->header); if (tcode == TCODE_LOCK_REQUEST && ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) { @@ -1640,10 +1635,7 @@ static void handle_local_request(struct context *ctx, struct fw_packet *packet) packet->callback(packet, &ctx->ohci->card, packet->ack); } - offset = - ((unsigned long long) - HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) | - packet->header[2]; + offset = async_header_get_offset(packet->header); csr = offset - CSR_REGISTER_BASE; /* Handle config rom reads. */ @@ -1679,7 +1671,7 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) spin_lock_irqsave(&ctx->ohci->lock, flags); - if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id && + if (async_header_get_destination(packet->header) == ctx->ohci->node_id && ctx->ohci->generation == packet->generation) { spin_unlock_irqrestore(&ctx->ohci->lock, flags); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:04
|
This commit uses common inline functions to serialize and deserialize header of asynchronous packet. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 138 +++++++++++----------------- 1 file changed, 56 insertions(+), 82 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index c427b7861eaf..a113f801cf33 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -29,29 +29,13 @@ #include <asm/byteorder.h> #include "core.h" +#include "packet-header-definitions.h" -#define HEADER_PRI(pri) ((pri) << 0) #define HEADER_TCODE(tcode) ((tcode) << 4) -#define HEADER_RETRY(retry) ((retry) << 8) -#define HEADER_TLABEL(tlabel) ((tlabel) << 10) -#define HEADER_DESTINATION(destination) ((destination) << 16) -#define HEADER_SOURCE(source) ((source) << 16) -#define HEADER_RCODE(rcode) ((rcode) << 12) -#define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0) #define HEADER_DATA_LENGTH(length) ((length) << 16) -#define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0) -#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) -#define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f) -#define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f) -#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) -#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - -#define HEADER_DESTINATION_IS_BROADCAST(q) \ - (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) +#define HEADER_DESTINATION_IS_BROADCAST(header) \ + ((async_header_get_destination(header) & 0x3f) == 0x3f) #define PHY_PACKET_CONFIG 0x0 #define PHY_PACKET_LINK_ON 0x1 @@ -248,28 +232,24 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, } else ext_tcode = 0; - packet->header[0] = - HEADER_RETRY(RETRY_X) | - HEADER_TLABEL(tlabel) | - HEADER_TCODE(tcode) | - HEADER_DESTINATION(destination_id); - packet->header[1] = - HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); - packet->header[2] = - offset; + async_header_set_retry(packet->header, RETRY_X); + async_header_set_tlabel(packet->header, tlabel); + async_header_set_tcode(packet->header, tcode); + async_header_set_destination(packet->header, destination_id); + async_header_set_source(packet->header, source_id); + async_header_set_offset(packet->header, offset); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: - packet->header[3] = *(u32 *)payload; + async_header_set_quadlet_data(packet->header, *(u32 *)payload); packet->header_length = 16; packet->payload_length = 0; break; case TCODE_LOCK_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: - packet->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(ext_tcode); + async_header_set_data_length(packet->header, length); + async_header_set_extended_tcode(packet->header, ext_tcode); packet->header_length = 16; packet->payload = payload; packet->payload_length = length; @@ -281,9 +261,8 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, break; case TCODE_READ_BLOCK_REQUEST: - packet->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(ext_tcode); + async_header_set_data_length(packet->header, length); + async_header_set_extended_tcode(packet->header, ext_tcode); packet->header_length = 16; packet->payload_length = 0; break; @@ -655,7 +634,7 @@ EXPORT_SYMBOL(fw_core_remove_address_handler); struct fw_request { struct kref kref; struct fw_packet response; - u32 request_header[4]; + u32 request_header[ASYNC_HEADER_QUADLET_COUNT]; int ack; u32 timestamp; u32 length; @@ -695,7 +674,7 @@ int fw_get_response_length(struct fw_request *r) { int tcode, ext_tcode, data_length; - tcode = HEADER_GET_TCODE(r->request_header[0]); + tcode = async_header_get_tcode(r->request_header); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: @@ -706,12 +685,12 @@ int fw_get_response_length(struct fw_request *r) return 4; case TCODE_READ_BLOCK_REQUEST: - data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + data_length = async_header_get_data_length(r->request_header); return data_length; case TCODE_LOCK_REQUEST: - ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]); - data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + ext_tcode = async_header_get_extended_tcode(r->request_header); + data_length = async_header_get_data_length(r->request_header); switch (ext_tcode) { case EXTCODE_FETCH_ADD: case EXTCODE_LITTLE_ADD: @@ -731,46 +710,42 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header, { int tcode, tlabel, extended_tcode, source, destination; - tcode = HEADER_GET_TCODE(request_header[0]); - tlabel = HEADER_GET_TLABEL(request_header[0]); - source = HEADER_GET_DESTINATION(request_header[0]); - destination = HEADER_GET_SOURCE(request_header[1]); - extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]); - - response->header[0] = - HEADER_RETRY(RETRY_1) | - HEADER_TLABEL(tlabel) | - HEADER_DESTINATION(destination); - response->header[1] = - HEADER_SOURCE(source) | - HEADER_RCODE(rcode); - response->header[2] = 0; + tcode = async_header_get_tcode(request_header); + tlabel = async_header_get_tlabel(request_header); + source = async_header_get_destination(request_header); // Exchange. + destination = async_header_get_source(request_header); // Exchange. + extended_tcode = async_header_get_extended_tcode(request_header); + + async_header_set_retry(response->header, RETRY_1); + async_header_set_tlabel(response->header, tlabel); + async_header_set_destination(response->header, destination); + async_header_set_source(response->header, source); + async_header_set_rcode(response->header, rcode); + response->header[2] = 0; // The field is reserved. switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: - response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); + async_header_set_tcode(response->header, TCODE_WRITE_RESPONSE); response->header_length = 12; response->payload_length = 0; break; case TCODE_READ_QUADLET_REQUEST: - response->header[0] |= - HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); + async_header_set_tcode(response->header, TCODE_READ_QUADLET_RESPONSE); if (payload != NULL) - response->header[3] = *(u32 *)payload; + async_header_set_quadlet_data(response->header, *(u32 *)payload); else - response->header[3] = 0; + async_header_set_quadlet_data(response->header, 0); response->header_length = 16; response->payload_length = 0; break; case TCODE_READ_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: - response->header[0] |= HEADER_TCODE(tcode + 2); - response->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(extended_tcode); + async_header_set_tcode(response->header, tcode + 2); + async_header_set_data_length(response->header, length); + async_header_set_extended_tcode(response->header, extended_tcode); response->header_length = 16; response->payload = payload; response->payload_length = length; @@ -807,7 +782,7 @@ static struct fw_request *allocate_request(struct fw_card *card, u32 *data, length; int request_tcode; - request_tcode = HEADER_GET_TCODE(p->header[0]); + request_tcode = async_header_get_tcode(p->header); switch (request_tcode) { case TCODE_WRITE_QUADLET_REQUEST: data = &p->header[3]; @@ -817,7 +792,7 @@ static struct fw_request *allocate_request(struct fw_card *card, case TCODE_WRITE_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: data = p->payload; - length = HEADER_GET_DATA_LENGTH(p->header[3]); + length = async_header_get_data_length(p->header); break; case TCODE_READ_QUADLET_REQUEST: @@ -827,7 +802,7 @@ static struct fw_request *allocate_request(struct fw_card *card, case TCODE_READ_BLOCK_REQUEST: data = NULL; - length = HEADER_GET_DATA_LENGTH(p->header[3]); + length = async_header_get_data_length(p->header); break; default: @@ -872,7 +847,7 @@ void fw_send_response(struct fw_card *card, { /* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || - HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { + HEADER_DESTINATION_IS_BROADCAST(request->request_header)) { fw_request_put(request); return; } @@ -926,11 +901,11 @@ static void handle_exclusive_region_request(struct fw_card *card, struct fw_address_handler *handler; int tcode, destination, source; - destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); - tcode = HEADER_GET_TCODE(p->header[0]); + destination = async_header_get_destination(p->header); + source = async_header_get_source(p->header); + tcode = async_header_get_tcode(p->header); if (tcode == TCODE_LOCK_REQUEST) - tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); + tcode = 0x10 + async_header_get_extended_tcode(p->header); rcu_read_lock(); handler = lookup_enclosing_address_handler(&address_handler_list, @@ -963,9 +938,9 @@ static void handle_fcp_region_request(struct fw_card *card, return; } - tcode = HEADER_GET_TCODE(p->header[0]); - destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); + tcode = async_header_get_tcode(p->header); + destination = async_header_get_destination(p->header); + source = async_header_get_source(p->header); if (tcode != TCODE_WRITE_QUADLET_REQUEST && tcode != TCODE_WRITE_BLOCK_REQUEST) { @@ -997,7 +972,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { + if (TCODE_IS_LINK_INTERNAL(async_header_get_tcode(p->header))) { fw_cdev_handle_phy_packet(card, p); return; } @@ -1008,8 +983,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) return; } - offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | - p->header[2]; + offset = async_header_get_offset(p->header); if (!is_in_fcp_region(offset, request->length)) handle_exclusive_region_request(card, p, request, offset); @@ -1027,10 +1001,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) size_t data_length; int tcode, tlabel, source, rcode; - tcode = HEADER_GET_TCODE(p->header[0]); - tlabel = HEADER_GET_TLABEL(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); - rcode = HEADER_GET_RCODE(p->header[1]); + tcode = async_header_get_tcode(p->header); + tlabel = async_header_get_tlabel(p->header); + source = async_header_get_source(p->header); + rcode = async_header_get_rcode(p->header); spin_lock_irqsave(&card->lock, flags); list_for_each_entry(iter, &card->transaction_list, link) { @@ -1073,7 +1047,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_RESPONSE: data = p->payload; - data_length = HEADER_GET_DATA_LENGTH(p->header[3]); + data_length = async_header_get_data_length(p->header); break; default: -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:03
|
In both core and 1394 OHCI driver, some hard-coded values and macros are used to serialize/deserialize the header of asynchronous packets. It is inconvenient to reuse them. This commit adds some helper inline functions with their tests for the purpose. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/.kunitconfig | 1 + drivers/firewire/Kconfig | 16 + drivers/firewire/Makefile | 3 + drivers/firewire/packet-header-definitions.h | 168 ++++++ drivers/firewire/packet-serdes-test.c | 538 +++++++++++++++++++ 5 files changed, 726 insertions(+) create mode 100644 drivers/firewire/packet-header-definitions.h create mode 100644 drivers/firewire/packet-serdes-test.c diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig index 76444a2d5e12..60d9e7c35417 100644 --- a/drivers/firewire/.kunitconfig +++ b/drivers/firewire/.kunitconfig @@ -3,3 +3,4 @@ CONFIG_PCI=y CONFIG_FIREWIRE=y CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y +CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 552a39df8cbd..869598b20e3a 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -50,6 +50,22 @@ config FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST For more information on KUnit and unit tests in general, refer to the KUnit documentation in Documentation/dev-tools/kunit/. +config FIREWIRE_KUNIT_PACKET_SERDES_TEST + tristate "KUnit tests for packet serialization/deserialization" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests for packet serialization and + deserialization. + + 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_OHCI tristate "OHCI-1394 controllers" depends on PCI && FIREWIRE && MMU diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index b24b2879ac34..bbde29a0fba6 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -17,4 +17,7 @@ obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o firewire-uapi-test-objs += uapi-test.o +firewire-packet-serdes-test-objs += packet-serdes-test.o + obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += firewire-uapi-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += firewire-packet-serdes-test.o diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h new file mode 100644 index 000000000000..83e550427706 --- /dev/null +++ b/drivers/firewire/packet-header-definitions.h @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// packet-header-definitions.h - The definitions of header fields for IEEE 1394 packet. +// +// Copyright (c) 2024 Takashi Sakamoto + +#ifndef _FIREWIRE_PACKET_HEADER_DEFINITIONS_H +#define _FIREWIRE_PACKET_HEADER_DEFINITIONS_H + +#define ASYNC_HEADER_QUADLET_COUNT 4 + +#define ASYNC_HEADER_Q0_DESTINATION_SHIFT 16 +#define ASYNC_HEADER_Q0_DESTINATION_MASK 0xffff0000 +#define ASYNC_HEADER_Q0_TLABEL_SHIFT 10 +#define ASYNC_HEADER_Q0_TLABEL_MASK 0x0000fc00 +#define ASYNC_HEADER_Q0_RETRY_SHIFT 8 +#define ASYNC_HEADER_Q0_RETRY_MASK 0x00000300 +#define ASYNC_HEADER_Q0_TCODE_SHIFT 4 +#define ASYNC_HEADER_Q0_TCODE_MASK 0x000000f0 +#define ASYNC_HEADER_Q0_PRIORITY_SHIFT 0 +#define ASYNC_HEADER_Q0_PRIORITY_MASK 0x0000000f +#define ASYNC_HEADER_Q1_SOURCE_SHIFT 16 +#define ASYNC_HEADER_Q1_SOURCE_MASK 0xffff0000 +#define ASYNC_HEADER_Q1_RCODE_SHIFT 12 +#define ASYNC_HEADER_Q1_RCODE_MASK 0x0000f000 +#define ASYNC_HEADER_Q1_RCODE_SHIFT 12 +#define ASYNC_HEADER_Q1_RCODE_MASK 0x0000f000 +#define ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT 0 +#define ASYNC_HEADER_Q1_OFFSET_HIGH_MASK 0x0000ffff +#define ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT 16 +#define ASYNC_HEADER_Q3_DATA_LENGTH_MASK 0xffff0000 +#define ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT 0 +#define ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK 0x0000ffff + +static inline unsigned int async_header_get_destination(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_DESTINATION_MASK) >> ASYNC_HEADER_Q0_DESTINATION_SHIFT; +} + +static inline unsigned int async_header_get_tlabel(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_TLABEL_MASK) >> ASYNC_HEADER_Q0_TLABEL_SHIFT; +} + +static inline unsigned int async_header_get_retry(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_RETRY_MASK) >> ASYNC_HEADER_Q0_RETRY_SHIFT; +} + +static inline unsigned int async_header_get_tcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_TCODE_MASK) >> ASYNC_HEADER_Q0_TCODE_SHIFT; +} + +static inline unsigned int async_header_get_priority(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_PRIORITY_MASK) >> ASYNC_HEADER_Q0_PRIORITY_SHIFT; +} + +static inline unsigned int async_header_get_source(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[1] & ASYNC_HEADER_Q1_SOURCE_MASK) >> ASYNC_HEADER_Q1_SOURCE_SHIFT; +} + +static inline unsigned int async_header_get_rcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[1] & ASYNC_HEADER_Q1_RCODE_MASK) >> ASYNC_HEADER_Q1_RCODE_SHIFT; +} + +static inline u64 async_header_get_offset(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + u32 hi = (header[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT; + return (((u64)hi) << 32) | ((u64)header[2]); +} + +static inline u32 async_header_get_quadlet_data(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return header[3]; +} + +static inline unsigned int async_header_get_data_length(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[3] & ASYNC_HEADER_Q3_DATA_LENGTH_MASK) >> ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT; +} + +static inline unsigned int async_header_get_extended_tcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[3] & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK) >> ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT; +} + +static inline void async_header_set_destination(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int destination) +{ + header[0] &= ~ASYNC_HEADER_Q0_DESTINATION_MASK; + header[0] |= (((u32)destination) << ASYNC_HEADER_Q0_DESTINATION_SHIFT) & ASYNC_HEADER_Q0_DESTINATION_MASK; +} + +static inline void async_header_set_tlabel(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int tlabel) +{ + header[0] &= ~ASYNC_HEADER_Q0_TLABEL_MASK; + header[0] |= (((u32)tlabel) << ASYNC_HEADER_Q0_TLABEL_SHIFT) & ASYNC_HEADER_Q0_TLABEL_MASK; +} + +static inline void async_header_set_retry(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int retry) +{ + header[0] &= ~ASYNC_HEADER_Q0_RETRY_MASK; + header[0] |= (((u32)retry) << ASYNC_HEADER_Q0_RETRY_SHIFT) & ASYNC_HEADER_Q0_RETRY_MASK; +} + +static inline void async_header_set_tcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int tcode) +{ + header[0] &= ~ASYNC_HEADER_Q0_TCODE_MASK; + header[0] |= (((u32)tcode) << ASYNC_HEADER_Q0_TCODE_SHIFT) & ASYNC_HEADER_Q0_TCODE_MASK; +} + +static inline void async_header_set_priority(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int priority) +{ + header[0] &= ~ASYNC_HEADER_Q0_PRIORITY_MASK; + header[0] |= (((u32)priority) << ASYNC_HEADER_Q0_PRIORITY_SHIFT) & ASYNC_HEADER_Q0_PRIORITY_MASK; +} + + +static inline void async_header_set_source(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int source) +{ + header[1] &= ~ASYNC_HEADER_Q1_SOURCE_MASK; + header[1] |= (((u32)source) << ASYNC_HEADER_Q1_SOURCE_SHIFT) & ASYNC_HEADER_Q1_SOURCE_MASK; +} + +static inline void async_header_set_rcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int rcode) +{ + header[1] &= ~ASYNC_HEADER_Q1_RCODE_MASK; + header[1] |= (((u32)rcode) << ASYNC_HEADER_Q1_RCODE_SHIFT) & ASYNC_HEADER_Q1_RCODE_MASK; +} + +static inline void async_header_set_offset(u32 header[ASYNC_HEADER_QUADLET_COUNT], u64 offset) +{ + u32 hi = (u32)(offset >> 32); + header[1] &= ~ASYNC_HEADER_Q1_OFFSET_HIGH_MASK; + header[1] |= (hi << ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK; + header[2] = (u32)(offset & 0x00000000ffffffff); +} + +static inline void async_header_set_quadlet_data(u32 header[ASYNC_HEADER_QUADLET_COUNT], u32 quadlet_data) +{ + header[3] = quadlet_data; +} + +static inline void async_header_set_data_length(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int data_length) +{ + header[3] &= ~ASYNC_HEADER_Q3_DATA_LENGTH_MASK; + header[3] |= (((u32)data_length) << ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT) & ASYNC_HEADER_Q3_DATA_LENGTH_MASK; +} + +static inline void async_header_set_extended_tcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int extended_tcode) +{ + header[3] &= ~ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; + header[3] |= (((u32)extended_tcode) << ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT) & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; +} + +#endif // _FIREWIRE_PACKET_HEADER_DEFINITIONS_H diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c new file mode 100644 index 000000000000..299e9f908463 --- /dev/null +++ b/drivers/firewire/packet-serdes-test.c @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// packet-serdes-test.c - An application of Kunit to check serialization/deserialization of packets +// defined by IEEE 1394. +// +// Copyright (c) 2024 Takashi Sakamoto + +#include <kunit/test.h> + +#include <linux/firewire-constants.h> + +#include "packet-header-definitions.h" + +static void serialize_async_header_common(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id) +{ + async_header_set_destination(header, dst_id); + async_header_set_tlabel(header, tlabel); + async_header_set_retry(header, retry); + async_header_set_tcode(header, tcode); + async_header_set_priority(header, priority); + async_header_set_source(header, src_id); +} + +static void serialize_async_header_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, u64 offset) +{ + serialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + async_header_set_offset(header, offset); +} + +static void serialize_async_header_quadlet_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + u64 offset) +{ + serialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); +} + +static void serialize_async_header_block_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + u64 offset, unsigned int data_length, + unsigned int extended_tcode) +{ + serialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); + async_header_set_data_length(header, data_length); + async_header_set_extended_tcode(header, extended_tcode); +} + +static void serialize_async_header_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode) +{ + serialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + async_header_set_rcode(header, rcode); +} + +static void serialize_async_header_quadlet_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode) +{ + serialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, + rcode); +} + +static void serialize_async_header_block_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode, unsigned int data_length, + unsigned int extended_tcode) +{ + serialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, + rcode); + async_header_set_data_length(header, data_length); + async_header_set_extended_tcode(header, extended_tcode); +} + +static void deserialize_async_header_common(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id) +{ + *dst_id = async_header_get_destination(header); + *tlabel = async_header_get_tlabel(header); + *retry = async_header_get_retry(header); + *tcode = async_header_get_tcode(header); + *priority = async_header_get_priority(header); + *src_id = async_header_get_source(header); +} + +static void deserialize_async_header_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset) +{ + deserialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + *offset = async_header_get_offset(header); +} + +static void deserialize_async_header_quadlet_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset) +{ + deserialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); +} + +static void deserialize_async_header_block_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset, + unsigned int *data_length, + unsigned int *extended_tcode) +{ + deserialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); + *data_length = async_header_get_data_length(header); + *extended_tcode = async_header_get_extended_tcode(header); +} + +static void deserialize_async_header_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode) +{ + deserialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + *rcode = async_header_get_rcode(header); +} + +static void deserialize_async_header_quadlet_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode) +{ + deserialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, rcode); +} + +static void deserialize_async_header_block_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode, unsigned int *data_length, + unsigned int *extended_tcode) +{ + deserialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, rcode); + *data_length = async_header_get_data_length(header); + *extended_tcode = async_header_get_extended_tcode(header); +} + +static void test_async_header_write_quadlet_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc05100, + 0xffc1ffff, + 0xf0000234, + 0x1f0000c0, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + u32 quadlet_data; + + deserialize_async_header_quadlet_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset); + quadlet_data = async_header_get_quadlet_data(expected); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x14, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_QUADLET_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000234, offset); + KUNIT_EXPECT_EQ(test, 0x1f0000c0, quadlet_data); + + serialize_async_header_quadlet_request(header, dst_id, tlabel, retry, tcode, priority, + src_id, offset); + async_header_set_quadlet_data(header, quadlet_data); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_write_block_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc06510, + 0xffc1ecc0, + 0x00000000, + 0x00180000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x19, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_BLOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xecc000000000, offset); + KUNIT_EXPECT_EQ(test, 0x0018, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_write_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc15120, + 0xffc00000, + 0x00000000, + 0x00000000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + + deserialize_async_header_quadlet_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x14, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + + serialize_async_header_quadlet_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected) - sizeof(expected[0])); +} + +static void test_async_header_read_quadlet_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc0f140, + 0xffc1ffff, + 0xf0000984, + 0x00000000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + + deserialize_async_header_quadlet_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x3c, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_QUADLET_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000984, offset); + + serialize_async_header_quadlet_request(header, dst_id, tlabel, retry, tcode, priority, + src_id, offset); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_quadlet_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc1f160, + 0xffc00000, + 0x00000000, + 0x00000180, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + u32 quadlet_data; + + deserialize_async_header_quadlet_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode); + quadlet_data = async_header_get_quadlet_data(expected); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x3c, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_QUADLET_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x00000180, quadlet_data); + + serialize_async_header_quadlet_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode); + async_header_set_quadlet_data(header, quadlet_data); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_block_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc0e150, + 0xffc1ffff, + 0xf0000400, + 0x00200000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x38, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_BLOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000400, offset); + KUNIT_EXPECT_EQ(test, 0x0020, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_block_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc1e170, + 0xffc00000, + 0x00000000, + 0x00200000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x38, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_BLOCK_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x0020, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_lock_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc02d90, + 0xffc1ffff, + 0xf0000984, + 0x00080002, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x0b, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_LOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000984, offset); + KUNIT_EXPECT_EQ(test, 0x0008, data_length); + KUNIT_EXPECT_EQ(test, EXTCODE_COMPARE_SWAP, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_lock_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc12db0, + 0xffc00000, + 0x00000000, + 0x00040002, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x0b, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_LOCK_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x0004, data_length); + KUNIT_EXPECT_EQ(test, EXTCODE_COMPARE_SWAP, extended_tcode); + + serialize_async_header_block_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, 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), + KUNIT_CASE(test_async_header_write_response), + KUNIT_CASE(test_async_header_read_quadlet_request), + KUNIT_CASE(test_async_header_read_quadlet_response), + KUNIT_CASE(test_async_header_read_block_request), + KUNIT_CASE(test_async_header_read_block_response), + KUNIT_CASE(test_async_header_lock_request), + KUNIT_CASE(test_async_header_lock_response), + {} +}; + +static struct kunit_suite packet_serdes_test_suite = { + .name = "firewire-packet-serdes", + .test_cases = packet_serdes_test_cases, +}; +kunit_test_suite(packet_serdes_test_suite); + +MODULE_LICENSE("GPL"); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 07:14:01
|
Hi, Between core and 1394 ohci driver modules, the data of 'struct fw_packet' is utilized to deliver data of asynchronous packet. Especially, its 'header' array member is for the parameters of packet. However, the serialization/deserialization are done by local hard-coded macro in each module. It is inconvenient. This series of changes adds some inline helper functions to replace them. A KUnit test is also added to check them. Takashi Sakamoto (8): firewire: core: add common inline functions to serialize/deserialize asynchronous packet header firewire: core: replace local macros with common inline functions for asynchronous packet header firewire: ohci: replace local macros with common inline functions for asynchronous packet header firewire: ohci: replace hard-coded values with inline functions for asynchronous packet header firewire: ohci: replace hard-coded values with common macros firewire: core: obsolete tcode check macros with inline functions firewire: core: add common macro to serialize/deserialize isochronous packet header firewire: core: replace local macros with common inline functions for isochronous packet header drivers/firewire/.kunitconfig | 1 + drivers/firewire/Kconfig | 16 + drivers/firewire/Makefile | 3 + drivers/firewire/core-transaction.c | 152 ++--- drivers/firewire/core.h | 21 +- drivers/firewire/ohci.c | 78 +-- drivers/firewire/packet-header-definitions.h | 234 ++++++++ drivers/firewire/packet-serdes-test.c | 582 +++++++++++++++++++ 8 files changed, 952 insertions(+), 135 deletions(-) create mode 100644 drivers/firewire/packet-header-definitions.h create mode 100644 drivers/firewire/packet-serdes-test.c -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-28 01:08:12
|
Hi, I'm a maintaier of Linux firewire subsystem (and ALSA dice driver). On Sat, Apr 27, 2024 at 04:15:33AM +0200, Joerg M. Sigle wrote: > I'm Joerg and I have a DM-4800 with the firewire interface card. > > I've seen before that there might be some support for its version 1, > which is used in the DM-24 mixer. But I would be very happy if I > could use the larger and more recent rig with Linux. > > I can program (to some extent :-) ) and if somebody could give me some > guidance, might possibly be able to make required adoptions to change a > Version 1 driver into a Version 2 driver. I've also (again, just now) > contacted Tascam asking whether they might be willing to provide > necessary documentation. > > I've also seen that some Tascam firewire support seems to be even in the > drivers/sound/firewire section of the linux kernel, In my opinion, you are the first person who owns the device in FLOSS world. Would I ask you to provide some resources to enhance the support of your device? 1. The image of configuration ROM I maintain hardware database[1] in systemd project, to describe vendor, model, and functions of each device. The data comes from the collection of configuration ROM[2], which is used to identify each node and units in IEEE 1394 bus. Would I ask you to provide the image of your device to fulfill the database? When your device is detected as `fw1`, the image is exposed via `/sys/bus/firewire/devices/fw1/config_rom', thus you can create the file for image by the command line, like: $ cat /sys/bus/firewire/devices/fw1/config_rom > tascam-iffw2.img 2. General section information in Wavefront DiceII ASIC The ASIC allows software to operate its functions by asynchronous communication by protocol defined by TC Applied Technologies (TCAT). The first step of the protocol is to read data of general section in its specific register. Would I ask you to provide the data? I maintain linux-firewire-utils[3] for the purpose[3]. When compiling it successfully (or installing), you can use `firewire-request` command to access to the section, like. $ firewire-request /dev/fw1 read 0xffffe0000000 0x28 It is known that the early version of firmware in TCAT dice solution has different size of global section than the later version. If you can see any failure by the above command, please retry with different size, like. $ firewire-request /dev/fw1 read 0xffffe0000000 0x20 The general section includes the offsets of sub-sections. If successful, let us go to access to Global section. [1] https://github.com/systemd/systemd/blob/main/hwdb.d/80-ieee1394-unit-function.hwdb [2] https://github.com/takaswie/am-config-roms/ [3] https://git.kernel.org/pub/scm/utils/ieee1394/linux-firewire-utils.git/ Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:24:07
|
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. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 6 +++ drivers/firewire/trace.h | 80 ++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 52d8d483c178..11a60094182a 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -29,6 +29,7 @@ #include <asm/byteorder.h> #include "core.h" +#include "trace.h" #include "packet-header-definitions.h" #define HEADER_DESTINATION_IS_BROADCAST(header) \ @@ -173,6 +174,8 @@ 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(card, t, packet); + switch (status) { case ACK_COMPLETE: close_transaction(t, card, RCODE_COMPLETE, packet->timestamp); @@ -394,6 +397,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(card, t, &t->packet, payload, + tcode_is_read_request(tcode) ? 0 : length / 4); + card->driver->send_request(card, &t->packet); } EXPORT_SYMBOL_GPL(__fw_send_request); diff --git a/drivers/firewire/trace.h b/drivers/firewire/trace.h index d36a10460301..0f7d176ba647 100644 --- a/drivers/firewire/trace.h +++ b/drivers/firewire/trace.h @@ -7,8 +7,86 @@ #define _FIREWIRE_TRACE_EVENT_H #include <linux/tracepoint.h> +#include <linux/firewire.h> -// Placeholder for future use. +#include <linux/firewire-constants.h> + +#include "packet-header-definitions.h" + +TRACE_EVENT(async_request_outbound_initiate, + TP_PROTO(const struct fw_card *card, const struct fw_transaction *transaction, + const struct fw_packet *packet, const u32 *data, size_t data_count), + TP_ARGS(card, transaction, packet, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, scode) + __field(u8, generation) + __field(u16, destination) + __field(u8, tlabel) + __field(u8, retry) + __field(u8, tcode) + __field(u8, priority) + __field(u16, source) + __field(u64, offset) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = (u64)transaction; + __entry->scode = packet->speed; + __entry->generation = packet->generation; + __entry->destination = async_header_get_destination(packet->header); + __entry->tlabel = async_header_get_tlabel(packet->header); + __entry->retry = async_header_get_retry(packet->header); + __entry->tcode = async_header_get_tcode(packet->header); + __entry->priority = async_header_get_priority(packet->header); + __entry->source = async_header_get_source(packet->header); + __entry->offset = async_header_get_offset(packet->header); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + TP_printk( + "transaction=0x%llx scode=%u generation=%u dst_id=0x%04x tlabel=%u retry=%u tcode=%u priority=%u src_id=0x%04x offset=0x%012llx data=%s", + __entry->transaction, + __entry->scode, + __entry->generation, + __entry->destination, + __entry->tlabel, + __entry->retry, + __entry->tcode, + __entry->priority, + __entry->source, + __entry->offset, + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / sizeof(u32), sizeof(u32)) + ) +) + +TRACE_EVENT(async_request_outbound_complete, + TP_PROTO(const struct fw_card *card, const struct fw_transaction *transaction, + const struct fw_packet *packet), + TP_ARGS(card, transaction, packet), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, scode) + __field(u8, generation) + __field(u8, ack) + __field(u16, timestamp) + ), + TP_fast_assign( + __entry->transaction = (u64)transaction; + __entry->scode = packet->speed; + __entry->generation = packet->generation; + __entry->ack = packet->ack; + __entry->timestamp = packet->timestamp; + ), + TP_printk( + "transaction=0x%llx scode=%u generation=%u ack=%u timestamp=0x%04x", + __entry->transaction, + __entry->scode, + __entry->generation, + __entry->ack, + __entry->timestamp + ) +) #endif // _FIREWIRE_TRACE_EVENT_H -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:24:06
|
In a view of core transaction service, the asynchronous outbound response consists of two stages; initiation and completion. This commit adds a pair of events for the asynchronous outbound response. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 21 ++++++--- drivers/firewire/trace.h | 68 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 1b972e95fe36..c963832d9824 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -667,6 +667,8 @@ static void free_response_callback(struct fw_packet *packet, { struct fw_request *request = container_of(packet, struct fw_request, response); + trace_async_response_outbound_complete(card, request, packet); + // Decrease the reference count since not at in-flight. fw_request_put(request); @@ -849,6 +851,9 @@ static struct fw_request *allocate_request(struct fw_card *card, void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) { + u32 *data = NULL; + unsigned int data_length = 0; + /* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || HEADER_DESTINATION_IS_BROADCAST(request->request_header)) { @@ -856,17 +861,19 @@ void fw_send_response(struct fw_card *card, return; } - if (rcode == RCODE_COMPLETE) - fw_fill_response(&request->response, request->request_header, - rcode, request->data, - fw_get_response_length(request)); - else - fw_fill_response(&request->response, request->request_header, - rcode, NULL, 0); + if (rcode == RCODE_COMPLETE) { + data = request->data; + data_length = fw_get_response_length(request); + } + + fw_fill_response(&request->response, request->request_header, rcode, data, data_length); // Increase the reference count so that the object is kept during in-flight. fw_request_get(request); + trace_async_response_outbound_initiate(card, request, &request->response, data, + data ? data_length / 4 : 0); + card->driver->send_response(card, &request->response); } EXPORT_SYMBOL(fw_send_response); diff --git a/drivers/firewire/trace.h b/drivers/firewire/trace.h index ba09eb720933..0109a70d3b02 100644 --- a/drivers/firewire/trace.h +++ b/drivers/firewire/trace.h @@ -190,6 +190,74 @@ TRACE_EVENT(async_request_inbound, ) ) +TRACE_EVENT(async_response_outbound_initiate, + TP_PROTO(const struct fw_card *card, const struct fw_request *request, + const struct fw_packet *packet, const u32 *data, unsigned int data_count), + TP_ARGS(card, request, packet, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, scode) + __field(u8, generation) + __field(u16, destination) + __field(u8, tlabel) + __field(u8, retry) + __field(u8, tcode) + __field(u8, priority) + __field(u16, source) + __field(u8, rcode) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = (u64)request; + __entry->scode = packet->speed; + __entry->generation = packet->generation; + __entry->destination = async_header_get_destination(packet->header); + __entry->tlabel = async_header_get_tlabel(packet->header); + __entry->retry = async_header_get_retry(packet->header); + __entry->tcode = async_header_get_tcode(packet->header); + __entry->priority = async_header_get_priority(packet->header); + __entry->source = async_header_get_source(packet->header); + __entry->rcode = async_header_get_rcode(packet->header); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + TP_printk( + "transaction=0x%llx scode=%u generation=%u dst_id=0x%04x tlabel=%u retry=%u tcode=%u priority=%u src_id=0x%04x rcode=%u data=%s", + __entry->transaction, + __entry->scode, + __entry->generation, + __entry->destination, + __entry->tlabel, + __entry->retry, + __entry->tcode, + __entry->priority, + __entry->source, + __entry->rcode, + __print_array(__get_dynamic_array(data), __get_dynamic_array_len(data), sizeof(u32)) + ) +) + +TRACE_EVENT(async_response_outbound_complete, + TP_PROTO(const struct fw_card *card, const struct fw_request *request, + const struct fw_packet *packet), + TP_ARGS(card, request, packet), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, ack) + __field(u16, timestamp) + ), + TP_fast_assign( + __entry->transaction = (u64)request; + __entry->ack = packet->ack; + __entry->timestamp = packet->timestamp; + ), + TP_printk( + "transaction=0x%llx ack=%u timestamp=0x%04x", + __entry->transaction, + __entry->ack, + __entry->timestamp + ) +) + #endif // _FIREWIRE_TRACE_EVENT_H #define TRACE_INCLUDE_PATH . -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:23:58
|
In the transaction of IEEE 1394, the node to receive the asynchronous request transfers response packet to the requester. This commit adds an event for the incoming packet. Note that the code to decode the packet header is moved, against the note about the sanity check. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 54 +++++++++++++++-------------- drivers/firewire/trace.h | 48 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 11a60094182a..977d8a36f969 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1010,32 +1010,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) source = async_header_get_source(p->header); rcode = async_header_get_rcode(p->header); - spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(iter, &card->transaction_list, link) { - if (iter->node_id == source && iter->tlabel == tlabel) { - if (!try_cancel_split_timeout(iter)) { - spin_unlock_irqrestore(&card->lock, flags); - goto timed_out; - } - list_del_init(&iter->link); - card->tlabel_mask &= ~(1ULL << iter->tlabel); - t = iter; - break; - } - } - spin_unlock_irqrestore(&card->lock, flags); - - if (!t) { - timed_out: - fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", - source, tlabel); - return; - } - - /* - * FIXME: sanity check packet, is length correct, does tcodes - * and addresses match. - */ + // FIXME: sanity check packet, is length correct, does tcodes + // and addresses match to the transaction request queried later. + // + // For the tracepoints event, let us decode the header here against the concern. switch (tcode) { case TCODE_READ_QUADLET_RESPONSE: @@ -1061,6 +1039,30 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(iter, &card->transaction_list, link) { + if (iter->node_id == source && iter->tlabel == tlabel) { + if (!try_cancel_split_timeout(iter)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } + list_del_init(&iter->link); + card->tlabel_mask &= ~(1ULL << iter->tlabel); + t = iter; + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + trace_async_response_inbound(card, t, p, data, data_length / 4); + + if (!t) { + timed_out: + fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", + source, tlabel); + return; + } + /* * The response handler may be executed while the request handler * is still pending. Cancel the request handler. diff --git a/drivers/firewire/trace.h b/drivers/firewire/trace.h index 0f7d176ba647..5187f5f2b140 100644 --- a/drivers/firewire/trace.h +++ b/drivers/firewire/trace.h @@ -88,6 +88,54 @@ TRACE_EVENT(async_request_outbound_complete, ) ) +TRACE_EVENT(async_response_inbound, + TP_PROTO(const struct fw_card *card, const struct fw_transaction *transaction, + const struct fw_packet *packet, u32 *data, unsigned int data_count), + TP_ARGS(card, transaction, packet, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, scode) + __field(u8, generation) + __field(u16, timestamp) + __field(u16, destination) + __field(u8, tlabel) + __field(u8, retry) + __field(u8, tcode) + __field(u8, priority) + __field(u16, source) + __field(u8, rcode) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = (u64)transaction; + __entry->scode = packet->speed; + __entry->timestamp = packet->timestamp; + __entry->destination = async_header_get_destination(packet->header); + __entry->tlabel = async_header_get_tlabel(packet->header); + __entry->retry = async_header_get_retry(packet->header); + __entry->tcode = async_header_get_tcode(packet->header); + __entry->priority = async_header_get_priority(packet->header); + __entry->source = async_header_get_source(packet->header); + __entry->rcode = async_header_get_rcode(packet->header); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + TP_printk( + "transaction=0x%llx scode=%u timestamp=0x%04x dst_id=0x%04x tlabel=%u retry=%u tcode=%u priority=%u src_id=0x%04x rcode=%u data=%s", + __entry->transaction, + __entry->scode, + __entry->timestamp, + __entry->destination, + __entry->tlabel, + __entry->retry, + __entry->tcode, + __entry->priority, + __entry->source, + __entry->rcode, + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / sizeof(u32), sizeof(u32)) + ) +) + #endif // _FIREWIRE_TRACE_EVENT_H #define TRACE_INCLUDE_PATH . -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:23:58
|
This commit adds an event for asynchronous inbound request. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-transaction.c | 8 ++++- drivers/firewire/trace.h | 54 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 977d8a36f969..1b972e95fe36 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -972,11 +972,13 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) { struct fw_request *request; unsigned long long offset; + unsigned int tcode; if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (tcode_is_link_internal(async_header_get_tcode(p->header))) { + tcode = async_header_get_tcode(p->header); + if (tcode_is_link_internal(tcode)) { fw_cdev_handle_phy_packet(card, p); return; } @@ -987,6 +989,10 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) return; } + trace_async_request_inbound(card, request, p->ack, p->speed, p->timestamp, p->generation, + p->header, request->data, + tcode_is_read_request(tcode) ? 0 : request->length / 4); + offset = async_header_get_offset(p->header); if (!is_in_fcp_region(offset, request->length)) diff --git a/drivers/firewire/trace.h b/drivers/firewire/trace.h index 5187f5f2b140..ba09eb720933 100644 --- a/drivers/firewire/trace.h +++ b/drivers/firewire/trace.h @@ -136,6 +136,60 @@ TRACE_EVENT(async_response_inbound, ) ) +TRACE_EVENT(async_request_inbound, + TP_PROTO(const struct fw_card *card, const struct fw_request *request, unsigned int ack, + unsigned int scode, unsigned int timestamp, unsigned int generation, + const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(card, request, ack, scode, timestamp, generation, header, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, scode) + __field(u8, ack) + __field(u8, generation) + __field(u16, timestamp) + __field(u16, destination) + __field(u8, tlabel) + __field(u8, retry) + __field(u8, tcode) + __field(u8, priority) + __field(u16, source) + __field(u64, offset) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = (u64)request; + __entry->scode = scode; + __entry->ack = ack; + __entry->generation = generation; + __entry->timestamp = timestamp; + __entry->destination = async_header_get_destination(header); + __entry->tlabel = async_header_get_tlabel(header); + __entry->retry = async_header_get_retry(header); + __entry->tcode = async_header_get_tcode(header); + __entry->priority = async_header_get_priority(header); + __entry->source = async_header_get_source(header); + __entry->offset = async_header_get_offset(header); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + TP_printk( + "transaction=0x%llx scode=%u ack=%u generation=%u timestamp=0x%04x dst_id=0x%04x tlabel=%u retry=%u tcode=%u priority=%u src_id=0x%04x offset=0x%012llx data=%s", + __entry->transaction, + __entry->scode, + __entry->ack, + __entry->generation, + __entry->timestamp, + __entry->destination, + __entry->tlabel, + __entry->retry, + __entry->tcode, + __entry->priority, + __entry->source, + __entry->offset, + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / sizeof(u32), sizeof(u32)) + ) +) + #endif // _FIREWIRE_TRACE_EVENT_H #define TRACE_INCLUDE_PATH . -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:23:58
|
The Linux Kernel Tracepoints framework is enough useful to trace packet data inbound to and outbound from core. This commit adds firewire subsystem to use the framework. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/Makefile | 5 ++++- drivers/firewire/trace.c | 5 +++++ drivers/firewire/trace.h | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 drivers/firewire/trace.c create mode 100644 drivers/firewire/trace.h diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index bbde29a0fba6..92376e045805 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -3,12 +3,15 @@ # Makefile for the Linux IEEE 1394 implementation # -firewire-core-y += core-card.o core-cdev.o core-device.o \ +firewire-core-y += trace.o core-card.o core-cdev.o core-device.o \ core-iso.o core-topology.o core-transaction.o firewire-ohci-y += ohci.o firewire-sbp2-y += sbp2.o firewire-net-y += net.o +# Let "include/trace/define_trace.h" find the header. +CFLAGS_trace.o := -I$(src) + obj-$(CONFIG_FIREWIRE) += firewire-core.o obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o diff --git a/drivers/firewire/trace.c b/drivers/firewire/trace.c new file mode 100644 index 000000000000..ffe427764a90 --- /dev/null +++ b/drivers/firewire/trace.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/firewire/trace.h b/drivers/firewire/trace.h new file mode 100644 index 000000000000..d36a10460301 --- /dev/null +++ b/drivers/firewire/trace.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define TRACE_SYSTEM firewire + +#if !defined(_FIREWIRE_TRACE_EVENT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _FIREWIRE_TRACE_EVENT_H + +#include <linux/tracepoint.h> + +// Placeholder for future use. + +#endif // _FIREWIRE_TRACE_EVENT_H + +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace +#include <trace/define_trace.h> -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:23:48
|
This commit uses the common inline functions to serialize and deserialize header for asynchronous packet. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 38d19410a2be..5254cf5c2e58 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -40,6 +40,7 @@ #include "core.h" #include "ohci.h" +#include "packet-header-definitions.h" #define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) #define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) @@ -1550,21 +1551,15 @@ static int handle_at_packet(struct context *context, return 1; } -#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) -#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) -#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - static void handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) { struct fw_packet response; int tcode, length, i; - tcode = HEADER_GET_TCODE(packet->header[0]); + tcode = async_header_get_tcode(packet->header); if (TCODE_IS_BLOCK_PACKET(tcode)) - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + length = async_header_get_data_length(packet->header); else length = 4; @@ -1591,10 +1586,10 @@ static void handle_local_lock(struct fw_ohci *ohci, __be32 *payload, lock_old; u32 lock_arg, lock_data; - tcode = HEADER_GET_TCODE(packet->header[0]); - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + tcode = async_header_get_tcode(packet->header); + length = async_header_get_data_length(packet->header); payload = packet->payload; - ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]); + ext_tcode = async_header_get_extended_tcode(packet->header); if (tcode == TCODE_LOCK_REQUEST && ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) { @@ -1640,10 +1635,7 @@ static void handle_local_request(struct context *ctx, struct fw_packet *packet) packet->callback(packet, &ctx->ohci->card, packet->ack); } - offset = - ((unsigned long long) - HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) | - packet->header[2]; + offset = async_header_get_offset(packet->header); csr = offset - CSR_REGISTER_BASE; /* Handle config rom reads. */ @@ -1679,7 +1671,7 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) spin_lock_irqsave(&ctx->ohci->lock, flags); - if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id && + if (async_header_get_destination(packet->header) == ctx->ohci->node_id && ctx->ohci->generation == packet->generation) { spin_unlock_irqrestore(&ctx->ohci->lock, flags); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-04-18 09:23:45
|
The packet for Asynchronous Streaming Packet includes the same header fields as the isochronous packet has. It is helpful to have some helper functions to serialize/deserialize them. This commit adds such helper functions with their test. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/packet-header-definitions.h | 66 ++++++++++++++++++++ drivers/firewire/packet-serdes-test.c | 44 +++++++++++++ 2 files changed, 110 insertions(+) diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h index 83e550427706..ab9d0fa790d4 100644 --- a/drivers/firewire/packet-header-definitions.h +++ b/drivers/firewire/packet-header-definitions.h @@ -165,4 +165,70 @@ static inline void async_header_set_extended_tcode(u32 header[ASYNC_HEADER_QUADL header[3] |= (((u32)extended_tcode) << ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT) & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; } +#define ISOC_HEADER_DATA_LENGTH_SHIFT 16 +#define ISOC_HEADER_DATA_LENGTH_MASK 0xffff0000 +#define ISOC_HEADER_TAG_SHIFT 14 +#define ISOC_HEADER_TAG_MASK 0x0000c000 +#define ISOC_HEADER_CHANNEL_SHIFT 8 +#define ISOC_HEADER_CHANNEL_MASK 0x00003f00 +#define ISOC_HEADER_TCODE_SHIFT 4 +#define ISOC_HEADER_TCODE_MASK 0x000000f0 +#define ISOC_HEADER_SY_SHIFT 0 +#define ISOC_HEADER_SY_MASK 0x0000000f + +static inline unsigned int isoc_header_get_data_length(u32 header) +{ + return (header & ISOC_HEADER_DATA_LENGTH_MASK) >> ISOC_HEADER_DATA_LENGTH_SHIFT; +} + +static inline unsigned int isoc_header_get_tag(u32 header) +{ + return (header & ISOC_HEADER_TAG_MASK) >> ISOC_HEADER_TAG_SHIFT; +} + +static inline unsigned int isoc_header_get_channel(u32 header) +{ + return (header & ISOC_HEADER_CHANNEL_MASK) >> ISOC_HEADER_CHANNEL_SHIFT; +} + +static inline unsigned int isoc_header_get_tcode(u32 header) +{ + return (header & ISOC_HEADER_TCODE_MASK) >> ISOC_HEADER_TCODE_SHIFT; +} + +static inline unsigned int isoc_header_get_sy(u32 header) +{ + return (header & ISOC_HEADER_SY_MASK) >> ISOC_HEADER_SY_SHIFT; +} + +static inline void isoc_header_set_data_length(u32 *header, unsigned int data_length) +{ + *header &= ~ISOC_HEADER_DATA_LENGTH_MASK; + *header |= (((u32)data_length) << ISOC_HEADER_DATA_LENGTH_SHIFT) & ISOC_HEADER_DATA_LENGTH_MASK; +} + +static inline void isoc_header_set_tag(u32 *header, unsigned int tag) +{ + *header &= ~ISOC_HEADER_TAG_MASK; + *header |= (((u32)tag) << ISOC_HEADER_TAG_SHIFT) & ISOC_HEADER_TAG_MASK; +} + +static inline void isoc_header_set_channel(u32 *header, unsigned int channel) +{ + *header &= ~ISOC_HEADER_CHANNEL_MASK; + *header |= (((u32)channel) << ISOC_HEADER_CHANNEL_SHIFT) & ISOC_HEADER_CHANNEL_MASK; +} + +static inline void isoc_header_set_tcode(u32 *header, unsigned int tcode) +{ + *header &= ~ISOC_HEADER_TCODE_MASK; + *header |= (((u32)tcode) << ISOC_HEADER_TCODE_SHIFT) & ISOC_HEADER_TCODE_MASK; +} + +static inline void isoc_header_set_sy(u32 *header, unsigned int sy) +{ + *header &= ~ISOC_HEADER_SY_MASK; + *header |= (((u32)sy) << ISOC_HEADER_SY_SHIFT) & ISOC_HEADER_SY_MASK; +} + #endif // _FIREWIRE_PACKET_HEADER_DEFINITIONS_H diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c index 299e9f908463..f93c966e794d 100644 --- a/drivers/firewire/packet-serdes-test.c +++ b/drivers/firewire/packet-serdes-test.c @@ -167,6 +167,26 @@ static void deserialize_async_header_block_response(const u32 header[ASYNC_HEADE *extended_tcode = async_header_get_extended_tcode(header); } +static void serialize_isoc_header(u32 *header, unsigned int data_length, unsigned int tag, + unsigned int channel, unsigned int tcode, unsigned int sy) +{ + isoc_header_set_data_length(header, data_length); + isoc_header_set_tag(header, tag); + isoc_header_set_channel(header, channel); + isoc_header_set_tcode(header, tcode); + isoc_header_set_sy(header, sy); +} + +static void deserialize_isoc_header(u32 header, unsigned int *data_length, unsigned int *tag, + unsigned int *channel, unsigned int *tcode, unsigned int *sy) +{ + *data_length = isoc_header_get_data_length(header); + *tag = isoc_header_get_tag(header); + *channel = isoc_header_get_channel(header); + *tcode = isoc_header_get_tcode(header); + *sy = isoc_header_get_sy(header); +} + static void test_async_header_write_quadlet_request(struct kunit *test) { static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { @@ -515,6 +535,29 @@ static void test_async_header_lock_response(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); } +static void test_isoc_header(struct kunit *test) +{ + const u32 expected = 0x00d08dec; + u32 header = 0; + + unsigned int data_length; + unsigned int tag; + unsigned int channel; + unsigned int tcode; + unsigned int sy; + + deserialize_isoc_header(expected, &data_length, &tag, &channel, &tcode, &sy); + + KUNIT_EXPECT_EQ(test, 0xd0, data_length); + KUNIT_EXPECT_EQ(test, 0x02, tag); + KUNIT_EXPECT_EQ(test, 0x0d, channel); + KUNIT_EXPECT_EQ(test, 0x0e, tcode); + KUNIT_EXPECT_EQ(test, 0x0c, sy); + + serialize_isoc_header(&header, data_length, tag, channel, tcode, sy); + + KUNIT_EXPECT_EQ(test, header, expected); +} static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_write_quadlet_request), @@ -526,6 +569,7 @@ static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_read_block_response), KUNIT_CASE(test_async_header_lock_request), KUNIT_CASE(test_async_header_lock_response), + KUNIT_CASE(test_isoc_header), {} }; -- 2.43.0 |