Skip to content

Commit

Permalink
firewire: use split transaction timeout only for split transactions
Browse files Browse the repository at this point in the history
Instead of starting the split transaction timeout timer when any request
is submitted, start it only when the destination's ACK_PENDING has been
received.  This prevents us from using a timeout that is too short, and,
if the controller's AT queue is emptying very slowly, from cancelling
a packet that has not yet been sent.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
  • Loading branch information
Clemens Ladisch authored and Stefan Richter committed Jan 4, 2011
1 parent 693a50b commit 410cf2b
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 14 deletions.
45 changes: 32 additions & 13 deletions drivers/firewire/core-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@
#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
#define PHY_IDENTIFIER(id) ((id) << 30)

/* returns 0 if the split timeout handler is already running */
static int try_cancel_split_timeout(struct fw_transaction *t)
{
if (t->is_split_transaction)
return del_timer(&t->split_timeout_timer);
else
return 1;
}

static int close_transaction(struct fw_transaction *transaction,
struct fw_card *card, int rcode)
{
Expand All @@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction,
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) {
if (t == transaction) {
if (!del_timer(&t->split_timeout_timer)) {
if (!try_cancel_split_timeout(t)) {
spin_unlock_irqrestore(&card->lock, flags);
goto timed_out;
}
Expand Down Expand Up @@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data)
card->tlabel_mask &= ~(1ULL << t->tlabel);
spin_unlock_irqrestore(&card->lock, flags);

card->driver->cancel_packet(card, &t->packet);

/*
* At this point cancel_packet will never call the transaction
* callback, since we just took the transaction out of the list.
* So do it here.
*/
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
}

static void start_split_transaction_timeout(struct fw_transaction *t,
struct fw_card *card)
{
unsigned long flags;

spin_lock_irqsave(&card->lock, flags);

if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
spin_unlock_irqrestore(&card->lock, flags);
return;
}

t->is_split_transaction = true;
mod_timer(&t->split_timeout_timer,
jiffies + card->split_timeout_jiffies);

spin_unlock_irqrestore(&card->lock, flags);
}

static void transmit_complete_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
Expand All @@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
close_transaction(t, card, RCODE_COMPLETE);
break;
case ACK_PENDING:
t->timestamp = packet->timestamp;
start_split_transaction_timeout(t, card);
break;
case ACK_BUSY_X:
case ACK_BUSY_A:
Expand Down Expand Up @@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
t->node_id = destination_id;
t->tlabel = tlabel;
t->card = card;
t->is_split_transaction = false;
setup_timer(&t->split_timeout_timer,
split_transaction_timeout_callback, (unsigned long)t);
/* FIXME: start this timer later, relative to t->timestamp */
mod_timer(&t->split_timeout_timer,
jiffies + card->split_timeout_jiffies);
t->callback = callback;
t->callback_data = callback_data;

Expand Down Expand Up @@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) {
if (t->node_id == source && t->tlabel == tlabel) {
if (!del_timer(&t->split_timeout_timer)) {
if (!try_cancel_split_timeout(t)) {
spin_unlock_irqrestore(&card->lock, flags);
goto timed_out;
}
Expand Down
2 changes: 1 addition & 1 deletion include/linux/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,9 @@ struct fw_packet {
struct fw_transaction {
int node_id; /* The generation is implied; it is always the current. */
int tlabel;
int timestamp;
struct list_head link;
struct fw_card *card;
bool is_split_transaction;
struct timer_list split_timeout_timer;

struct fw_packet packet;
Expand Down

0 comments on commit 410cf2b

Please sign in to comment.