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.c154
1 files changed, 111 insertions, 43 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index da628c72a462..673b03f8b4ec 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -218,12 +218,15 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
218 packet->header_length = 16; 218 packet->header_length = 16;
219 packet->payload_length = 0; 219 packet->payload_length = 0;
220 break; 220 break;
221
222 default:
223 WARN(1, KERN_ERR "wrong tcode %d", tcode);
221 } 224 }
222 common: 225 common:
223 packet->speed = speed; 226 packet->speed = speed;
224 packet->generation = generation; 227 packet->generation = generation;
225 packet->ack = 0; 228 packet->ack = 0;
226 packet->payload_bus = 0; 229 packet->payload_mapped = false;
227} 230}
228 231
229/** 232/**
@@ -429,14 +432,20 @@ static struct fw_address_handler *lookup_overlapping_address_handler(
429 return NULL; 432 return NULL;
430} 433}
431 434
435static bool is_enclosing_handler(struct fw_address_handler *handler,
436 unsigned long long offset, size_t length)
437{
438 return handler->offset <= offset &&
439 offset + length <= handler->offset + handler->length;
440}
441
432static struct fw_address_handler *lookup_enclosing_address_handler( 442static struct fw_address_handler *lookup_enclosing_address_handler(
433 struct list_head *list, unsigned long long offset, size_t length) 443 struct list_head *list, unsigned long long offset, size_t length)
434{ 444{
435 struct fw_address_handler *handler; 445 struct fw_address_handler *handler;
436 446
437 list_for_each_entry(handler, list, link) { 447 list_for_each_entry(handler, list, link) {
438 if (handler->offset <= offset && 448 if (is_enclosing_handler(handler, offset, length))
439 offset + length <= handler->offset + handler->length)
440 return handler; 449 return handler;
441 } 450 }
442 451
@@ -462,6 +471,12 @@ const struct fw_address_region fw_unit_space_region =
462 { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; 471 { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
463#endif /* 0 */ 472#endif /* 0 */
464 473
474static bool is_in_fcp_region(u64 offset, size_t length)
475{
476 return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
477 offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
478}
479
465/** 480/**
466 * fw_core_add_address_handler - register for incoming requests 481 * fw_core_add_address_handler - register for incoming requests
467 * @handler: callback 482 * @handler: callback
@@ -474,8 +489,11 @@ const struct fw_address_region fw_unit_space_region =
474 * give the details of the particular request. 489 * give the details of the particular request.
475 * 490 *
476 * Return value: 0 on success, non-zero otherwise. 491 * Return value: 0 on success, non-zero otherwise.
492 *
477 * The start offset of the handler's address region is determined by 493 * The start offset of the handler's address region is determined by
478 * fw_core_add_address_handler() and is returned in handler->offset. 494 * fw_core_add_address_handler() and is returned in handler->offset.
495 *
496 * Address allocations are exclusive, except for the FCP registers.
479 */ 497 */
480int fw_core_add_address_handler(struct fw_address_handler *handler, 498int fw_core_add_address_handler(struct fw_address_handler *handler,
481 const struct fw_address_region *region) 499 const struct fw_address_region *region)
@@ -495,10 +513,12 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
495 513
496 handler->offset = region->start; 514 handler->offset = region->start;
497 while (handler->offset + handler->length <= region->end) { 515 while (handler->offset + handler->length <= region->end) {
498 other = 516 if (is_in_fcp_region(handler->offset, handler->length))
499 lookup_overlapping_address_handler(&address_handler_list, 517 other = NULL;
500 handler->offset, 518 else
501 handler->length); 519 other = lookup_overlapping_address_handler
520 (&address_handler_list,
521 handler->offset, handler->length);
502 if (other != NULL) { 522 if (other != NULL) {
503 handler->offset += other->length; 523 handler->offset += other->length;
504 } else { 524 } else {
@@ -595,11 +615,10 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
595 break; 615 break;
596 616
597 default: 617 default:
598 BUG(); 618 WARN(1, KERN_ERR "wrong tcode %d", tcode);
599 return;
600 } 619 }
601 620
602 response->payload_bus = 0; 621 response->payload_mapped = false;
603} 622}
604EXPORT_SYMBOL(fw_fill_response); 623EXPORT_SYMBOL(fw_fill_response);
605 624
@@ -666,6 +685,9 @@ static struct fw_request *allocate_request(struct fw_packet *p)
666void fw_send_response(struct fw_card *card, 685void fw_send_response(struct fw_card *card,
667 struct fw_request *request, int rcode) 686 struct fw_request *request, int rcode)
668{ 687{
688 if (WARN_ONCE(!request, "invalid for FCP address handlers"))
689 return;
690
669 /* unified transaction or broadcast transaction: don't respond */ 691 /* unified transaction or broadcast transaction: don't respond */
670 if (request->ack != ACK_PENDING || 692 if (request->ack != ACK_PENDING ||
671 HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { 693 HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
@@ -684,26 +706,15 @@ void fw_send_response(struct fw_card *card,
684} 706}
685EXPORT_SYMBOL(fw_send_response); 707EXPORT_SYMBOL(fw_send_response);
686 708
687void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) 709static void handle_exclusive_region_request(struct fw_card *card,
710 struct fw_packet *p,
711 struct fw_request *request,
712 unsigned long long offset)
688{ 713{
689 struct fw_address_handler *handler; 714 struct fw_address_handler *handler;
690 struct fw_request *request;
691 unsigned long long offset;
692 unsigned long flags; 715 unsigned long flags;
693 int tcode, destination, source; 716 int tcode, destination, source;
694 717
695 if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
696 return;
697
698 request = allocate_request(p);
699 if (request == NULL) {
700 /* FIXME: send statically allocated busy packet. */
701 return;
702 }
703
704 offset =
705 ((unsigned long long)
706 HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2];
707 tcode = HEADER_GET_TCODE(p->header[0]); 718 tcode = HEADER_GET_TCODE(p->header[0]);
708 destination = HEADER_GET_DESTINATION(p->header[0]); 719 destination = HEADER_GET_DESTINATION(p->header[0]);
709 source = HEADER_GET_SOURCE(p->header[1]); 720 source = HEADER_GET_SOURCE(p->header[1]);
@@ -730,6 +741,73 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
730 request->data, request->length, 741 request->data, request->length,
731 handler->callback_data); 742 handler->callback_data);
732} 743}
744
745static void handle_fcp_region_request(struct fw_card *card,
746 struct fw_packet *p,
747 struct fw_request *request,
748 unsigned long long offset)
749{
750 struct fw_address_handler *handler;
751 unsigned long flags;
752 int tcode, destination, source;
753
754 if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
755 offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
756 request->length > 0x200) {
757 fw_send_response(card, request, RCODE_ADDRESS_ERROR);
758
759 return;
760 }
761
762 tcode = HEADER_GET_TCODE(p->header[0]);
763 destination = HEADER_GET_DESTINATION(p->header[0]);
764 source = HEADER_GET_SOURCE(p->header[1]);
765
766 if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
767 tcode != TCODE_WRITE_BLOCK_REQUEST) {
768 fw_send_response(card, request, RCODE_TYPE_ERROR);
769
770 return;
771 }
772
773 spin_lock_irqsave(&address_handler_lock, flags);
774 list_for_each_entry(handler, &address_handler_list, link) {
775 if (is_enclosing_handler(handler, offset, request->length))
776 handler->address_callback(card, NULL, tcode,
777 destination, source,
778 p->generation, p->speed,
779 offset, request->data,
780 request->length,
781 handler->callback_data);
782 }
783 spin_unlock_irqrestore(&address_handler_lock, flags);
784
785 fw_send_response(card, request, RCODE_COMPLETE);
786}
787
788void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
789{
790 struct fw_request *request;
791 unsigned long long offset;
792
793 if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
794 return;
795
796 request = allocate_request(p);
797 if (request == NULL) {
798 /* FIXME: send statically allocated busy packet. */
799 return;
800 }
801
802 offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |
803 p->header[2];
804
805 if (!is_in_fcp_region(offset, request->length))
806 handle_exclusive_region_request(card, p, request, offset);
807 else
808 handle_fcp_region_request(card, p, request, offset);
809
810}
733EXPORT_SYMBOL(fw_core_handle_request); 811EXPORT_SYMBOL(fw_core_handle_request);
734 812
735void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) 813void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
@@ -810,8 +888,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
810 int speed, unsigned long long offset, 888 int speed, unsigned long long offset,
811 void *payload, size_t length, void *callback_data) 889 void *payload, size_t length, void *callback_data)
812{ 890{
813 int i, start, end; 891 int start;
814 __be32 *map;
815 892
816 if (!TCODE_IS_READ_REQUEST(tcode)) { 893 if (!TCODE_IS_READ_REQUEST(tcode)) {
817 fw_send_response(card, request, RCODE_TYPE_ERROR); 894 fw_send_response(card, request, RCODE_TYPE_ERROR);
@@ -824,11 +901,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
824 } 901 }
825 902
826 start = (offset - topology_map_region.start) / 4; 903 start = (offset - topology_map_region.start) / 4;
827 end = start + length / 4; 904 memcpy(payload, &card->topology_map[start], length);
828 map = payload;
829
830 for (i = 0; i < length / 4; i++)
831 map[i] = cpu_to_be32(card->topology_map[start + i]);
832 905
833 fw_send_response(card, request, RCODE_COMPLETE); 906 fw_send_response(card, request, RCODE_COMPLETE);
834} 907}
@@ -848,23 +921,15 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
848 void *payload, size_t length, void *callback_data) 921 void *payload, size_t length, void *callback_data)
849{ 922{
850 int reg = offset & ~CSR_REGISTER_BASE; 923 int reg = offset & ~CSR_REGISTER_BASE;
851 unsigned long long bus_time;
852 __be32 *data = payload; 924 __be32 *data = payload;
853 int rcode = RCODE_COMPLETE; 925 int rcode = RCODE_COMPLETE;
854 926
855 switch (reg) { 927 switch (reg) {
856 case CSR_CYCLE_TIME: 928 case CSR_CYCLE_TIME:
857 case CSR_BUS_TIME: 929 if (TCODE_IS_READ_REQUEST(tcode) && length == 4)
858 if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) { 930 *data = cpu_to_be32(card->driver->get_cycle_time(card));
859 rcode = RCODE_TYPE_ERROR;
860 break;
861 }
862
863 bus_time = card->driver->get_bus_time(card);
864 if (reg == CSR_CYCLE_TIME)
865 *data = cpu_to_be32(bus_time);
866 else 931 else
867 *data = cpu_to_be32(bus_time >> 25); 932 rcode = RCODE_TYPE_ERROR;
868 break; 933 break;
869 934
870 case CSR_BROADCAST_CHANNEL: 935 case CSR_BROADCAST_CHANNEL:
@@ -895,6 +960,9 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
895 case CSR_BUSY_TIMEOUT: 960 case CSR_BUSY_TIMEOUT:
896 /* FIXME: Implement this. */ 961 /* FIXME: Implement this. */
897 962
963 case CSR_BUS_TIME:
964 /* Useless without initialization by the bus manager. */
965
898 default: 966 default:
899 rcode = RCODE_ADDRESS_ERROR; 967 rcode = RCODE_ADDRESS_ERROR;
900 break; 968 break;