@@ -432,14 +432,20 @@ static struct fw_address_handler *lookup_overlapping_address_handler(
432
432
return NULL ;
433
433
}
434
434
435
+ static 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
+
435
442
static struct fw_address_handler * lookup_enclosing_address_handler (
436
443
struct list_head * list , unsigned long long offset , size_t length )
437
444
{
438
445
struct fw_address_handler * handler ;
439
446
440
447
list_for_each_entry (handler , list , link ) {
441
- if (handler -> offset <= offset &&
442
- offset + length <= handler -> offset + handler -> length )
448
+ if (is_enclosing_handler (handler , offset , length ))
443
449
return handler ;
444
450
}
445
451
@@ -465,6 +471,12 @@ const struct fw_address_region fw_unit_space_region =
465
471
{ .start = 0xfffff0000900ULL , .end = 0x1000000000000ULL , };
466
472
#endif /* 0 */
467
473
474
+ static 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
+
468
480
/**
469
481
* fw_core_add_address_handler - register for incoming requests
470
482
* @handler: callback
@@ -477,8 +489,11 @@ const struct fw_address_region fw_unit_space_region =
477
489
* give the details of the particular request.
478
490
*
479
491
* Return value: 0 on success, non-zero otherwise.
492
+ *
480
493
* The start offset of the handler's address region is determined by
481
494
* fw_core_add_address_handler() and is returned in handler->offset.
495
+ *
496
+ * Address allocations are exclusive, except for the FCP registers.
482
497
*/
483
498
int fw_core_add_address_handler (struct fw_address_handler * handler ,
484
499
const struct fw_address_region * region )
@@ -498,10 +513,12 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
498
513
499
514
handler -> offset = region -> start ;
500
515
while (handler -> offset + handler -> length <= region -> end ) {
501
- other =
502
- lookup_overlapping_address_handler (& address_handler_list ,
503
- handler -> offset ,
504
- handler -> length );
516
+ if (is_in_fcp_region (handler -> offset , handler -> length ))
517
+ other = NULL ;
518
+ else
519
+ other = lookup_overlapping_address_handler
520
+ (& address_handler_list ,
521
+ handler -> offset , handler -> length );
505
522
if (other != NULL ) {
506
523
handler -> offset += other -> length ;
507
524
} else {
@@ -668,6 +685,9 @@ static struct fw_request *allocate_request(struct fw_packet *p)
668
685
void fw_send_response (struct fw_card * card ,
669
686
struct fw_request * request , int rcode )
670
687
{
688
+ if (WARN_ONCE (!request , "invalid for FCP address handlers" ))
689
+ return ;
690
+
671
691
/* unified transaction or broadcast transaction: don't respond */
672
692
if (request -> ack != ACK_PENDING ||
673
693
HEADER_DESTINATION_IS_BROADCAST (request -> request_header [0 ])) {
@@ -686,26 +706,15 @@ void fw_send_response(struct fw_card *card,
686
706
}
687
707
EXPORT_SYMBOL (fw_send_response );
688
708
689
- void fw_core_handle_request (struct fw_card * card , struct fw_packet * p )
709
+ static void handle_exclusive_region_request (struct fw_card * card ,
710
+ struct fw_packet * p ,
711
+ struct fw_request * request ,
712
+ unsigned long long offset )
690
713
{
691
714
struct fw_address_handler * handler ;
692
- struct fw_request * request ;
693
- unsigned long long offset ;
694
715
unsigned long flags ;
695
716
int tcode , destination , source ;
696
717
697
- if (p -> ack != ACK_PENDING && p -> ack != ACK_COMPLETE )
698
- return ;
699
-
700
- request = allocate_request (p );
701
- if (request == NULL ) {
702
- /* FIXME: send statically allocated busy packet. */
703
- return ;
704
- }
705
-
706
- offset =
707
- ((unsigned long long )
708
- HEADER_GET_OFFSET_HIGH (p -> header [1 ]) << 32 ) | p -> header [2 ];
709
718
tcode = HEADER_GET_TCODE (p -> header [0 ]);
710
719
destination = HEADER_GET_DESTINATION (p -> header [0 ]);
711
720
source = HEADER_GET_SOURCE (p -> header [1 ]);
@@ -732,6 +741,73 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
732
741
request -> data , request -> length ,
733
742
handler -> callback_data );
734
743
}
744
+
745
+ static 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
+
788
+ void 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
+ }
735
811
EXPORT_SYMBOL (fw_core_handle_request );
736
812
737
813
void fw_core_handle_response (struct fw_card * card , struct fw_packet * p )
0 commit comments