mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 22:26:55 +00:00
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: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
693a50b511
commit
410cf2bd3d
2 changed files with 33 additions and 14 deletions
|
@ -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,
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue