@@ -235,6 +235,8 @@ struct apple_dart {
235235
236236 u32 save_tcr [DART_MAX_STREAMS ];
237237 u32 save_ttbr [DART_MAX_STREAMS ][DART_MAX_TTBR ];
238+
239+ u64 * locked_ttbr [DART_MAX_STREAMS ][DART_MAX_TTBR ];
238240};
239241
240242/*
@@ -383,6 +385,82 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map)
383385 apple_dart_hw_clear_ttbr (stream_map , i );
384386}
385387
388+ static int
389+ apple_dart_hw_map_locked_ttbr (struct apple_dart_stream_map * stream_map , u8 idx )
390+ {
391+ struct apple_dart * dart = stream_map -> dart ;
392+ int sid ;
393+
394+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
395+ u32 ttbr ;
396+ phys_addr_t phys ;
397+ u64 * l1_tbl ;
398+
399+ ttbr = readl (dart -> regs + DART_TTBR (dart , sid , idx ));
400+
401+ if (!(ttbr & dart -> hw -> ttbr_valid )) {
402+ dev_err (dart -> dev , "Invalid ttbr[%u] for locked dart\n" ,
403+ idx );
404+ return - EIO ;
405+ }
406+
407+ ttbr &= ~dart -> hw -> ttbr_valid ;
408+
409+ if (dart -> hw -> ttbr_addr_field_shift )
410+ ttbr >>= dart -> hw -> ttbr_addr_field_shift ;
411+ phys = ((phys_addr_t ) ttbr ) << dart -> hw -> ttbr_shift ;
412+
413+ l1_tbl = devm_memremap (dart -> dev , phys , dart -> pgsize ,
414+ MEMREMAP_WB );
415+ if (!l1_tbl )
416+ return - ENOMEM ;
417+
418+ dart -> locked_ttbr [sid ][idx ] = l1_tbl ;
419+ }
420+
421+ return 0 ;
422+ }
423+
424+ static int
425+ apple_dart_hw_unmap_locked_ttbr (struct apple_dart_stream_map * stream_map ,
426+ u8 idx )
427+ {
428+ struct apple_dart * dart = stream_map -> dart ;
429+ int sid ;
430+
431+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
432+ /* TODO: locked L1 table might need to be restored to boot state */
433+ if (dart -> locked_ttbr [sid ][idx ]) {
434+ memset (dart -> locked_ttbr [sid ][idx ], 0 , dart -> pgsize );
435+ devm_memunmap (dart -> dev , dart -> locked_ttbr [sid ][idx ]);
436+ }
437+ dart -> locked_ttbr [sid ][idx ] = NULL ;
438+ }
439+
440+ return 0 ;
441+ }
442+
443+ static int
444+ apple_dart_hw_sync_locked (struct io_pgtable_cfg * cfg ,
445+ struct apple_dart_stream_map * stream_map )
446+ {
447+ struct apple_dart * dart = stream_map -> dart ;
448+ int sid ;
449+
450+ for_each_set_bit (sid , stream_map -> sidmap , dart -> num_streams ) {
451+ for (int idx = 0 ; idx < dart -> hw -> ttbr_count ; idx ++ ) {
452+ u64 * ttbrep = dart -> locked_ttbr [sid ][idx ];
453+ u64 * ptep = cfg -> apple_dart_cfg .ttbr [idx ];
454+ if (!ttbrep || !ptep )
455+ continue ;
456+ for (int entry = 0 ; entry < dart -> pgsize / sizeof (* ptep ); entry ++ )
457+ ttbrep [entry ] = ptep [entry ];
458+ }
459+ }
460+
461+ return 0 ;
462+ }
463+
386464static int
387465apple_dart_t8020_hw_stream_command (struct apple_dart_stream_map * stream_map ,
388466 u32 command )
@@ -504,6 +582,8 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
504582 int i , j ;
505583 struct apple_dart_atomic_stream_map * domain_stream_map ;
506584 struct apple_dart_stream_map stream_map ;
585+ struct io_pgtable_cfg * pgtbl_cfg =
586+ & io_pgtable_ops_to_pgtable (domain -> pgtbl_ops )-> cfg ;
507587
508588 for_each_stream_map (i , domain , domain_stream_map ) {
509589 stream_map .dart = domain_stream_map -> dart ;
@@ -512,6 +592,10 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
512592 stream_map .sidmap [j ] = atomic_long_read (& domain_stream_map -> sidmap [j ]);
513593
514594 WARN_ON (pm_runtime_get_sync (stream_map .dart -> dev ) < 0 );
595+
596+ if (stream_map .dart -> locked )
597+ apple_dart_hw_sync_locked (pgtbl_cfg , & stream_map );
598+
515599 stream_map .dart -> hw -> invalidate_tlb (& stream_map );
516600 pm_runtime_put (stream_map .dart -> dev );
517601 }
@@ -594,6 +678,24 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
594678 stream_map -> dart -> hw -> invalidate_tlb (stream_map );
595679}
596680
681+ static void
682+ apple_dart_setup_translation_locked (struct apple_dart_domain * domain ,
683+ struct apple_dart_stream_map * stream_map )
684+ {
685+ int i ;
686+ struct io_pgtable_cfg * pgtbl_cfg =
687+ & io_pgtable_ops_to_pgtable (domain -> pgtbl_ops )-> cfg ;
688+
689+ /* Locked DARTs are set up by the bootloader. */
690+ for (i = 0 ; i < pgtbl_cfg -> apple_dart_cfg .n_ttbrs ; ++ i )
691+ apple_dart_hw_map_locked_ttbr (stream_map , i );
692+ for (; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
693+ apple_dart_hw_unmap_locked_ttbr (stream_map , i );
694+
695+ apple_dart_hw_sync_locked (pgtbl_cfg , stream_map );
696+ stream_map -> dart -> hw -> invalidate_tlb (stream_map );
697+ }
698+
597699static int apple_dart_finalize_domain (struct apple_dart_domain * dart_domain ,
598700 struct apple_dart_master_cfg * cfg )
599701{
@@ -627,6 +729,42 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
627729 .iommu_dev = dart -> dev ,
628730 };
629731
732+ if (dart -> locked ) {
733+ unsigned long * sidmap ;
734+ int sid ;
735+ u32 ttbr ;
736+
737+ /* Locked DARTs can only have a single stream bound */
738+ sidmap = cfg -> stream_maps [0 ].sidmap ;
739+ sid = find_first_bit (sidmap , dart -> num_streams );
740+
741+ WARN_ON ((sid < 0 ) || bitmap_weight (sidmap , dart -> num_streams ) > 1 );
742+ ttbr = readl (dart -> regs + DART_TTBR (dart , sid , 0 ));
743+
744+ WARN_ON (!(ttbr & dart -> hw -> ttbr_valid ));
745+
746+ /* If the DART is locked, we need to keep the translation level count. */
747+ if (dart -> hw -> tcr_4level && dart -> ias > 36 ) {
748+ if (readl (dart -> regs + DART_TCR (dart , sid )) & dart -> hw -> tcr_4level ) {
749+ if (ias < 37 ) {
750+ dev_info (dart -> dev , "Expanded to ias=37 due to lock\n" );
751+ pgtbl_cfg .ias = 37 ;
752+ }
753+ } else if (ias > 36 ) {
754+ dev_info (dart -> dev , "Limited to ias=36 due to lock\n" );
755+ pgtbl_cfg .ias = 36 ;
756+ if (dart -> dma_min == 0 && dma_max == DMA_BIT_MASK (dart -> ias )) {
757+ dma_max = DMA_BIT_MASK (pgtbl_cfg .ias );
758+ } else if ((dart -> dma_min ^ dma_max ) & ~DMA_BIT_MASK (36 )) {
759+ dev_err (dart -> dev ,
760+ "Invalid DMA range for locked 3-level PT\n" );
761+ ret = - ENOMEM ;
762+ goto done ;
763+ }
764+ }
765+ }
766+ }
767+
630768 dart_domain -> pgtbl_ops = alloc_io_pgtable_ops (dart -> hw -> fmt , & pgtbl_cfg ,
631769 & dart_domain -> domain );
632770 if (!dart_domain -> pgtbl_ops ) {
@@ -707,8 +845,13 @@ static int apple_dart_attach_dev_paging(struct iommu_domain *domain,
707845 if (ret )
708846 goto err ;
709847
710- for_each_stream_map (i , cfg , stream_map )
711- apple_dart_setup_translation (dart_domain , stream_map );
848+ for_each_stream_map (i , cfg , stream_map ) {
849+ if (!stream_map -> dart -> locked )
850+ apple_dart_setup_translation (dart_domain , stream_map );
851+ else
852+ apple_dart_setup_translation_locked (dart_domain ,
853+ stream_map );
854+ }
712855
713856err :
714857 for_each_stream_map (i , cfg , stream_map )
@@ -792,8 +935,16 @@ static struct iommu_device *apple_dart_probe_device(struct device *dev)
792935
793936static void apple_dart_release_device (struct device * dev )
794937{
938+ int i , j ;
939+ struct apple_dart_stream_map * stream_map ;
795940 struct apple_dart_master_cfg * cfg = dev_iommu_priv_get (dev );
796941
942+ for_each_stream_map (j , cfg , stream_map ) {
943+ if (stream_map -> dart -> locked )
944+ for (i = 0 ; i < stream_map -> dart -> hw -> ttbr_count ; ++ i )
945+ apple_dart_hw_unmap_locked_ttbr (stream_map , i );
946+ }
947+
797948 kfree (cfg );
798949}
799950
@@ -1068,6 +1219,11 @@ static const struct iommu_ops apple_dart_iommu_no_bypass_ops = {
10681219 APPLE_DART_IOMMU_COMMON_OPS ()
10691220};
10701221
1222+ static const struct iommu_ops apple_dart_iommu_locked_ops = {
1223+ .def_domain_type = apple_dart_def_domain_type_dma ,
1224+ APPLE_DART_IOMMU_COMMON_OPS ()
1225+ };
1226+
10711227static irqreturn_t apple_dart_t8020_irq (int irq , void * dev )
10721228{
10731229 struct apple_dart * dart = dev ;
@@ -1277,7 +1433,9 @@ static int apple_dart_probe(struct platform_device *pdev)
12771433 if (ret )
12781434 goto err_free_irq ;
12791435
1280- if (!dart -> supports_bypass )
1436+ if (dart -> locked )
1437+ ret = iommu_device_register (& dart -> iommu , & apple_dart_iommu_locked_ops , dev );
1438+ else if (!dart -> supports_bypass )
12811439 ret = iommu_device_register (& dart -> iommu , & apple_dart_iommu_no_bypass_ops , dev );
12821440 else
12831441 ret = iommu_device_register (& dart -> iommu , & apple_dart_iommu_ops , dev );
0 commit comments