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
	
	 Clemens Ladisch
				Clemens Ladisch