@@ -226,6 +226,9 @@ struct apple_dart {
226226
227227 u32 save_tcr [DART_MAX_STREAMS ];
228228 u32 save_ttbr [DART_MAX_STREAMS ][DART_MAX_TTBR ];
229+
230+ u64 * locked_ttbr [DART_MAX_STREAMS ][DART_MAX_TTBR ];
231+ u64 * shadow_ttbr [DART_MAX_STREAMS ][DART_MAX_TTBR ];
229232};
230233
231234/*
@@ -372,6 +375,89 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map)
372375 apple_dart_hw_clear_ttbr (stream_map , i );
373376}
374377
378+ static int
379+ apple_dart_hw_set_locked_ttbr (struct apple_dart_stream_map * stream_map , u8 idx ,
380+ phys_addr_t paddr )
381+ {
382+ struct apple_dart * dart = stream_map -> dart ;
383+ int sid ;
384+
385+ WARN_ON (!dart -> locked );
386+ WARN_ON (paddr & ((1 << dart -> hw -> ttbr_shift ) - 1 ));
387+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
388+ u32 ttbr ;
389+ phys_addr_t phys ;
390+ u64 * l1_tbl , * l1_shadow ;
391+
392+ ttbr = readl (dart -> regs + DART_TTBR (dart , sid , idx ));
393+
394+ WARN_ON (!(ttbr & dart -> hw -> ttbr_valid ));
395+ ttbr &= ~dart -> hw -> ttbr_valid ;
396+
397+ if (dart -> hw -> ttbr_addr_field_shift )
398+ ttbr >>= dart -> hw -> ttbr_addr_field_shift ;
399+ phys = ((phys_addr_t ) ttbr ) << dart -> hw -> ttbr_shift ;
400+
401+ l1_tbl = devm_memremap (dart -> dev , phys , dart -> pgsize ,
402+ MEMREMAP_WB );
403+ if (!l1_tbl )
404+ return - ENOMEM ;
405+ l1_shadow = devm_memremap (dart -> dev , paddr , dart -> pgsize ,
406+ MEMREMAP_WB );
407+ if (!l1_shadow )
408+ return - ENOMEM ;
409+
410+ dart -> locked_ttbr [sid ][idx ] = l1_tbl ;
411+ dart -> shadow_ttbr [sid ][idx ] = l1_shadow ;
412+ }
413+
414+ return 0 ;
415+ }
416+
417+ static int
418+ apple_dart_hw_clear_locked_ttbr (struct apple_dart_stream_map * stream_map ,
419+ u8 idx )
420+ {
421+ struct apple_dart * dart = stream_map -> dart ;
422+ int sid ;
423+
424+ WARN_ON (!dart -> locked );
425+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
426+ /* TODO: locked L1 table might need to be restored to boot state */
427+ if (dart -> locked_ttbr [sid ][idx ]) {
428+ memset (dart -> locked_ttbr [sid ][idx ], 0 , dart -> pgsize );
429+ devm_memunmap (dart -> dev , dart -> locked_ttbr [sid ][idx ]);
430+ }
431+ dart -> locked_ttbr [sid ][idx ] = NULL ;
432+ if (dart -> shadow_ttbr [sid ][idx ])
433+ devm_memunmap (dart -> dev , dart -> shadow_ttbr [sid ][idx ]);
434+ dart -> shadow_ttbr [sid ][idx ] = NULL ;
435+ }
436+
437+ return 0 ;
438+ }
439+
440+ static int
441+ apple_dart_hw_sync_locked (struct apple_dart_stream_map * stream_map )
442+ {
443+ struct apple_dart * dart = stream_map -> dart ;
444+ int sid ;
445+
446+ WARN_ON (!dart -> locked );
447+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
448+ for (int idx = 0 ; idx < dart -> hw -> ttbr_count ; idx ++ ) {
449+ u64 * ttbrep = dart -> locked_ttbr [sid ][idx ];
450+ u64 * ptep = dart -> shadow_ttbr [sid ][idx ];
451+ if (!ttbrep || !ptep )
452+ continue ;
453+ for (int entry = 0 ; entry < dart -> pgsize / sizeof (* ptep ); entry ++ )
454+ ttbrep [entry ] = ptep [entry ];
455+ }
456+ }
457+
458+ return 0 ;
459+ }
460+
375461static int
376462apple_dart_t8020_hw_stream_command (struct apple_dart_stream_map * stream_map ,
377463 u32 command )
@@ -490,6 +576,10 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
490576 for (j = 0 ; j < BITS_TO_LONGS (stream_map .dart -> num_streams ); j ++ )
491577 stream_map .sidmap [j ] = atomic_long_read (& domain_stream_map -> sidmap [j ]);
492578
579+
580+ if (stream_map .dart -> locked )
581+ apple_dart_hw_sync_locked (& stream_map );
582+
493583 stream_map .dart -> hw -> invalidate_tlb (& stream_map );
494584 }
495585}
@@ -557,17 +647,62 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
557647 struct io_pgtable_cfg * pgtbl_cfg =
558648 & io_pgtable_ops_to_pgtable (domain -> pgtbl_ops )-> cfg ;
559649
560- for (i = 0 ; i < pgtbl_cfg -> apple_dart_cfg .n_ttbrs ; ++ i )
561- apple_dart_hw_set_ttbr (stream_map , i ,
562- pgtbl_cfg -> apple_dart_cfg .ttbr [i ]);
563- for (; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
564- apple_dart_hw_clear_ttbr (stream_map , i );
650+ /* Locked DARTs are set up by the bootloader. */
651+ if (stream_map -> dart -> locked ) {
652+ for (i = 0 ; i < pgtbl_cfg -> apple_dart_cfg .n_ttbrs ; ++ i )
653+ apple_dart_hw_set_locked_ttbr (stream_map , i ,
654+ pgtbl_cfg -> apple_dart_cfg .ttbr [i ]);
655+ for (; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
656+ apple_dart_hw_clear_locked_ttbr (stream_map , i );
657+ apple_dart_hw_sync_locked (stream_map );
658+ } else {
659+ for (i = 0 ; i < pgtbl_cfg -> apple_dart_cfg .n_ttbrs ; ++ i )
660+ apple_dart_hw_set_ttbr (stream_map , i ,
661+ pgtbl_cfg -> apple_dart_cfg .ttbr [i ]);
662+ for (; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
663+ apple_dart_hw_clear_ttbr (stream_map , i );
565664
566- apple_dart_hw_enable_translation (stream_map );
665+ apple_dart_hw_enable_translation (stream_map );
666+ }
567667 stream_map -> dart -> hw -> invalidate_tlb (stream_map );
568668}
569669
670+ static int apple_dart_setup_resv_locked (struct iommu_domain * domain ,
671+ struct device * dev , size_t pgsize )
672+ {
673+ struct iommu_resv_region * region ;
674+ LIST_HEAD (resv_regions );
675+ int ret = 0 ;
676+
677+ of_iommu_get_resv_regions (dev , & resv_regions );
678+ list_for_each_entry (region , & resv_regions , list ) {
679+ size_t mapped = 0 ;
680+
681+ /* Only map translated reserved regions */
682+ if (region -> type != IOMMU_RESV_TRANSLATED )
683+ continue ;
684+
685+ while (mapped < region -> length ) {
686+ phys_addr_t paddr = region -> start + mapped ;
687+ unsigned long iova = region -> dva + mapped ;
688+ size_t length = region -> length - mapped ;
689+ size_t pgcount = length / pgsize ;
690+
691+ ret = apple_dart_map_pages (domain , iova ,
692+ paddr , pgsize , pgcount ,
693+ region -> prot , GFP_KERNEL , & mapped );
694+
695+ if (ret )
696+ goto end_put ;
697+ }
698+ }
699+ end_put :
700+ iommu_put_resv_regions (dev , & resv_regions );
701+ return ret ;
702+ }
703+
570704static int apple_dart_finalize_domain (struct iommu_domain * domain ,
705+ struct device * dev ,
571706 struct apple_dart_master_cfg * cfg )
572707{
573708 struct apple_dart_domain * dart_domain = to_dart_domain (domain );
@@ -596,6 +731,21 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
596731 .iommu_dev = dart -> dev ,
597732 };
598733
734+ if (dart -> locked ) {
735+ unsigned long * sidmap ;
736+ int sid ;
737+ u32 ttbr ;
738+
739+ /* Locked DARTs can only have a single stream bound */
740+ sidmap = cfg -> stream_maps [0 ].sidmap ;
741+ sid = find_first_bit (sidmap , dart -> num_streams );
742+
743+ WARN_ON ((sid < 0 ) || bitmap_weight (sidmap , dart -> num_streams ) > 1 );
744+ ttbr = readl (dart -> regs + DART_TTBR (dart , sid , 0 ));
745+
746+ WARN_ON (!(ttbr & dart -> hw -> ttbr_valid ));
747+ }
748+
599749 dart_domain -> pgtbl_ops =
600750 alloc_io_pgtable_ops (dart -> hw -> fmt , & pgtbl_cfg , domain );
601751 if (!dart_domain -> pgtbl_ops ) {
@@ -610,6 +760,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
610760
611761 dart_domain -> finalized = true;
612762
763+ ret = apple_dart_setup_resv_locked (domain , dev , dart -> pgsize );
613764done :
614765 mutex_unlock (& dart_domain -> init_lock );
615766 return ret ;
@@ -667,7 +818,7 @@ static int apple_dart_attach_dev(struct iommu_domain *domain,
667818 domain -> type != IOMMU_DOMAIN_UNMANAGED )
668819 return - EINVAL ;
669820
670- ret = apple_dart_finalize_domain (domain , cfg );
821+ ret = apple_dart_finalize_domain (domain , dev , cfg );
671822 if (ret )
672823 return ret ;
673824
@@ -712,8 +863,16 @@ static struct iommu_device *apple_dart_probe_device(struct device *dev)
712863
713864static void apple_dart_release_device (struct device * dev )
714865{
866+ int i , j ;
867+ struct apple_dart_stream_map * stream_map ;
715868 struct apple_dart_master_cfg * cfg = dev_iommu_priv_get (dev );
716869
870+ for_each_stream_map (j , cfg , stream_map ) {
871+ if (stream_map -> dart -> locked )
872+ for (i = 0 ; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
873+ apple_dart_hw_clear_locked_ttbr (stream_map , i );
874+ }
875+
717876 kfree (cfg );
718877}
719878
0 commit comments