Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -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)
{
@@ -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;
			}
@@ -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)
{
@@ -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:
@@ -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;

@@ -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;
			}
+1 −1
Original line number Diff line number Diff line
@@ -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;