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…
	
	Add table
		Add a link
		
	
		Reference in a new issue