diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/firewire/core-transaction.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r-- | drivers/firewire/core-transaction.c | 77 |
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 */ | ||
77 | static 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 | |||
75 | static int close_transaction(struct fw_transaction *transaction, | 85 | static 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 | ||
157 | static 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 | |||
154 | static void transmit_complete_callback(struct fw_packet *packet, | 176 | static 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 | */ |
397 | int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, | 418 | int 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 | ||
425 | static struct fw_packet phy_config_packet = { | 446 | static 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 | ||