aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2014-05-15 06:40:42 -0400
committerJoerg Roedel <jroedel@suse.de>2014-05-26 05:18:22 -0400
commit192d2045707b25b984436eabfbfd3c8f1ada5a56 (patch)
tree56c707d26e8e2c35b75f269f87ab8146e4e89fd8 /drivers/iommu
parentd25a2a16f0889de4a1cd8639896f35dc9465f6f5 (diff)
iommu/ipmmu-vmsa: Refactor micro-TLB lookup
Cache the micro-TLB number in archdata allocated in the .add_device handler instead of looking it up when the deviced is attached and detached. This simplifies the .attach_dev and .detach_dev operations and prepares for DT support. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/ipmmu-vmsa.c92
1 files changed, 52 insertions, 40 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index b084530babf4..1949f3c55679 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -44,6 +44,11 @@ struct ipmmu_vmsa_domain {
44 pgd_t *pgd; 44 pgd_t *pgd;
45}; 45};
46 46
47struct ipmmu_vmsa_archdata {
48 struct ipmmu_vmsa_device *mmu;
49 unsigned int utlb;
50};
51
47static DEFINE_SPINLOCK(ipmmu_devices_lock); 52static DEFINE_SPINLOCK(ipmmu_devices_lock);
48static LIST_HEAD(ipmmu_devices); 53static LIST_HEAD(ipmmu_devices);
49 54
@@ -265,14 +270,19 @@ static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain)
265 * Enable MMU translation for the microTLB. 270 * Enable MMU translation for the microTLB.
266 */ 271 */
267static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain, 272static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
268 const struct ipmmu_vmsa_master *master) 273 unsigned int utlb)
269{ 274{
270 struct ipmmu_vmsa_device *mmu = domain->mmu; 275 struct ipmmu_vmsa_device *mmu = domain->mmu;
271 276
277 /*
278 * TODO: Reference-count the microTLB as several bus masters can be
279 * connected to the same microTLB.
280 */
281
272 /* TODO: What should we set the ASID to ? */ 282 /* TODO: What should we set the ASID to ? */
273 ipmmu_write(mmu, IMUASID(master->utlb), 0); 283 ipmmu_write(mmu, IMUASID(utlb), 0);
274 /* TODO: Do we need to flush the microTLB ? */ 284 /* TODO: Do we need to flush the microTLB ? */
275 ipmmu_write(mmu, IMUCTR(master->utlb), 285 ipmmu_write(mmu, IMUCTR(utlb),
276 IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH | 286 IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH |
277 IMUCTR_MMUEN); 287 IMUCTR_MMUEN);
278} 288}
@@ -281,11 +291,11 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
281 * Disable MMU translation for the microTLB. 291 * Disable MMU translation for the microTLB.
282 */ 292 */
283static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain, 293static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
284 const struct ipmmu_vmsa_master *master) 294 unsigned int utlb)
285{ 295{
286 struct ipmmu_vmsa_device *mmu = domain->mmu; 296 struct ipmmu_vmsa_device *mmu = domain->mmu;
287 297
288 ipmmu_write(mmu, IMUCTR(master->utlb), 0); 298 ipmmu_write(mmu, IMUCTR(utlb), 0);
289} 299}
290 300
291static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr, 301static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr,
@@ -674,21 +684,6 @@ static int ipmmu_handle_mapping(struct ipmmu_vmsa_domain *domain,
674 * IOMMU Operations 684 * IOMMU Operations
675 */ 685 */
676 686
677static const struct ipmmu_vmsa_master *
678ipmmu_find_master(struct ipmmu_vmsa_device *ipmmu, struct device *dev)
679{
680 const struct ipmmu_vmsa_master *master = ipmmu->pdata->masters;
681 const char *devname = dev_name(dev);
682 unsigned int i;
683
684 for (i = 0; i < ipmmu->pdata->num_masters; ++i, ++master) {
685 if (strcmp(master->name, devname) == 0)
686 return master;
687 }
688
689 return NULL;
690}
691
692static int ipmmu_domain_init(struct iommu_domain *io_domain) 687static int ipmmu_domain_init(struct iommu_domain *io_domain)
693{ 688{
694 struct ipmmu_vmsa_domain *domain; 689 struct ipmmu_vmsa_domain *domain;
@@ -727,9 +722,9 @@ static void ipmmu_domain_destroy(struct iommu_domain *io_domain)
727static int ipmmu_attach_device(struct iommu_domain *io_domain, 722static int ipmmu_attach_device(struct iommu_domain *io_domain,
728 struct device *dev) 723 struct device *dev)
729{ 724{
730 struct ipmmu_vmsa_device *mmu = dev->archdata.iommu; 725 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
726 struct ipmmu_vmsa_device *mmu = archdata->mmu;
731 struct ipmmu_vmsa_domain *domain = io_domain->priv; 727 struct ipmmu_vmsa_domain *domain = io_domain->priv;
732 const struct ipmmu_vmsa_master *master;
733 unsigned long flags; 728 unsigned long flags;
734 int ret = 0; 729 int ret = 0;
735 730
@@ -759,11 +754,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
759 if (ret < 0) 754 if (ret < 0)
760 return ret; 755 return ret;
761 756
762 master = ipmmu_find_master(mmu, dev); 757 ipmmu_utlb_enable(domain, archdata->utlb);
763 if (!master)
764 return -EINVAL;
765
766 ipmmu_utlb_enable(domain, master);
767 758
768 return 0; 759 return 0;
769} 760}
@@ -771,14 +762,10 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
771static void ipmmu_detach_device(struct iommu_domain *io_domain, 762static void ipmmu_detach_device(struct iommu_domain *io_domain,
772 struct device *dev) 763 struct device *dev)
773{ 764{
765 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
774 struct ipmmu_vmsa_domain *domain = io_domain->priv; 766 struct ipmmu_vmsa_domain *domain = io_domain->priv;
775 const struct ipmmu_vmsa_master *master;
776 767
777 master = ipmmu_find_master(domain->mmu, dev); 768 ipmmu_utlb_disable(domain, archdata->utlb);
778 if (!master)
779 return;
780
781 ipmmu_utlb_disable(domain, master);
782 769
783 /* 770 /*
784 * TODO: Optimize by disabling the context when no device is attached. 771 * TODO: Optimize by disabling the context when no device is attached.
@@ -839,11 +826,26 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
839 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); 826 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK);
840} 827}
841 828
829static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev)
830{
831 const struct ipmmu_vmsa_master *master = mmu->pdata->masters;
832 const char *devname = dev_name(dev);
833 unsigned int i;
834
835 for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) {
836 if (strcmp(master->name, devname) == 0)
837 return master->utlb;
838 }
839
840 return -1;
841}
842
842static int ipmmu_add_device(struct device *dev) 843static int ipmmu_add_device(struct device *dev)
843{ 844{
844 const struct ipmmu_vmsa_master *master = NULL; 845 struct ipmmu_vmsa_archdata *archdata;
845 struct ipmmu_vmsa_device *mmu; 846 struct ipmmu_vmsa_device *mmu;
846 struct iommu_group *group; 847 struct iommu_group *group;
848 int utlb = -1;
847 int ret; 849 int ret;
848 850
849 if (dev->archdata.iommu) { 851 if (dev->archdata.iommu) {
@@ -856,10 +858,10 @@ static int ipmmu_add_device(struct device *dev)
856 spin_lock(&ipmmu_devices_lock); 858 spin_lock(&ipmmu_devices_lock);
857 859
858 list_for_each_entry(mmu, &ipmmu_devices, list) { 860 list_for_each_entry(mmu, &ipmmu_devices, list) {
859 master = ipmmu_find_master(mmu, dev); 861 utlb = ipmmu_find_utlb(mmu, dev);
860 if (master) { 862 if (utlb >= 0) {
861 /* 863 /*
862 * TODO Take a reference to the master to protect 864 * TODO Take a reference to the MMU to protect
863 * against device removal. 865 * against device removal.
864 */ 866 */
865 break; 867 break;
@@ -868,10 +870,10 @@ static int ipmmu_add_device(struct device *dev)
868 870
869 spin_unlock(&ipmmu_devices_lock); 871 spin_unlock(&ipmmu_devices_lock);
870 872
871 if (!master) 873 if (utlb < 0)
872 return -ENODEV; 874 return -ENODEV;
873 875
874 if (!master->utlb >= mmu->num_utlbs) 876 if (utlb >= mmu->num_utlbs)
875 return -EINVAL; 877 return -EINVAL;
876 878
877 /* Create a device group and add the device to it. */ 879 /* Create a device group and add the device to it. */
@@ -889,7 +891,15 @@ static int ipmmu_add_device(struct device *dev)
889 return ret; 891 return ret;
890 } 892 }
891 893
892 dev->archdata.iommu = mmu; 894 archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
895 if (!archdata) {
896 ret = -ENOMEM;
897 goto error;
898 }
899
900 archdata->mmu = mmu;
901 archdata->utlb = utlb;
902 dev->archdata.iommu = archdata;
893 903
894 /* 904 /*
895 * Create the ARM mapping, used by the ARM DMA mapping core to allocate 905 * Create the ARM mapping, used by the ARM DMA mapping core to allocate
@@ -923,6 +933,7 @@ static int ipmmu_add_device(struct device *dev)
923 return 0; 933 return 0;
924 934
925error: 935error:
936 kfree(dev->archdata.iommu);
926 dev->archdata.iommu = NULL; 937 dev->archdata.iommu = NULL;
927 iommu_group_remove_device(dev); 938 iommu_group_remove_device(dev);
928 return ret; 939 return ret;
@@ -932,6 +943,7 @@ static void ipmmu_remove_device(struct device *dev)
932{ 943{
933 arm_iommu_detach_device(dev); 944 arm_iommu_detach_device(dev);
934 iommu_group_remove_device(dev); 945 iommu_group_remove_device(dev);
946 kfree(dev->archdata.iommu);
935 dev->archdata.iommu = NULL; 947 dev->archdata.iommu = NULL;
936} 948}
937 949