diff options
Diffstat (limited to 'drivers/firewire/fw-transaction.c')
-rw-r--r-- | drivers/firewire/fw-transaction.c | 185 |
1 files changed, 88 insertions, 97 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 699ac041f39a..283dac6d327d 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -64,10 +64,8 @@ | |||
64 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) | 64 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) |
65 | #define PHY_IDENTIFIER(id) ((id) << 30) | 65 | #define PHY_IDENTIFIER(id) ((id) << 30) |
66 | 66 | ||
67 | static int | 67 | static int close_transaction(struct fw_transaction *transaction, |
68 | close_transaction(struct fw_transaction *transaction, | 68 | struct fw_card *card, int rcode) |
69 | struct fw_card *card, int rcode, | ||
70 | u32 *payload, size_t length) | ||
71 | { | 69 | { |
72 | struct fw_transaction *t; | 70 | struct fw_transaction *t; |
73 | unsigned long flags; | 71 | unsigned long flags; |
@@ -83,7 +81,7 @@ close_transaction(struct fw_transaction *transaction, | |||
83 | spin_unlock_irqrestore(&card->lock, flags); | 81 | spin_unlock_irqrestore(&card->lock, flags); |
84 | 82 | ||
85 | if (&t->link != &card->transaction_list) { | 83 | if (&t->link != &card->transaction_list) { |
86 | t->callback(card, rcode, payload, length, t->callback_data); | 84 | t->callback(card, rcode, NULL, 0, t->callback_data); |
87 | return 0; | 85 | return 0; |
88 | } | 86 | } |
89 | 87 | ||
@@ -94,9 +92,8 @@ close_transaction(struct fw_transaction *transaction, | |||
94 | * Only valid for transactions that are potentially pending (ie have | 92 | * Only valid for transactions that are potentially pending (ie have |
95 | * been sent). | 93 | * been sent). |
96 | */ | 94 | */ |
97 | int | 95 | int fw_cancel_transaction(struct fw_card *card, |
98 | fw_cancel_transaction(struct fw_card *card, | 96 | struct fw_transaction *transaction) |
99 | struct fw_transaction *transaction) | ||
100 | { | 97 | { |
101 | /* | 98 | /* |
102 | * Cancel the packet transmission if it's still queued. That | 99 | * Cancel the packet transmission if it's still queued. That |
@@ -112,20 +109,19 @@ fw_cancel_transaction(struct fw_card *card, | |||
112 | * if the transaction is still pending and remove it in that case. | 109 | * if the transaction is still pending and remove it in that case. |
113 | */ | 110 | */ |
114 | 111 | ||
115 | return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0); | 112 | return close_transaction(transaction, card, RCODE_CANCELLED); |
116 | } | 113 | } |
117 | EXPORT_SYMBOL(fw_cancel_transaction); | 114 | EXPORT_SYMBOL(fw_cancel_transaction); |
118 | 115 | ||
119 | static void | 116 | static void transmit_complete_callback(struct fw_packet *packet, |
120 | transmit_complete_callback(struct fw_packet *packet, | 117 | struct fw_card *card, int status) |
121 | struct fw_card *card, int status) | ||
122 | { | 118 | { |
123 | struct fw_transaction *t = | 119 | struct fw_transaction *t = |
124 | container_of(packet, struct fw_transaction, packet); | 120 | container_of(packet, struct fw_transaction, packet); |
125 | 121 | ||
126 | switch (status) { | 122 | switch (status) { |
127 | case ACK_COMPLETE: | 123 | case ACK_COMPLETE: |
128 | close_transaction(t, card, RCODE_COMPLETE, NULL, 0); | 124 | close_transaction(t, card, RCODE_COMPLETE); |
129 | break; | 125 | break; |
130 | case ACK_PENDING: | 126 | case ACK_PENDING: |
131 | t->timestamp = packet->timestamp; | 127 | t->timestamp = packet->timestamp; |
@@ -133,31 +129,42 @@ transmit_complete_callback(struct fw_packet *packet, | |||
133 | case ACK_BUSY_X: | 129 | case ACK_BUSY_X: |
134 | case ACK_BUSY_A: | 130 | case ACK_BUSY_A: |
135 | case ACK_BUSY_B: | 131 | case ACK_BUSY_B: |
136 | close_transaction(t, card, RCODE_BUSY, NULL, 0); | 132 | close_transaction(t, card, RCODE_BUSY); |
137 | break; | 133 | break; |
138 | case ACK_DATA_ERROR: | 134 | case ACK_DATA_ERROR: |
139 | close_transaction(t, card, RCODE_DATA_ERROR, NULL, 0); | 135 | close_transaction(t, card, RCODE_DATA_ERROR); |
140 | break; | 136 | break; |
141 | case ACK_TYPE_ERROR: | 137 | case ACK_TYPE_ERROR: |
142 | close_transaction(t, card, RCODE_TYPE_ERROR, NULL, 0); | 138 | close_transaction(t, card, RCODE_TYPE_ERROR); |
143 | break; | 139 | break; |
144 | default: | 140 | default: |
145 | /* | 141 | /* |
146 | * In this case the ack is really a juju specific | 142 | * In this case the ack is really a juju specific |
147 | * rcode, so just forward that to the callback. | 143 | * rcode, so just forward that to the callback. |
148 | */ | 144 | */ |
149 | close_transaction(t, card, status, NULL, 0); | 145 | close_transaction(t, card, status); |
150 | break; | 146 | break; |
151 | } | 147 | } |
152 | } | 148 | } |
153 | 149 | ||
154 | static void | 150 | static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
155 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | ||
156 | int destination_id, int source_id, int generation, int speed, | 151 | int destination_id, int source_id, int generation, int speed, |
157 | unsigned long long offset, void *payload, size_t length) | 152 | unsigned long long offset, void *payload, size_t length) |
158 | { | 153 | { |
159 | int ext_tcode; | 154 | int ext_tcode; |
160 | 155 | ||
156 | if (tcode == TCODE_STREAM_DATA) { | ||
157 | packet->header[0] = | ||
158 | HEADER_DATA_LENGTH(length) | | ||
159 | destination_id | | ||
160 | HEADER_TCODE(TCODE_STREAM_DATA); | ||
161 | packet->header_length = 4; | ||
162 | packet->payload = payload; | ||
163 | packet->payload_length = length; | ||
164 | |||
165 | goto common; | ||
166 | } | ||
167 | |||
161 | if (tcode > 0x10) { | 168 | if (tcode > 0x10) { |
162 | ext_tcode = tcode & ~0x10; | 169 | ext_tcode = tcode & ~0x10; |
163 | tcode = TCODE_LOCK_REQUEST; | 170 | tcode = TCODE_LOCK_REQUEST; |
@@ -204,7 +211,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
204 | packet->payload_length = 0; | 211 | packet->payload_length = 0; |
205 | break; | 212 | break; |
206 | } | 213 | } |
207 | 214 | common: | |
208 | packet->speed = speed; | 215 | packet->speed = speed; |
209 | packet->generation = generation; | 216 | packet->generation = generation; |
210 | packet->ack = 0; | 217 | packet->ack = 0; |
@@ -246,13 +253,14 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
246 | * @param callback function to be called when the transaction is completed | 253 | * @param callback function to be called when the transaction is completed |
247 | * @param callback_data pointer to arbitrary data, which will be | 254 | * @param callback_data pointer to arbitrary data, which will be |
248 | * passed to the callback | 255 | * passed to the callback |
256 | * | ||
257 | * In case of asynchronous stream packets i.e. TCODE_STREAM_DATA, the caller | ||
258 | * needs to synthesize @destination_id with fw_stream_packet_destination_id(). | ||
249 | */ | 259 | */ |
250 | void | 260 | void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, |
251 | fw_send_request(struct fw_card *card, struct fw_transaction *t, | 261 | int destination_id, int generation, int speed, |
252 | int tcode, int destination_id, int generation, int speed, | 262 | unsigned long long offset, void *payload, size_t length, |
253 | unsigned long long offset, | 263 | fw_transaction_callback_t callback, void *callback_data) |
254 | void *payload, size_t length, | ||
255 | fw_transaction_callback_t callback, void *callback_data) | ||
256 | { | 264 | { |
257 | unsigned long flags; | 265 | unsigned long flags; |
258 | int tlabel; | 266 | int tlabel; |
@@ -322,16 +330,16 @@ static void transaction_callback(struct fw_card *card, int rcode, | |||
322 | * Returns the RCODE. | 330 | * Returns the RCODE. |
323 | */ | 331 | */ |
324 | int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, | 332 | int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, |
325 | int generation, int speed, unsigned long long offset, | 333 | int generation, int speed, unsigned long long offset, |
326 | void *data, size_t length) | 334 | void *payload, size_t length) |
327 | { | 335 | { |
328 | struct transaction_callback_data d; | 336 | struct transaction_callback_data d; |
329 | struct fw_transaction t; | 337 | struct fw_transaction t; |
330 | 338 | ||
331 | init_completion(&d.done); | 339 | init_completion(&d.done); |
332 | d.payload = data; | 340 | d.payload = payload; |
333 | fw_send_request(card, &t, tcode, destination_id, generation, speed, | 341 | fw_send_request(card, &t, tcode, destination_id, generation, speed, |
334 | offset, data, length, transaction_callback, &d); | 342 | offset, payload, length, transaction_callback, &d); |
335 | wait_for_completion(&d.done); | 343 | wait_for_completion(&d.done); |
336 | 344 | ||
337 | return d.rcode; | 345 | return d.rcode; |
@@ -399,9 +407,8 @@ void fw_flush_transactions(struct fw_card *card) | |||
399 | } | 407 | } |
400 | } | 408 | } |
401 | 409 | ||
402 | static struct fw_address_handler * | 410 | static struct fw_address_handler *lookup_overlapping_address_handler( |
403 | lookup_overlapping_address_handler(struct list_head *list, | 411 | struct list_head *list, unsigned long long offset, size_t length) |
404 | unsigned long long offset, size_t length) | ||
405 | { | 412 | { |
406 | struct fw_address_handler *handler; | 413 | struct fw_address_handler *handler; |
407 | 414 | ||
@@ -414,9 +421,8 @@ lookup_overlapping_address_handler(struct list_head *list, | |||
414 | return NULL; | 421 | return NULL; |
415 | } | 422 | } |
416 | 423 | ||
417 | static struct fw_address_handler * | 424 | static struct fw_address_handler *lookup_enclosing_address_handler( |
418 | lookup_enclosing_address_handler(struct list_head *list, | 425 | struct list_head *list, unsigned long long offset, size_t length) |
419 | unsigned long long offset, size_t length) | ||
420 | { | 426 | { |
421 | struct fw_address_handler *handler; | 427 | struct fw_address_handler *handler; |
422 | 428 | ||
@@ -449,36 +455,44 @@ const struct fw_address_region fw_unit_space_region = | |||
449 | #endif /* 0 */ | 455 | #endif /* 0 */ |
450 | 456 | ||
451 | /** | 457 | /** |
452 | * Allocate a range of addresses in the node space of the OHCI | 458 | * fw_core_add_address_handler - register for incoming requests |
453 | * controller. When a request is received that falls within the | 459 | * @handler: callback |
454 | * specified address range, the specified callback is invoked. The | 460 | * @region: region in the IEEE 1212 node space address range |
455 | * parameters passed to the callback give the details of the | 461 | * |
456 | * particular request. | 462 | * region->start, ->end, and handler->length have to be quadlet-aligned. |
463 | * | ||
464 | * When a request is received that falls within the specified address range, | ||
465 | * the specified callback is invoked. The parameters passed to the callback | ||
466 | * give the details of the particular request. | ||
457 | * | 467 | * |
458 | * Return value: 0 on success, non-zero otherwise. | 468 | * Return value: 0 on success, non-zero otherwise. |
459 | * The start offset of the handler's address region is determined by | 469 | * The start offset of the handler's address region is determined by |
460 | * fw_core_add_address_handler() and is returned in handler->offset. | 470 | * fw_core_add_address_handler() and is returned in handler->offset. |
461 | * The offset is quadlet-aligned. | ||
462 | */ | 471 | */ |
463 | int | 472 | int fw_core_add_address_handler(struct fw_address_handler *handler, |
464 | fw_core_add_address_handler(struct fw_address_handler *handler, | 473 | const struct fw_address_region *region) |
465 | const struct fw_address_region *region) | ||
466 | { | 474 | { |
467 | struct fw_address_handler *other; | 475 | struct fw_address_handler *other; |
468 | unsigned long flags; | 476 | unsigned long flags; |
469 | int ret = -EBUSY; | 477 | int ret = -EBUSY; |
470 | 478 | ||
479 | if (region->start & 0xffff000000000003ULL || | ||
480 | region->end & 0xffff000000000003ULL || | ||
481 | region->start >= region->end || | ||
482 | handler->length & 3 || | ||
483 | handler->length == 0) | ||
484 | return -EINVAL; | ||
485 | |||
471 | spin_lock_irqsave(&address_handler_lock, flags); | 486 | spin_lock_irqsave(&address_handler_lock, flags); |
472 | 487 | ||
473 | handler->offset = roundup(region->start, 4); | 488 | handler->offset = region->start; |
474 | while (handler->offset + handler->length <= region->end) { | 489 | while (handler->offset + handler->length <= region->end) { |
475 | other = | 490 | other = |
476 | lookup_overlapping_address_handler(&address_handler_list, | 491 | lookup_overlapping_address_handler(&address_handler_list, |
477 | handler->offset, | 492 | handler->offset, |
478 | handler->length); | 493 | handler->length); |
479 | if (other != NULL) { | 494 | if (other != NULL) { |
480 | handler->offset = | 495 | handler->offset += other->length; |
481 | roundup(other->offset + other->length, 4); | ||
482 | } else { | 496 | } else { |
483 | list_add_tail(&handler->link, &address_handler_list); | 497 | list_add_tail(&handler->link, &address_handler_list); |
484 | ret = 0; | 498 | ret = 0; |
@@ -493,12 +507,7 @@ fw_core_add_address_handler(struct fw_address_handler *handler, | |||
493 | EXPORT_SYMBOL(fw_core_add_address_handler); | 507 | EXPORT_SYMBOL(fw_core_add_address_handler); |
494 | 508 | ||
495 | /** | 509 | /** |
496 | * Deallocate a range of addresses allocated with fw_allocate. This | 510 | * fw_core_remove_address_handler - unregister an address handler |
497 | * will call the associated callback one last time with a the special | ||
498 | * tcode TCODE_DEALLOCATE, to let the client destroy the registered | ||
499 | * callback data. For convenience, the callback parameters offset and | ||
500 | * length are set to the start and the length respectively for the | ||
501 | * deallocated region, payload is set to NULL. | ||
502 | */ | 511 | */ |
503 | void fw_core_remove_address_handler(struct fw_address_handler *handler) | 512 | void fw_core_remove_address_handler(struct fw_address_handler *handler) |
504 | { | 513 | { |
@@ -518,9 +527,8 @@ struct fw_request { | |||
518 | u32 data[0]; | 527 | u32 data[0]; |
519 | }; | 528 | }; |
520 | 529 | ||
521 | static void | 530 | static void free_response_callback(struct fw_packet *packet, |
522 | free_response_callback(struct fw_packet *packet, | 531 | struct fw_card *card, int status) |
523 | struct fw_card *card, int status) | ||
524 | { | 532 | { |
525 | struct fw_request *request; | 533 | struct fw_request *request; |
526 | 534 | ||
@@ -528,9 +536,8 @@ free_response_callback(struct fw_packet *packet, | |||
528 | kfree(request); | 536 | kfree(request); |
529 | } | 537 | } |
530 | 538 | ||
531 | void | 539 | void fw_fill_response(struct fw_packet *response, u32 *request_header, |
532 | fw_fill_response(struct fw_packet *response, u32 *request_header, | 540 | int rcode, void *payload, size_t length) |
533 | int rcode, void *payload, size_t length) | ||
534 | { | 541 | { |
535 | int tcode, tlabel, extended_tcode, source, destination; | 542 | int tcode, tlabel, extended_tcode, source, destination; |
536 | 543 | ||
@@ -588,8 +595,7 @@ fw_fill_response(struct fw_packet *response, u32 *request_header, | |||
588 | } | 595 | } |
589 | EXPORT_SYMBOL(fw_fill_response); | 596 | EXPORT_SYMBOL(fw_fill_response); |
590 | 597 | ||
591 | static struct fw_request * | 598 | static struct fw_request *allocate_request(struct fw_packet *p) |
592 | allocate_request(struct fw_packet *p) | ||
593 | { | 599 | { |
594 | struct fw_request *request; | 600 | struct fw_request *request; |
595 | u32 *data, length; | 601 | u32 *data, length; |
@@ -649,8 +655,8 @@ allocate_request(struct fw_packet *p) | |||
649 | return request; | 655 | return request; |
650 | } | 656 | } |
651 | 657 | ||
652 | void | 658 | void fw_send_response(struct fw_card *card, |
653 | fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) | 659 | struct fw_request *request, int rcode) |
654 | { | 660 | { |
655 | /* unified transaction or broadcast transaction: don't respond */ | 661 | /* unified transaction or broadcast transaction: don't respond */ |
656 | if (request->ack != ACK_PENDING || | 662 | if (request->ack != ACK_PENDING || |
@@ -670,8 +676,7 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) | |||
670 | } | 676 | } |
671 | EXPORT_SYMBOL(fw_send_response); | 677 | EXPORT_SYMBOL(fw_send_response); |
672 | 678 | ||
673 | void | 679 | void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) |
674 | fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | ||
675 | { | 680 | { |
676 | struct fw_address_handler *handler; | 681 | struct fw_address_handler *handler; |
677 | struct fw_request *request; | 682 | struct fw_request *request; |
@@ -719,8 +724,7 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | |||
719 | } | 724 | } |
720 | EXPORT_SYMBOL(fw_core_handle_request); | 725 | EXPORT_SYMBOL(fw_core_handle_request); |
721 | 726 | ||
722 | void | 727 | void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) |
723 | fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | ||
724 | { | 728 | { |
725 | struct fw_transaction *t; | 729 | struct fw_transaction *t; |
726 | unsigned long flags; | 730 | unsigned long flags; |
@@ -793,12 +797,10 @@ static const struct fw_address_region topology_map_region = | |||
793 | { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, | 797 | { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, |
794 | .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; | 798 | .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; |
795 | 799 | ||
796 | static void | 800 | static void handle_topology_map(struct fw_card *card, struct fw_request *request, |
797 | handle_topology_map(struct fw_card *card, struct fw_request *request, | 801 | int tcode, int destination, int source, int generation, |
798 | int tcode, int destination, int source, | 802 | int speed, unsigned long long offset, |
799 | int generation, int speed, | 803 | void *payload, size_t length, void *callback_data) |
800 | unsigned long long offset, | ||
801 | void *payload, size_t length, void *callback_data) | ||
802 | { | 804 | { |
803 | int i, start, end; | 805 | int i, start, end; |
804 | __be32 *map; | 806 | __be32 *map; |
@@ -832,12 +834,10 @@ static const struct fw_address_region registers_region = | |||
832 | { .start = CSR_REGISTER_BASE, | 834 | { .start = CSR_REGISTER_BASE, |
833 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; | 835 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; |
834 | 836 | ||
835 | static void | 837 | static void handle_registers(struct fw_card *card, struct fw_request *request, |
836 | handle_registers(struct fw_card *card, struct fw_request *request, | 838 | int tcode, int destination, int source, int generation, |
837 | int tcode, int destination, int source, | 839 | int speed, unsigned long long offset, |
838 | int generation, int speed, | 840 | void *payload, size_t length, void *callback_data) |
839 | unsigned long long offset, | ||
840 | void *payload, size_t length, void *callback_data) | ||
841 | { | 841 | { |
842 | int reg = offset & ~CSR_REGISTER_BASE; | 842 | int reg = offset & ~CSR_REGISTER_BASE; |
843 | unsigned long long bus_time; | 843 | unsigned long long bus_time; |
@@ -939,11 +939,11 @@ static struct fw_descriptor model_id_descriptor = { | |||
939 | 939 | ||
940 | static int __init fw_core_init(void) | 940 | static int __init fw_core_init(void) |
941 | { | 941 | { |
942 | int retval; | 942 | int ret; |
943 | 943 | ||
944 | retval = bus_register(&fw_bus_type); | 944 | ret = bus_register(&fw_bus_type); |
945 | if (retval < 0) | 945 | if (ret < 0) |
946 | return retval; | 946 | return ret; |
947 | 947 | ||
948 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); | 948 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); |
949 | if (fw_cdev_major < 0) { | 949 | if (fw_cdev_major < 0) { |
@@ -951,19 +951,10 @@ static int __init fw_core_init(void) | |||
951 | return fw_cdev_major; | 951 | return fw_cdev_major; |
952 | } | 952 | } |
953 | 953 | ||
954 | retval = fw_core_add_address_handler(&topology_map, | 954 | fw_core_add_address_handler(&topology_map, &topology_map_region); |
955 | &topology_map_region); | 955 | fw_core_add_address_handler(®isters, ®isters_region); |
956 | BUG_ON(retval < 0); | 956 | fw_core_add_descriptor(&vendor_id_descriptor); |
957 | 957 | fw_core_add_descriptor(&model_id_descriptor); | |
958 | retval = fw_core_add_address_handler(®isters, | ||
959 | ®isters_region); | ||
960 | BUG_ON(retval < 0); | ||
961 | |||
962 | /* Add the vendor textual descriptor. */ | ||
963 | retval = fw_core_add_descriptor(&vendor_id_descriptor); | ||
964 | BUG_ON(retval < 0); | ||
965 | retval = fw_core_add_descriptor(&model_id_descriptor); | ||
966 | BUG_ON(retval < 0); | ||
967 | 958 | ||
968 | return 0; | 959 | return 0; |
969 | } | 960 | } |