diff options
| -rw-r--r-- | drivers/firewire/core-transaction.c | 45 | ||||
| -rw-r--r-- | include/linux/firewire.h | 2 |
2 files changed, 33 insertions, 14 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 9e81cc54abd2..d00f8ce902cc 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c | |||
| @@ -72,6 +72,15 @@ | |||
| 72 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) | 72 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) |
| 73 | #define PHY_IDENTIFIER(id) ((id) << 30) | 73 | #define PHY_IDENTIFIER(id) ((id) << 30) |
| 74 | 74 | ||
| 75 | /* returns 0 if the split timeout handler is already running */ | ||
| 76 | static int try_cancel_split_timeout(struct fw_transaction *t) | ||
| 77 | { | ||
| 78 | if (t->is_split_transaction) | ||
| 79 | return del_timer(&t->split_timeout_timer); | ||
| 80 | else | ||
| 81 | return 1; | ||
| 82 | } | ||
| 83 | |||
| 75 | static int close_transaction(struct fw_transaction *transaction, | 84 | static int close_transaction(struct fw_transaction *transaction, |
| 76 | struct fw_card *card, int rcode) | 85 | struct fw_card *card, int rcode) |
| 77 | { | 86 | { |
| @@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction, | |||
| 81 | spin_lock_irqsave(&card->lock, flags); | 90 | spin_lock_irqsave(&card->lock, flags); |
| 82 | list_for_each_entry(t, &card->transaction_list, link) { | 91 | list_for_each_entry(t, &card->transaction_list, link) { |
| 83 | if (t == transaction) { | 92 | if (t == transaction) { |
| 84 | if (!del_timer(&t->split_timeout_timer)) { | 93 | if (!try_cancel_split_timeout(t)) { |
| 85 | spin_unlock_irqrestore(&card->lock, flags); | 94 | spin_unlock_irqrestore(&card->lock, flags); |
| 86 | goto timed_out; | 95 | goto timed_out; |
| 87 | } | 96 | } |
| @@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data) | |||
| 141 | card->tlabel_mask &= ~(1ULL << t->tlabel); | 150 | card->tlabel_mask &= ~(1ULL << t->tlabel); |
| 142 | spin_unlock_irqrestore(&card->lock, flags); | 151 | spin_unlock_irqrestore(&card->lock, flags); |
| 143 | 152 | ||
| 144 | card->driver->cancel_packet(card, &t->packet); | ||
| 145 | |||
| 146 | /* | ||
| 147 | * At this point cancel_packet will never call the transaction | ||
| 148 | * callback, since we just took the transaction out of the list. | ||
| 149 | * So do it here. | ||
| 150 | */ | ||
| 151 | t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); | 153 | t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 156 | static void start_split_transaction_timeout(struct fw_transaction *t, | ||
| 157 | struct fw_card *card) | ||
| 158 | { | ||
| 159 | unsigned long flags; | ||
| 160 | |||
| 161 | spin_lock_irqsave(&card->lock, flags); | ||
| 162 | |||
| 163 | if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) { | ||
| 164 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | |||
| 168 | t->is_split_transaction = true; | ||
| 169 | mod_timer(&t->split_timeout_timer, | ||
| 170 | jiffies + card->split_timeout_jiffies); | ||
| 171 | |||
| 172 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 173 | } | ||
| 174 | |||
| 154 | static void transmit_complete_callback(struct fw_packet *packet, | 175 | static void transmit_complete_callback(struct fw_packet *packet, |
| 155 | struct fw_card *card, int status) | 176 | struct fw_card *card, int status) |
| 156 | { | 177 | { |
| @@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet, | |||
| 162 | close_transaction(t, card, RCODE_COMPLETE); | 183 | close_transaction(t, card, RCODE_COMPLETE); |
| 163 | break; | 184 | break; |
| 164 | case ACK_PENDING: | 185 | case ACK_PENDING: |
| 165 | t->timestamp = packet->timestamp; | 186 | start_split_transaction_timeout(t, card); |
| 166 | break; | 187 | break; |
| 167 | case ACK_BUSY_X: | 188 | case ACK_BUSY_X: |
| 168 | case ACK_BUSY_A: | 189 | case ACK_BUSY_A: |
| @@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | |||
| 349 | t->node_id = destination_id; | 370 | t->node_id = destination_id; |
| 350 | t->tlabel = tlabel; | 371 | t->tlabel = tlabel; |
| 351 | t->card = card; | 372 | t->card = card; |
| 373 | t->is_split_transaction = false; | ||
| 352 | setup_timer(&t->split_timeout_timer, | 374 | setup_timer(&t->split_timeout_timer, |
| 353 | split_transaction_timeout_callback, (unsigned long)t); | 375 | split_transaction_timeout_callback, (unsigned long)t); |
| 354 | /* FIXME: start this timer later, relative to t->timestamp */ | ||
| 355 | mod_timer(&t->split_timeout_timer, | ||
| 356 | jiffies + card->split_timeout_jiffies); | ||
| 357 | t->callback = callback; | 376 | t->callback = callback; |
| 358 | t->callback_data = callback_data; | 377 | t->callback_data = callback_data; |
| 359 | 378 | ||
| @@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | |||
| 926 | spin_lock_irqsave(&card->lock, flags); | 945 | spin_lock_irqsave(&card->lock, flags); |
| 927 | list_for_each_entry(t, &card->transaction_list, link) { | 946 | list_for_each_entry(t, &card->transaction_list, link) { |
| 928 | if (t->node_id == source && t->tlabel == tlabel) { | 947 | if (t->node_id == source && t->tlabel == tlabel) { |
| 929 | if (!del_timer(&t->split_timeout_timer)) { | 948 | if (!try_cancel_split_timeout(t)) { |
| 930 | spin_unlock_irqrestore(&card->lock, flags); | 949 | spin_unlock_irqrestore(&card->lock, flags); |
| 931 | goto timed_out; | 950 | goto timed_out; |
| 932 | } | 951 | } |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 1cd637ef62d2..9a3f5f9383f6 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
| @@ -302,9 +302,9 @@ struct fw_packet { | |||
| 302 | struct fw_transaction { | 302 | struct fw_transaction { |
| 303 | int node_id; /* The generation is implied; it is always the current. */ | 303 | int node_id; /* The generation is implied; it is always the current. */ |
| 304 | int tlabel; | 304 | int tlabel; |
| 305 | int timestamp; | ||
| 306 | struct list_head link; | 305 | struct list_head link; |
| 307 | struct fw_card *card; | 306 | struct fw_card *card; |
| 307 | bool is_split_transaction; | ||
| 308 | struct timer_list split_timeout_timer; | 308 | struct timer_list split_timeout_timer; |
| 309 | 309 | ||
| 310 | struct fw_packet packet; | 310 | struct fw_packet packet; |
