aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r--drivers/firewire/core-transaction.c77
1 files changed, 54 insertions, 23 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index b42a0bde8494..334b82a3542c 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -36,6 +36,7 @@
36#include <linux/string.h> 36#include <linux/string.h>
37#include <linux/timer.h> 37#include <linux/timer.h>
38#include <linux/types.h> 38#include <linux/types.h>
39#include <linux/workqueue.h>
39 40
40#include <asm/byteorder.h> 41#include <asm/byteorder.h>
41 42
@@ -72,6 +73,15 @@
72#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) 73#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
73#define PHY_IDENTIFIER(id) ((id) << 30) 74#define PHY_IDENTIFIER(id) ((id) << 30)
74 75
76/* returns 0 if the split timeout handler is already running */
77static int try_cancel_split_timeout(struct fw_transaction *t)
78{
79 if (t->is_split_transaction)
80 return del_timer(&t->split_timeout_timer);
81 else
82 return 1;
83}
84
75static int close_transaction(struct fw_transaction *transaction, 85static int close_transaction(struct fw_transaction *transaction,
76 struct fw_card *card, int rcode) 86 struct fw_card *card, int rcode)
77{ 87{
@@ -81,7 +91,7 @@ static int close_transaction(struct fw_transaction *transaction,
81 spin_lock_irqsave(&card->lock, flags); 91 spin_lock_irqsave(&card->lock, flags);
82 list_for_each_entry(t, &card->transaction_list, link) { 92 list_for_each_entry(t, &card->transaction_list, link) {
83 if (t == transaction) { 93 if (t == transaction) {
84 if (!del_timer(&t->split_timeout_timer)) { 94 if (!try_cancel_split_timeout(t)) {
85 spin_unlock_irqrestore(&card->lock, flags); 95 spin_unlock_irqrestore(&card->lock, flags);
86 goto timed_out; 96 goto timed_out;
87 } 97 }
@@ -141,16 +151,28 @@ static void split_transaction_timeout_callback(unsigned long data)
141 card->tlabel_mask &= ~(1ULL << t->tlabel); 151 card->tlabel_mask &= ~(1ULL << t->tlabel);
142 spin_unlock_irqrestore(&card->lock, flags); 152 spin_unlock_irqrestore(&card->lock, flags);
143 153
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); 154 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
152} 155}
153 156
157static void start_split_transaction_timeout(struct fw_transaction *t,
158 struct fw_card *card)
159{
160 unsigned long flags;
161
162 spin_lock_irqsave(&card->lock, flags);
163
164 if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
165 spin_unlock_irqrestore(&card->lock, flags);
166 return;
167 }
168
169 t->is_split_transaction = true;
170 mod_timer(&t->split_timeout_timer,
171 jiffies + card->split_timeout_jiffies);
172
173 spin_unlock_irqrestore(&card->lock, flags);
174}
175
154static void transmit_complete_callback(struct fw_packet *packet, 176static void transmit_complete_callback(struct fw_packet *packet,
155 struct fw_card *card, int status) 177 struct fw_card *card, int status)
156{ 178{
@@ -162,7 +184,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
162 close_transaction(t, card, RCODE_COMPLETE); 184 close_transaction(t, card, RCODE_COMPLETE);
163 break; 185 break;
164 case ACK_PENDING: 186 case ACK_PENDING:
165 t->timestamp = packet->timestamp; 187 start_split_transaction_timeout(t, card);
166 break; 188 break;
167 case ACK_BUSY_X: 189 case ACK_BUSY_X:
168 case ACK_BUSY_A: 190 case ACK_BUSY_A:
@@ -250,7 +272,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
250 break; 272 break;
251 273
252 default: 274 default:
253 WARN(1, "wrong tcode %d", tcode); 275 WARN(1, "wrong tcode %d\n", tcode);
254 } 276 }
255 common: 277 common:
256 packet->speed = speed; 278 packet->speed = speed;
@@ -305,8 +327,8 @@ static int allocate_tlabel(struct fw_card *card)
305 * It will contain tag, channel, and sy data instead of a node ID then. 327 * It will contain tag, channel, and sy data instead of a node ID then.
306 * 328 *
307 * The payload buffer at @data is going to be DMA-mapped except in case of 329 * The payload buffer at @data is going to be DMA-mapped except in case of
308 * quadlet-sized payload or of local (loopback) requests. Hence make sure that 330 * @length <= 8 or of local (loopback) requests. Hence make sure that the
309 * the buffer complies with the restrictions for DMA-mapped memory. The 331 * buffer complies with the restrictions of the streaming DMA mapping API.
310 * @payload must not be freed before the @callback is called. 332 * @payload must not be freed before the @callback is called.
311 * 333 *
312 * In case of request types without payload, @data is NULL and @length is 0. 334 * In case of request types without payload, @data is NULL and @length is 0.
@@ -349,11 +371,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
349 t->node_id = destination_id; 371 t->node_id = destination_id;
350 t->tlabel = tlabel; 372 t->tlabel = tlabel;
351 t->card = card; 373 t->card = card;
374 t->is_split_transaction = false;
352 setup_timer(&t->split_timeout_timer, 375 setup_timer(&t->split_timeout_timer,
353 split_transaction_timeout_callback, (unsigned long)t); 376 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; 377 t->callback = callback;
358 t->callback_data = callback_data; 378 t->callback_data = callback_data;
359 379
@@ -392,7 +412,8 @@ static void transaction_callback(struct fw_card *card, int rcode,
392 * 412 *
393 * Returns the RCODE. See fw_send_request() for parameter documentation. 413 * Returns the RCODE. See fw_send_request() for parameter documentation.
394 * Unlike fw_send_request(), @data points to the payload of the request or/and 414 * Unlike fw_send_request(), @data points to the payload of the request or/and
395 * to the payload of the response. 415 * to the payload of the response. DMA mapping restrictions apply to outbound
416 * request payloads of >= 8 bytes but not to inbound response payloads.
396 */ 417 */
397int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, 418int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
398 int generation, int speed, unsigned long long offset, 419 int generation, int speed, unsigned long long offset,
@@ -423,7 +444,8 @@ static void transmit_phy_packet_callback(struct fw_packet *packet,
423} 444}
424 445
425static struct fw_packet phy_config_packet = { 446static struct fw_packet phy_config_packet = {
426 .header_length = 8, 447 .header_length = 12,
448 .header[0] = TCODE_LINK_INTERNAL << 4,
427 .payload_length = 0, 449 .payload_length = 0,
428 .speed = SCODE_100, 450 .speed = SCODE_100,
429 .callback = transmit_phy_packet_callback, 451 .callback = transmit_phy_packet_callback,
@@ -451,8 +473,8 @@ void fw_send_phy_config(struct fw_card *card,
451 473
452 mutex_lock(&phy_config_mutex); 474 mutex_lock(&phy_config_mutex);
453 475
454 phy_config_packet.header[0] = data; 476 phy_config_packet.header[1] = data;
455 phy_config_packet.header[1] = ~data; 477 phy_config_packet.header[2] = ~data;
456 phy_config_packet.generation = generation; 478 phy_config_packet.generation = generation;
457 INIT_COMPLETION(phy_config_done); 479 INIT_COMPLETION(phy_config_done);
458 480
@@ -638,7 +660,7 @@ int fw_get_response_length(struct fw_request *r)
638 } 660 }
639 661
640 default: 662 default:
641 WARN(1, "wrong tcode %d", tcode); 663 WARN(1, "wrong tcode %d\n", tcode);
642 return 0; 664 return 0;
643 } 665 }
644} 666}
@@ -694,7 +716,7 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
694 break; 716 break;
695 717
696 default: 718 default:
697 WARN(1, "wrong tcode %d", tcode); 719 WARN(1, "wrong tcode %d\n", tcode);
698 } 720 }
699 721
700 response->payload_mapped = false; 722 response->payload_mapped = false;
@@ -925,7 +947,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
925 spin_lock_irqsave(&card->lock, flags); 947 spin_lock_irqsave(&card->lock, flags);
926 list_for_each_entry(t, &card->transaction_list, link) { 948 list_for_each_entry(t, &card->transaction_list, link) {
927 if (t->node_id == source && t->tlabel == tlabel) { 949 if (t->node_id == source && t->tlabel == tlabel) {
928 if (!del_timer(&t->split_timeout_timer)) { 950 if (!try_cancel_split_timeout(t)) {
929 spin_unlock_irqrestore(&card->lock, flags); 951 spin_unlock_irqrestore(&card->lock, flags);
930 goto timed_out; 952 goto timed_out;
931 } 953 }
@@ -1192,13 +1214,21 @@ static int __init fw_core_init(void)
1192{ 1214{
1193 int ret; 1215 int ret;
1194 1216
1217 fw_workqueue = alloc_workqueue("firewire",
1218 WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
1219 if (!fw_workqueue)
1220 return -ENOMEM;
1221
1195 ret = bus_register(&fw_bus_type); 1222 ret = bus_register(&fw_bus_type);
1196 if (ret < 0) 1223 if (ret < 0) {
1224 destroy_workqueue(fw_workqueue);
1197 return ret; 1225 return ret;
1226 }
1198 1227
1199 fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); 1228 fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
1200 if (fw_cdev_major < 0) { 1229 if (fw_cdev_major < 0) {
1201 bus_unregister(&fw_bus_type); 1230 bus_unregister(&fw_bus_type);
1231 destroy_workqueue(fw_workqueue);
1202 return fw_cdev_major; 1232 return fw_cdev_major;
1203 } 1233 }
1204 1234
@@ -1214,6 +1244,7 @@ static void __exit fw_core_cleanup(void)
1214{ 1244{
1215 unregister_chrdev(fw_cdev_major, "firewire"); 1245 unregister_chrdev(fw_cdev_major, "firewire");
1216 bus_unregister(&fw_bus_type); 1246 bus_unregister(&fw_bus_type);
1247 destroy_workqueue(fw_workqueue);
1217 idr_destroy(&fw_device_idr); 1248 idr_destroy(&fw_device_idr);
1218} 1249}
1219 1250