]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
ocxl: Allow contexts to be attached with a NULL mm
authorAlastair D'Silva <alastair@d-silva.org>
Thu, 20 Jun 2019 04:12:01 +0000 (14:12 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2019 19:29:47 +0000 (21:29 +0200)
If an OpenCAPI context is to be used directly by a kernel driver, there
may not be a suitable mm to use.

The patch makes the mm parameter to ocxl_context_attach optional.

Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
Acked-by: Andrew Donnellan <ajd@linux.ibm.com>
Acked-by: Frederic Barrat <fbarrat@linux.ibm.com>
Acked-by: Nicholas Piggin <npiggin@gmail.com>
Link: https://lore.kernel.org/r/20190620041203.12274-1-alastair@au1.ibm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/mm/book3s64/radix_tlb.c
drivers/misc/ocxl/context.c
drivers/misc/ocxl/link.c

index bb98356813154a6deccada9d1b29a03e89d686d5..ce8a77fae6a74d35f4c63780e6a55e58480020be 100644 (file)
@@ -666,6 +666,11 @@ EXPORT_SYMBOL(radix__flush_tlb_page);
 #define radix__flush_all_mm radix__local_flush_all_mm
 #endif /* CONFIG_SMP */
 
+/*
+ * If kernel TLBIs ever become local rather than global, then
+ * drivers/misc/ocxl/link.c:ocxl_link_add_pe will need some work, as it
+ * assumes kernel TLBIs are global.
+ */
 void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        _tlbie_pid(0, RIC_FLUSH_ALL);
index bab9c9364184e031c42a6e50f9f4cfaf832140e9..994563a078eb9f249b8576ddb0ab69abaa4de434 100644 (file)
@@ -69,6 +69,7 @@ static void xsl_fault_error(void *data, u64 addr, u64 dsisr)
 int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
 {
        int rc;
+       unsigned long pidr = 0;
 
        // Locks both status & tidr
        mutex_lock(&ctx->status_mutex);
@@ -77,9 +78,11 @@ int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
                goto out;
        }
 
-       rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid,
-                       mm->context.id, ctx->tidr, amr, mm,
-                       xsl_fault_error, ctx);
+       if (mm)
+               pidr = mm->context.id;
+
+       rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid, pidr, ctx->tidr,
+                             amr, mm, xsl_fault_error, ctx);
        if (rc)
                goto out;
 
index cce5b0d6450592bed691383a64bae52d66d496c9..58d111afd9f6ab5217812334ae2da26c4dc01b16 100644 (file)
@@ -224,6 +224,17 @@ static irqreturn_t xsl_fault_handler(int irq, void *data)
                ack_irq(spa, ADDRESS_ERROR);
                return IRQ_HANDLED;
        }
+
+       if (!pe_data->mm) {
+               /*
+                * translation fault from a kernel context - an OpenCAPI
+                * device tried to access a bad kernel address
+                */
+               rcu_read_unlock();
+               pr_warn("Unresolved OpenCAPI xsl fault in kernel context\n");
+               ack_irq(spa, ADDRESS_ERROR);
+               return IRQ_HANDLED;
+       }
        WARN_ON(pe_data->mm->context.id != pid);
 
        if (mmget_not_zero(pe_data->mm)) {
@@ -523,7 +534,13 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
        pe->amr = cpu_to_be64(amr);
        pe->software_state = cpu_to_be32(SPA_PE_VALID);
 
-       mm_context_add_copro(mm);
+       /*
+        * For user contexts, register a copro so that TLBIs are seen
+        * by the nest MMU. If we have a kernel context, TLBIs are
+        * already global.
+        */
+       if (mm)
+               mm_context_add_copro(mm);
        /*
         * Barrier is to make sure PE is visible in the SPA before it
         * is used by the device. It also helps with the global TLBI
@@ -546,7 +563,8 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
         * have a reference on mm_users. Incrementing mm_count solves
         * the problem.
         */
-       mmgrab(mm);
+       if (mm)
+               mmgrab(mm);
        trace_ocxl_context_add(current->pid, spa->spa_mem, pasid, pidr, tidr);
 unlock:
        mutex_unlock(&spa->spa_lock);
@@ -652,8 +670,10 @@ int ocxl_link_remove_pe(void *link_handle, int pasid)
        if (!pe_data) {
                WARN(1, "Couldn't find pe data when removing PE\n");
        } else {
-               mm_context_remove_copro(pe_data->mm);
-               mmdrop(pe_data->mm);
+               if (pe_data->mm) {
+                       mm_context_remove_copro(pe_data->mm);
+                       mmdrop(pe_data->mm);
+               }
                kfree_rcu(pe_data, rcu);
        }
 unlock: