Commit 410cf2bd authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Stefan Richter

firewire: use split transaction timeout only for split transactions

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: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 693a50b5
...@@ -72,6 +72,15 @@ ...@@ -72,6 +72,15 @@
#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
#define PHY_IDENTIFIER(id) ((id) << 30) #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, static int close_transaction(struct fw_transaction *transaction,
struct fw_card *card, int rcode) struct fw_card *card, int rcode)
{ {
...@@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction, ...@@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction,
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) { list_for_each_entry(t, &card->transaction_list, link) {
if (t == transaction) { if (t == transaction) {
if (!del_timer(&t->split_timeout_timer)) { if (!try_cancel_split_timeout(t)) {
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
goto timed_out; goto timed_out;
} }
...@@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data) ...@@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data)
card->tlabel_mask &= ~(1ULL << t->tlabel); card->tlabel_mask &= ~(1ULL << t->tlabel);
spin_unlock_irqrestore(&card->lock, flags); 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); 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, static void transmit_complete_callback(struct fw_packet *packet,
struct fw_card *card, int status) struct fw_card *card, int status)
{ {
...@@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet, ...@@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
close_transaction(t, card, RCODE_COMPLETE); close_transaction(t, card, RCODE_COMPLETE);
break; break;
case ACK_PENDING: case ACK_PENDING:
t->timestamp = packet->timestamp; start_split_transaction_timeout(t, card);
break; break;
case ACK_BUSY_X: case ACK_BUSY_X:
case ACK_BUSY_A: case ACK_BUSY_A:
...@@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, ...@@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
t->node_id = destination_id; t->node_id = destination_id;
t->tlabel = tlabel; t->tlabel = tlabel;
t->card = card; t->card = card;
t->is_split_transaction = false;
setup_timer(&t->split_timeout_timer, setup_timer(&t->split_timeout_timer,
split_transaction_timeout_callback, (unsigned long)t); 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 = callback;
t->callback_data = callback_data; t->callback_data = callback_data;
...@@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) ...@@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) { list_for_each_entry(t, &card->transaction_list, link) {
if (t->node_id == source && t->tlabel == tlabel) { 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); spin_unlock_irqrestore(&card->lock, flags);
goto timed_out; goto timed_out;
} }
......
...@@ -302,9 +302,9 @@ struct fw_packet { ...@@ -302,9 +302,9 @@ struct fw_packet {
struct fw_transaction { struct fw_transaction {
int node_id; /* The generation is implied; it is always the current. */ int node_id; /* The generation is implied; it is always the current. */
int tlabel; int tlabel;
int timestamp;
struct list_head link; struct list_head link;
struct fw_card *card; struct fw_card *card;
bool is_split_transaction;
struct timer_list split_timeout_timer; struct timer_list split_timeout_timer;
struct fw_packet packet; struct fw_packet packet;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment