Skip to content

Commit dcadfd7

Browse files
committed
firewire: core: use union for callback of transaction completion
In 1394 OHCI, the OUTPUT_LAST descriptor of Asynchronous Transmit (AT) request context has timeStamp field, in which 1394 OHCI controller record the isochronous cycle when the packet was sent for the request subaction. Additionally, for the case of split transaction in IEEE 1394, Asynchronous Receive (AT) request context is used for response subaction to finish the transaction. The trailer quadlet of descriptor in the context has timeStamp field, in which 1394 OHCI controller records the isochronous cycle when the packet arrived. Current implementation of 1394 OHCI controller driver stores values of both fields to internal structure as time stamp, while Linux FireWire subsystem provides no way to access to it. When using asynchronous transaction service provided by the subsystem, callback function is passed to kernel API. The prototype of callback function has the lack of argument for the values. This commit adds a new callback function for the purpose. It has an additional argument to point to the constant array with two elements. For backward compatibility to kernel space, a new union is also adds to wrap two different prototype of callback function. The fw_transaction structure has the union as a member and a boolean flag to express which function callback is available. The core function is changed to handle the two cases; with or without time stamp. For the error path to process transaction, the isochronous cycle is computed by current value of CYCLE_TIMER register in 1394 OHCI controller. Especially for the case of timeout of split transaction, the expected isochronous cycle is computed. Link: https://lore.kernel.org/r/20230529113406.986289-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
1 parent 865efff commit dcadfd7

File tree

4 files changed

+80
-15
lines changed

4 files changed

+80
-15
lines changed

drivers/firewire/core-transaction.c

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ static int try_cancel_split_timeout(struct fw_transaction *t)
7070
return 1;
7171
}
7272

73-
static int close_transaction(struct fw_transaction *transaction,
74-
struct fw_card *card, int rcode)
73+
static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode,
74+
u32 response_tstamp)
7575
{
7676
struct fw_transaction *t = NULL, *iter;
7777
unsigned long flags;
@@ -92,7 +92,12 @@ static int close_transaction(struct fw_transaction *transaction,
9292
spin_unlock_irqrestore(&card->lock, flags);
9393

9494
if (t) {
95-
t->callback(card, rcode, NULL, 0, t->callback_data);
95+
if (!t->with_tstamp) {
96+
t->callback.without_tstamp(card, rcode, NULL, 0, t->callback_data);
97+
} else {
98+
t->callback.with_tstamp(card, rcode, t->packet.timestamp, response_tstamp,
99+
NULL, 0, t->callback_data);
100+
}
96101
return 0;
97102
}
98103

@@ -107,6 +112,8 @@ static int close_transaction(struct fw_transaction *transaction,
107112
int fw_cancel_transaction(struct fw_card *card,
108113
struct fw_transaction *transaction)
109114
{
115+
u32 tstamp;
116+
110117
/*
111118
* Cancel the packet transmission if it's still queued. That
112119
* will call the packet transmission callback which cancels
@@ -121,7 +128,17 @@ int fw_cancel_transaction(struct fw_card *card,
121128
* if the transaction is still pending and remove it in that case.
122129
*/
123130

124-
return close_transaction(transaction, card, RCODE_CANCELLED);
131+
if (transaction->packet.ack == 0) {
132+
// The timestamp is reused since it was just read now.
133+
tstamp = transaction->packet.timestamp;
134+
} else {
135+
u32 curr_cycle_time = 0;
136+
137+
(void)fw_card_read_cycle_time(card, &curr_cycle_time);
138+
tstamp = cycle_time_to_ohci_tstamp(curr_cycle_time);
139+
}
140+
141+
return close_transaction(transaction, card, RCODE_CANCELLED, tstamp);
125142
}
126143
EXPORT_SYMBOL(fw_cancel_transaction);
127144

@@ -140,7 +157,12 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
140157
card->tlabel_mask &= ~(1ULL << t->tlabel);
141158
spin_unlock_irqrestore(&card->lock, flags);
142159

143-
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
160+
if (!t->with_tstamp) {
161+
t->callback.without_tstamp(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
162+
} else {
163+
t->callback.with_tstamp(card, RCODE_CANCELLED, t->packet.timestamp,
164+
t->split_timeout_cycle, NULL, 0, t->callback_data);
165+
}
144166
}
145167

146168
static void start_split_transaction_timeout(struct fw_transaction *t,
@@ -162,6 +184,8 @@ static void start_split_transaction_timeout(struct fw_transaction *t,
162184
spin_unlock_irqrestore(&card->lock, flags);
163185
}
164186

187+
static u32 compute_split_timeout_timestamp(struct fw_card *card, u32 request_timestamp);
188+
165189
static void transmit_complete_callback(struct fw_packet *packet,
166190
struct fw_card *card, int status)
167191
{
@@ -170,28 +194,32 @@ static void transmit_complete_callback(struct fw_packet *packet,
170194

171195
switch (status) {
172196
case ACK_COMPLETE:
173-
close_transaction(t, card, RCODE_COMPLETE);
197+
close_transaction(t, card, RCODE_COMPLETE, packet->timestamp);
174198
break;
175199
case ACK_PENDING:
200+
{
201+
t->split_timeout_cycle =
202+
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
176203
start_split_transaction_timeout(t, card);
177204
break;
205+
}
178206
case ACK_BUSY_X:
179207
case ACK_BUSY_A:
180208
case ACK_BUSY_B:
181-
close_transaction(t, card, RCODE_BUSY);
209+
close_transaction(t, card, RCODE_BUSY, packet->timestamp);
182210
break;
183211
case ACK_DATA_ERROR:
184-
close_transaction(t, card, RCODE_DATA_ERROR);
212+
close_transaction(t, card, RCODE_DATA_ERROR, packet->timestamp);
185213
break;
186214
case ACK_TYPE_ERROR:
187-
close_transaction(t, card, RCODE_TYPE_ERROR);
215+
close_transaction(t, card, RCODE_TYPE_ERROR, packet->timestamp);
188216
break;
189217
default:
190218
/*
191219
* In this case the ack is really a juju specific
192220
* rcode, so just forward that to the callback.
193221
*/
194-
close_transaction(t, card, status);
222+
close_transaction(t, card, status, packet->timestamp);
195223
break;
196224
}
197225
}
@@ -363,7 +391,8 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
363391
t->is_split_transaction = false;
364392
timer_setup(&t->split_timeout_timer,
365393
split_transaction_timeout_callback, 0);
366-
t->callback = callback;
394+
t->callback.without_tstamp = callback;
395+
t->with_tstamp = false;
367396
t->callback_data = callback_data;
368397

369398
fw_fill_request(&t->packet, tcode, t->tlabel,
@@ -1047,7 +1076,12 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
10471076
*/
10481077
card->driver->cancel_packet(card, &t->packet);
10491078

1050-
t->callback(card, rcode, data, data_length, t->callback_data);
1079+
if (!t->with_tstamp) {
1080+
t->callback.without_tstamp(card, rcode, data, data_length, t->callback_data);
1081+
} else {
1082+
t->callback.with_tstamp(card, rcode, t->packet.timestamp, p->timestamp, data,
1083+
data_length, t->callback_data);
1084+
}
10511085
}
10521086
EXPORT_SYMBOL(fw_core_handle_response);
10531087

drivers/firewire/core.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
247247
void fw_request_get(struct fw_request *request);
248248
void fw_request_put(struct fw_request *request);
249249

250+
// Convert the value of IEEE 1394 CYCLE_TIME register to the format of timeStamp field in
251+
// descriptors of 1394 OHCI.
252+
static inline u32 cycle_time_to_ohci_tstamp(u32 tstamp)
253+
{
254+
return (tstamp & 0x0ffff000) >> 12;
255+
}
256+
250257
#define FW_PHY_CONFIG_NO_NODE_ID -1
251258
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
252259
void fw_send_phy_config(struct fw_card *card,

drivers/firewire/ohci.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,8 @@ static void handle_local_request(struct context *ctx, struct fw_packet *packet)
16231623
}
16241624
}
16251625

1626+
static u32 get_cycle_time(struct fw_ohci *ohci);
1627+
16261628
static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
16271629
{
16281630
unsigned long flags;
@@ -1633,16 +1635,23 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
16331635
if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id &&
16341636
ctx->ohci->generation == packet->generation) {
16351637
spin_unlock_irqrestore(&ctx->ohci->lock, flags);
1638+
1639+
// Timestamping on behalf of the hardware.
1640+
packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ctx->ohci));
1641+
16361642
handle_local_request(ctx, packet);
16371643
return;
16381644
}
16391645

16401646
ret = at_context_queue_packet(ctx, packet);
16411647
spin_unlock_irqrestore(&ctx->ohci->lock, flags);
16421648

1643-
if (ret < 0)
1644-
packet->callback(packet, &ctx->ohci->card, packet->ack);
1649+
if (ret < 0) {
1650+
// Timestamping on behalf of the hardware.
1651+
packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ctx->ohci));
16451652

1653+
packet->callback(packet, &ctx->ohci->card, packet->ack);
1654+
}
16461655
}
16471656

16481657
static void detect_dead_context(struct fw_ohci *ohci,
@@ -2557,6 +2566,10 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
25572566
log_ar_at_event(ohci, 'T', packet->speed, packet->header, 0x20);
25582567
driver_data->packet = NULL;
25592568
packet->ack = RCODE_CANCELLED;
2569+
2570+
// Timestamping on behalf of the hardware.
2571+
packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
2572+
25602573
packet->callback(packet, &ohci->card, packet->ack);
25612574
ret = 0;
25622575
out:

include/linux/firewire.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,15 @@ typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
261261
typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
262262
void *data, size_t length,
263263
void *callback_data);
264+
typedef void (*fw_transaction_callback_with_tstamp_t)(struct fw_card *card, int rcode,
265+
u32 request_tstamp, u32 response_tstamp, void *data,
266+
size_t length, void *callback_data);
267+
268+
union fw_transaction_callback {
269+
fw_transaction_callback_t without_tstamp;
270+
fw_transaction_callback_with_tstamp_t with_tstamp;
271+
};
272+
264273
/*
265274
* This callback handles an inbound request subaction. It is called in
266275
* RCU read-side context, therefore must not sleep.
@@ -312,14 +321,16 @@ struct fw_transaction {
312321
struct fw_card *card;
313322
bool is_split_transaction;
314323
struct timer_list split_timeout_timer;
324+
u32 split_timeout_cycle;
315325

316326
struct fw_packet packet;
317327

318328
/*
319329
* The data passed to the callback is valid only during the
320330
* callback.
321331
*/
322-
fw_transaction_callback_t callback;
332+
union fw_transaction_callback callback;
333+
bool with_tstamp;
323334
void *callback_data;
324335
};
325336

0 commit comments

Comments
 (0)