@@ -46,6 +46,7 @@ struct viommu_dev {
4646 struct iommu_domain_geometry geometry ;
4747 u64 pgsize_bitmap ;
4848 u8 domain_bits ;
49+ u32 probe_size ;
4950};
5051
5152struct viommu_mapping {
@@ -67,8 +68,10 @@ struct viommu_domain {
6768};
6869
6970struct viommu_endpoint {
71+ struct device * dev ;
7072 struct viommu_dev * viommu ;
7173 struct viommu_domain * vdomain ;
74+ struct list_head resv_regions ;
7275};
7376
7477struct viommu_request {
@@ -119,6 +122,9 @@ static off_t viommu_get_write_desc_offset(struct viommu_dev *viommu,
119122{
120123 size_t tail_size = sizeof (struct virtio_iommu_req_tail );
121124
125+ if (req -> type == VIRTIO_IOMMU_T_PROBE )
126+ return len - viommu -> probe_size - tail_size ;
127+
122128 return len - tail_size ;
123129}
124130
@@ -393,6 +399,110 @@ static int viommu_replay_mappings(struct viommu_domain *vdomain)
393399 return ret ;
394400}
395401
402+ static int viommu_add_resv_mem (struct viommu_endpoint * vdev ,
403+ struct virtio_iommu_probe_resv_mem * mem ,
404+ size_t len )
405+ {
406+ size_t size ;
407+ u64 start64 , end64 ;
408+ phys_addr_t start , end ;
409+ struct iommu_resv_region * region = NULL ;
410+ unsigned long prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO ;
411+
412+ start = start64 = le64_to_cpu (mem -> start );
413+ end = end64 = le64_to_cpu (mem -> end );
414+ size = end64 - start64 + 1 ;
415+
416+ /* Catch any overflow, including the unlikely end64 - start64 + 1 = 0 */
417+ if (start != start64 || end != end64 || size < end64 - start64 )
418+ return - EOVERFLOW ;
419+
420+ if (len < sizeof (* mem ))
421+ return - EINVAL ;
422+
423+ switch (mem -> subtype ) {
424+ default :
425+ dev_warn (vdev -> dev , "unknown resv mem subtype 0x%x\n" ,
426+ mem -> subtype );
427+ /* Fall-through */
428+ case VIRTIO_IOMMU_RESV_MEM_T_RESERVED :
429+ region = iommu_alloc_resv_region (start , size , 0 ,
430+ IOMMU_RESV_RESERVED );
431+ break ;
432+ case VIRTIO_IOMMU_RESV_MEM_T_MSI :
433+ region = iommu_alloc_resv_region (start , size , prot ,
434+ IOMMU_RESV_MSI );
435+ break ;
436+ }
437+ if (!region )
438+ return - ENOMEM ;
439+
440+ list_add (& vdev -> resv_regions , & region -> list );
441+ return 0 ;
442+ }
443+
444+ static int viommu_probe_endpoint (struct viommu_dev * viommu , struct device * dev )
445+ {
446+ int ret ;
447+ u16 type , len ;
448+ size_t cur = 0 ;
449+ size_t probe_len ;
450+ struct virtio_iommu_req_probe * probe ;
451+ struct virtio_iommu_probe_property * prop ;
452+ struct iommu_fwspec * fwspec = dev_iommu_fwspec_get (dev );
453+ struct viommu_endpoint * vdev = fwspec -> iommu_priv ;
454+
455+ if (!fwspec -> num_ids )
456+ return - EINVAL ;
457+
458+ probe_len = sizeof (* probe ) + viommu -> probe_size +
459+ sizeof (struct virtio_iommu_req_tail );
460+ probe = kzalloc (probe_len , GFP_KERNEL );
461+ if (!probe )
462+ return - ENOMEM ;
463+
464+ probe -> head .type = VIRTIO_IOMMU_T_PROBE ;
465+ /*
466+ * For now, assume that properties of an endpoint that outputs multiple
467+ * IDs are consistent. Only probe the first one.
468+ */
469+ probe -> endpoint = cpu_to_le32 (fwspec -> ids [0 ]);
470+
471+ ret = viommu_send_req_sync (viommu , probe , probe_len );
472+ if (ret )
473+ goto out_free ;
474+
475+ prop = (void * )probe -> properties ;
476+ type = le16_to_cpu (prop -> type ) & VIRTIO_IOMMU_PROBE_T_MASK ;
477+
478+ while (type != VIRTIO_IOMMU_PROBE_T_NONE &&
479+ cur < viommu -> probe_size ) {
480+ len = le16_to_cpu (prop -> length ) + sizeof (* prop );
481+
482+ switch (type ) {
483+ case VIRTIO_IOMMU_PROBE_T_RESV_MEM :
484+ ret = viommu_add_resv_mem (vdev , (void * )prop , len );
485+ break ;
486+ default :
487+ dev_err (dev , "unknown viommu prop 0x%x\n" , type );
488+ }
489+
490+ if (ret )
491+ dev_err (dev , "failed to parse viommu prop 0x%x\n" , type );
492+
493+ cur += len ;
494+ if (cur >= viommu -> probe_size )
495+ break ;
496+
497+ prop = (void * )probe -> properties + cur ;
498+ type = le16_to_cpu (prop -> type ) & VIRTIO_IOMMU_PROBE_T_MASK ;
499+ }
500+
501+ out_free :
502+ kfree (probe );
503+ return ret ;
504+ }
505+
396506/* IOMMU API */
397507
398508static struct iommu_domain * viommu_domain_alloc (unsigned type )
@@ -614,15 +724,34 @@ static void viommu_iotlb_sync(struct iommu_domain *domain)
614724
615725static void viommu_get_resv_regions (struct device * dev , struct list_head * head )
616726{
617- struct iommu_resv_region * region ;
727+ struct iommu_resv_region * entry , * new_entry , * msi = NULL ;
728+ struct iommu_fwspec * fwspec = dev_iommu_fwspec_get (dev );
729+ struct viommu_endpoint * vdev = fwspec -> iommu_priv ;
618730 int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO ;
619731
620- region = iommu_alloc_resv_region (MSI_IOVA_BASE , MSI_IOVA_LENGTH , prot ,
621- IOMMU_RESV_SW_MSI );
622- if (!region )
623- return ;
732+ list_for_each_entry (entry , & vdev -> resv_regions , list ) {
733+ if (entry -> type == IOMMU_RESV_MSI )
734+ msi = entry ;
735+
736+ new_entry = kmemdup (entry , sizeof (* entry ), GFP_KERNEL );
737+ if (!new_entry )
738+ return ;
739+ list_add_tail (& new_entry -> list , head );
740+ }
741+
742+ /*
743+ * If the device didn't register any bypass MSI window, add a
744+ * software-mapped region.
745+ */
746+ if (!msi ) {
747+ msi = iommu_alloc_resv_region (MSI_IOVA_BASE , MSI_IOVA_LENGTH ,
748+ prot , IOMMU_RESV_SW_MSI );
749+ if (!msi )
750+ return ;
751+
752+ list_add_tail (& msi -> list , head );
753+ }
624754
625- list_add_tail (& region -> list , head );
626755 iommu_dma_get_resv_regions (dev , head );
627756}
628757
@@ -670,9 +799,18 @@ static int viommu_add_device(struct device *dev)
670799 if (!vdev )
671800 return - ENOMEM ;
672801
802+ vdev -> dev = dev ;
673803 vdev -> viommu = viommu ;
804+ INIT_LIST_HEAD (& vdev -> resv_regions );
674805 fwspec -> iommu_priv = vdev ;
675806
807+ if (viommu -> probe_size ) {
808+ /* Get additional information for this endpoint */
809+ ret = viommu_probe_endpoint (viommu , dev );
810+ if (ret )
811+ goto err_free_dev ;
812+ }
813+
676814 ret = iommu_device_link (& viommu -> iommu , dev );
677815 if (ret )
678816 goto err_free_dev ;
@@ -694,6 +832,7 @@ static int viommu_add_device(struct device *dev)
694832err_unlink_dev :
695833 iommu_device_unlink (& viommu -> iommu , dev );
696834err_free_dev :
835+ viommu_put_resv_regions (dev , & vdev -> resv_regions );
697836 kfree (vdev );
698837
699838 return ret ;
@@ -711,6 +850,7 @@ static void viommu_remove_device(struct device *dev)
711850
712851 iommu_group_remove_device (dev );
713852 iommu_device_unlink (& vdev -> viommu -> iommu , dev );
853+ viommu_put_resv_regions (dev , & vdev -> resv_regions );
714854 kfree (vdev );
715855}
716856
@@ -810,6 +950,10 @@ static int viommu_probe(struct virtio_device *vdev)
810950 struct virtio_iommu_config , domain_bits ,
811951 & viommu -> domain_bits );
812952
953+ virtio_cread_feature (vdev , VIRTIO_IOMMU_F_PROBE ,
954+ struct virtio_iommu_config , probe_size ,
955+ & viommu -> probe_size );
956+
813957 viommu -> geometry = (struct iommu_domain_geometry ) {
814958 .aperture_start = input_start ,
815959 .aperture_end = input_end ,
@@ -891,6 +1035,7 @@ static unsigned int features[] = {
8911035 VIRTIO_IOMMU_F_MAP_UNMAP ,
8921036 VIRTIO_IOMMU_F_DOMAIN_BITS ,
8931037 VIRTIO_IOMMU_F_INPUT_RANGE ,
1038+ VIRTIO_IOMMU_F_PROBE ,
8941039};
8951040
8961041static struct virtio_device_id id_table [] = {
0 commit comments