Merge branches 'iommu/fixes', 'arm/smmu', 'ppc/pamu', 'virtio', 'x86/vt-d', 'core...
[platform/kernel/linux-starfive.git] / drivers / iommu / amd / iommu.c
index 4a31464..dc48108 100644 (file)
@@ -845,6 +845,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
        (MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
         MMIO_STATUS_EVT_INT_MASK | \
         MMIO_STATUS_PPR_INT_MASK | \
+        MMIO_STATUS_GALOG_OVERFLOW_MASK | \
         MMIO_STATUS_GALOG_INT_MASK)
 
 irqreturn_t amd_iommu_int_thread(int irq, void *data)
@@ -868,10 +869,16 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
                }
 
 #ifdef CONFIG_IRQ_REMAP
-               if (status & MMIO_STATUS_GALOG_INT_MASK) {
+               if (status & (MMIO_STATUS_GALOG_INT_MASK |
+                             MMIO_STATUS_GALOG_OVERFLOW_MASK)) {
                        pr_devel("Processing IOMMU GA Log\n");
                        iommu_poll_ga_log(iommu);
                }
+
+               if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) {
+                       pr_info_ratelimited("IOMMU GA Log overflow\n");
+                       amd_iommu_restart_ga_log(iommu);
+               }
 #endif
 
                if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {
@@ -1175,11 +1182,11 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
        if (!iommu->need_sync)
                return 0;
 
-       raw_spin_lock_irqsave(&iommu->lock, flags);
-
-       data = ++iommu->cmd_sem_val;
+       data = atomic64_add_return(1, &iommu->cmd_sem_val);
        build_completion_wait(&cmd, iommu, data);
 
+       raw_spin_lock_irqsave(&iommu->lock, flags);
+
        ret = __iommu_queue_command_sync(iommu, &cmd, false);
        if (ret)
                goto out_unlock;
@@ -1266,6 +1273,9 @@ static void amd_iommu_flush_irt_all(struct amd_iommu *iommu)
        u32 devid;
        u16 last_bdf = iommu->pci_seg->last_bdf;
 
+       if (iommu->irtcachedis_enabled)
+               return;
+
        for (devid = 0; devid <= last_bdf; devid++)
                iommu_flush_irt(iommu, devid);
 
@@ -2067,14 +2077,10 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
 {
        struct io_pgtable_ops *pgtbl_ops;
        struct protection_domain *domain;
-       int pgtable = amd_iommu_pgtable;
+       int pgtable;
        int mode = DEFAULT_PGTABLE_LEVEL;
        int ret;
 
-       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
-       if (!domain)
-               return NULL;
-
        /*
         * Force IOMMU v1 page table when iommu=pt and
         * when allocating domain for pass-through devices.
@@ -2084,8 +2090,16 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
                mode = PAGE_MODE_NONE;
        } else if (type == IOMMU_DOMAIN_UNMANAGED) {
                pgtable = AMD_IOMMU_V1;
+       } else if (type == IOMMU_DOMAIN_DMA || type == IOMMU_DOMAIN_DMA_FQ) {
+               pgtable = amd_iommu_pgtable;
+       } else {
+               return NULL;
        }
 
+       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+       if (!domain)
+               return NULL;
+
        switch (pgtable) {
        case AMD_IOMMU_V1:
                ret = protection_domain_init_v1(domain, mode);
@@ -2118,6 +2132,15 @@ out_err:
        return NULL;
 }
 
+static inline u64 dma_max_address(void)
+{
+       if (amd_iommu_pgtable == AMD_IOMMU_V1)
+               return ~0ULL;
+
+       /* V2 with 4/5 level page table */
+       return ((1ULL << PM_LEVEL_SHIFT(amd_iommu_gpt_level)) - 1);
+}
+
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *domain;
@@ -2134,7 +2157,7 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
                return NULL;
 
        domain->domain.geometry.aperture_start = 0;
-       domain->domain.geometry.aperture_end   = ~0ULL;
+       domain->domain.geometry.aperture_end   = dma_max_address();
        domain->domain.geometry.force_aperture = true;
 
        return &domain->domain;
@@ -2293,6 +2316,8 @@ static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap)
                return amdr_ivrs_remap_support;
        case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
                return true;
+       case IOMMU_CAP_DEFERRED_FLUSH:
+               return true;
        default:
                break;
        }
@@ -2387,7 +2412,7 @@ static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
        unsigned long flags;
 
        spin_lock_irqsave(&dom->lock, flags);
-       domain_flush_pages(dom, gather->start, gather->end - gather->start, 1);
+       domain_flush_pages(dom, gather->start, gather->end - gather->start + 1, 1);
        amd_iommu_domain_flush_complete(dom);
        spin_unlock_irqrestore(&dom->lock, flags);
 }
@@ -2802,6 +2827,32 @@ EXPORT_SYMBOL(amd_iommu_device_info);
 static struct irq_chip amd_ir_chip;
 static DEFINE_SPINLOCK(iommu_table_lock);
 
+static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
+{
+       int ret;
+       u64 data;
+       unsigned long flags;
+       struct iommu_cmd cmd, cmd2;
+
+       if (iommu->irtcachedis_enabled)
+               return;
+
+       build_inv_irt(&cmd, devid);
+       data = atomic64_add_return(1, &iommu->cmd_sem_val);
+       build_completion_wait(&cmd2, iommu, data);
+
+       raw_spin_lock_irqsave(&iommu->lock, flags);
+       ret = __iommu_queue_command_sync(iommu, &cmd, true);
+       if (ret)
+               goto out;
+       ret = __iommu_queue_command_sync(iommu, &cmd2, false);
+       if (ret)
+               goto out;
+       wait_on_sem(iommu, data);
+out:
+       raw_spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
 static void set_dte_irq_entry(struct amd_iommu *iommu, u16 devid,
                              struct irq_remap_table *table)
 {
@@ -3001,7 +3052,7 @@ out:
 }
 
 static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
-                         struct irte_ga *irte, struct amd_ir_data *data)
+                         struct irte_ga *irte)
 {
        bool ret;
        struct irq_remap_table *table;
@@ -3028,13 +3079,9 @@ static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
         */
        WARN_ON(!ret);
 
-       if (data)
-               data->ref = entry;
-
        raw_spin_unlock_irqrestore(&table->lock, flags);
 
-       iommu_flush_irt(iommu, devid);
-       iommu_completion_wait(iommu);
+       iommu_flush_irt_and_complete(iommu, devid);
 
        return 0;
 }
@@ -3053,8 +3100,7 @@ static int modify_irte(struct amd_iommu *iommu,
        table->table[index] = irte->val;
        raw_spin_unlock_irqrestore(&table->lock, flags);
 
-       iommu_flush_irt(iommu, devid);
-       iommu_completion_wait(iommu);
+       iommu_flush_irt_and_complete(iommu, devid);
 
        return 0;
 }
@@ -3072,8 +3118,7 @@ static void free_irte(struct amd_iommu *iommu, u16 devid, int index)
        iommu->irte_ops->clear_allocated(table, index);
        raw_spin_unlock_irqrestore(&table->lock, flags);
 
-       iommu_flush_irt(iommu, devid);
-       iommu_completion_wait(iommu);
+       iommu_flush_irt_and_complete(iommu, devid);
 }
 
 static void irte_prepare(void *entry,
@@ -3119,7 +3164,7 @@ static void irte_ga_activate(struct amd_iommu *iommu, void *entry, u16 devid, u1
        struct irte_ga *irte = (struct irte_ga *) entry;
 
        irte->lo.fields_remap.valid = 1;
-       modify_irte_ga(iommu, devid, index, irte, NULL);
+       modify_irte_ga(iommu, devid, index, irte);
 }
 
 static void irte_deactivate(struct amd_iommu *iommu, void *entry, u16 devid, u16 index)
@@ -3135,7 +3180,7 @@ static void irte_ga_deactivate(struct amd_iommu *iommu, void *entry, u16 devid,
        struct irte_ga *irte = (struct irte_ga *) entry;
 
        irte->lo.fields_remap.valid = 0;
-       modify_irte_ga(iommu, devid, index, irte, NULL);
+       modify_irte_ga(iommu, devid, index, irte);
 }
 
 static void irte_set_affinity(struct amd_iommu *iommu, void *entry, u16 devid, u16 index,
@@ -3159,7 +3204,7 @@ static void irte_ga_set_affinity(struct amd_iommu *iommu, void *entry, u16 devid
                                        APICID_TO_IRTE_DEST_LO(dest_apicid);
                irte->hi.fields.destination =
                                        APICID_TO_IRTE_DEST_HI(dest_apicid);
-               modify_irte_ga(iommu, devid, index, irte, NULL);
+               modify_irte_ga(iommu, devid, index, irte);
        }
 }
 
@@ -3493,8 +3538,7 @@ int amd_iommu_activate_guest_mode(void *data)
        struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
        u64 valid;
 
-       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
-           !entry || entry->lo.fields_vapic.guest_mode)
+       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || !entry)
                return 0;
 
        valid = entry->lo.fields_vapic.valid;
@@ -3510,7 +3554,7 @@ int amd_iommu_activate_guest_mode(void *data)
        entry->lo.fields_vapic.ga_tag      = ir_data->ga_tag;
 
        return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
-                             ir_data->irq_2_irte.index, entry, ir_data);
+                             ir_data->irq_2_irte.index, entry);
 }
 EXPORT_SYMBOL(amd_iommu_activate_guest_mode);
 
@@ -3540,7 +3584,7 @@ int amd_iommu_deactivate_guest_mode(void *data)
                                APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
 
        return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
-                             ir_data->irq_2_irte.index, entry, ir_data);
+                             ir_data->irq_2_irte.index, entry);
 }
 EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 
@@ -3702,44 +3746,26 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
 
 int amd_iommu_update_ga(int cpu, bool is_run, void *data)
 {
-       unsigned long flags;
-       struct amd_iommu *iommu;
-       struct irq_remap_table *table;
        struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
-       int devid = ir_data->irq_2_irte.devid;
        struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
-       struct irte_ga *ref = (struct irte_ga *) ir_data->ref;
 
        if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
-           !ref || !entry || !entry->lo.fields_vapic.guest_mode)
+           !entry || !entry->lo.fields_vapic.guest_mode)
                return 0;
 
-       iommu = ir_data->iommu;
-       if (!iommu)
-               return -ENODEV;
-
-       table = get_irq_table(iommu, devid);
-       if (!table)
+       if (!ir_data->iommu)
                return -ENODEV;
 
-       raw_spin_lock_irqsave(&table->lock, flags);
-
-       if (ref->lo.fields_vapic.guest_mode) {
-               if (cpu >= 0) {
-                       ref->lo.fields_vapic.destination =
-                                               APICID_TO_IRTE_DEST_LO(cpu);
-                       ref->hi.fields.destination =
-                                               APICID_TO_IRTE_DEST_HI(cpu);
-               }
-               ref->lo.fields_vapic.is_run = is_run;
-               barrier();
+       if (cpu >= 0) {
+               entry->lo.fields_vapic.destination =
+                                       APICID_TO_IRTE_DEST_LO(cpu);
+               entry->hi.fields.destination =
+                                       APICID_TO_IRTE_DEST_HI(cpu);
        }
+       entry->lo.fields_vapic.is_run = is_run;
 
-       raw_spin_unlock_irqrestore(&table->lock, flags);
-
-       iommu_flush_irt(iommu, devid);
-       iommu_completion_wait(iommu);
-       return 0;
+       return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
+                             ir_data->irq_2_irte.index, entry);
 }
 EXPORT_SYMBOL(amd_iommu_update_ga);
 #endif