cxl: Name interrupts in /proc/interrupt
authorMichael Neuling <mikey@neuling.org>
Fri, 14 Nov 2014 07:09:28 +0000 (18:09 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 18 Nov 2014 02:01:39 +0000 (13:01 +1100)
Currently all interrupts generated by cxl are named "cxl".  This is not very
informative as we can't distinguish between cards, AFUs, error interrupts, user
contexts and user interrupts numbers.  Being able to distinguish them is useful
for setting affinity.

This patch gives each of these names in /proc/interrupts.

A two card CAPI system, with afu0.0 having 2 active contexts each with 4 user
IRQs each, will now look like this:

    % grep cxl /proc/interrupts
    444:          0  OPAL ICS 141312 Level     cxl-card1-err
    445:          0  OPAL ICS 141313 Level     cxl-afu1.0-err
    446:          0  OPAL ICS 141314 Level     cxl-afu1.0
    462:          0  OPAL ICS 2052 Level     cxl-afu0.0-pe0-1
    463:      75517  OPAL ICS 2053 Level     cxl-afu0.0-pe0-2
    468:          0  OPAL ICS 2054 Level     cxl-afu0.0-pe0-3
    469:          0  OPAL ICS 2055 Level     cxl-afu0.0-pe0-4
    470:          0  OPAL ICS 2056 Level     cxl-afu0.0-pe1-1
    471:      75506  OPAL ICS 2057 Level     cxl-afu0.0-pe1-2
    472:          0  OPAL ICS 2058 Level     cxl-afu0.0-pe1-3
    473:          0  OPAL ICS 2059 Level     cxl-afu0.0-pe1-4
    502:       1066  OPAL ICS 2050 Level     cxl-afu0.0
    514:          0  OPAL ICS 2048 Level     cxl-card0-err
    515:          0  OPAL ICS 2049 Level     cxl-afu0.0-err

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
drivers/misc/cxl/cxl.h
drivers/misc/cxl/irq.c

index 64a4aa3a5c5d8d4785c9418b8a437f679ba7d87a..b5b6bda44a009c1732ef7832a9884ddc556ac127 100644 (file)
@@ -336,6 +336,8 @@ struct cxl_sste {
 struct cxl_afu {
        irq_hw_number_t psl_hwirq;
        irq_hw_number_t serr_hwirq;
+       char *err_irq_name;
+       char *psl_irq_name;
        unsigned int serr_virq;
        void __iomem *p1n_mmio;
        void __iomem *p2n_mmio;
@@ -379,6 +381,12 @@ struct cxl_afu {
        bool enabled;
 };
 
+
+struct cxl_irq_name {
+       struct list_head list;
+       char *name;
+};
+
 /*
  * This is a cxl context.  If the PSL is in dedicated mode, there will be one
  * of these per AFU.  If in AFU directed there can be lots of these.
@@ -403,6 +411,7 @@ struct cxl_context {
 
        unsigned long *irq_bitmap; /* Accessed from IRQ context */
        struct cxl_irq_ranges irqs;
+       struct list_head irq_names;
        u64 fault_addr;
        u64 fault_dsisr;
        u64 afu_err;
@@ -444,6 +453,7 @@ struct cxl {
        struct dentry *trace;
        struct dentry *psl_err_chk;
        struct dentry *debugfs;
+       char *irq_name;
        struct bin_attribute cxl_attr;
        int adapter_num;
        int user_irqs;
@@ -563,9 +573,6 @@ int _cxl_afu_deactivate_mode(struct cxl_afu *afu, int mode);
 int cxl_afu_deactivate_mode(struct cxl_afu *afu);
 int cxl_afu_select_best_mode(struct cxl_afu *afu);
 
-unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
-                        irq_handler_t handler, void *cookie);
-void cxl_unmap_irq(unsigned int virq, void *cookie);
 int cxl_register_psl_irq(struct cxl_afu *afu);
 void cxl_release_psl_irq(struct cxl_afu *afu);
 int cxl_register_psl_err_irq(struct cxl *adapter);
index 35fcb3d43dc06d1ac3e3949f46bce5668a0a8e83..c294925f73ee4d918138023288e25f18791d5dbe 100644 (file)
@@ -255,7 +255,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data)
 }
 
 unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
-                        irq_handler_t handler, void *cookie)
+                        irq_handler_t handler, void *cookie, const char *name)
 {
        unsigned int virq;
        int result;
@@ -271,7 +271,7 @@ unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
 
        pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq);
 
-       result = request_irq(virq, handler, 0, "cxl", cookie);
+       result = request_irq(virq, handler, 0, name, cookie);
        if (result) {
                dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result);
                return 0;
@@ -290,14 +290,15 @@ static int cxl_register_one_irq(struct cxl *adapter,
                                irq_handler_t handler,
                                void *cookie,
                                irq_hw_number_t *dest_hwirq,
-                               unsigned int *dest_virq)
+                               unsigned int *dest_virq,
+                               const char *name)
 {
        int hwirq, virq;
 
        if ((hwirq = cxl_alloc_one_irq(adapter)) < 0)
                return hwirq;
 
-       if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie)))
+       if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie, name)))
                goto err;
 
        *dest_hwirq = hwirq;
@@ -314,10 +315,19 @@ int cxl_register_psl_err_irq(struct cxl *adapter)
 {
        int rc;
 
+       adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
+                                     dev_name(&adapter->dev));
+       if (!adapter->irq_name)
+               return -ENOMEM;
+
        if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter,
                                       &adapter->err_hwirq,
-                                      &adapter->err_virq)))
+                                      &adapter->err_virq,
+                                      adapter->irq_name))) {
+               kfree(adapter->irq_name);
+               adapter->irq_name = NULL;
                return rc;
+       }
 
        cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff);
 
@@ -329,6 +339,7 @@ void cxl_release_psl_err_irq(struct cxl *adapter)
        cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
        cxl_unmap_irq(adapter->err_virq, adapter);
        cxl_release_one_irq(adapter, adapter->err_hwirq);
+       kfree(adapter->irq_name);
 }
 
 int cxl_register_serr_irq(struct cxl_afu *afu)
@@ -336,10 +347,18 @@ int cxl_register_serr_irq(struct cxl_afu *afu)
        u64 serr;
        int rc;
 
+       afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
+                                     dev_name(&afu->dev));
+       if (!afu->err_irq_name)
+               return -ENOMEM;
+
        if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu,
                                       &afu->serr_hwirq,
-                                      &afu->serr_virq)))
+                                      &afu->serr_virq, afu->err_irq_name))) {
+               kfree(afu->err_irq_name);
+               afu->err_irq_name = NULL;
                return rc;
+       }
 
        serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
        serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
@@ -353,24 +372,50 @@ void cxl_release_serr_irq(struct cxl_afu *afu)
        cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
        cxl_unmap_irq(afu->serr_virq, afu);
        cxl_release_one_irq(afu->adapter, afu->serr_hwirq);
+       kfree(afu->err_irq_name);
 }
 
 int cxl_register_psl_irq(struct cxl_afu *afu)
 {
-       return cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu,
-                       &afu->psl_hwirq, &afu->psl_virq);
+       int rc;
+
+       afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s",
+                                     dev_name(&afu->dev));
+       if (!afu->psl_irq_name)
+               return -ENOMEM;
+
+       if ((rc = cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu,
+                                   &afu->psl_hwirq, &afu->psl_virq,
+                                   afu->psl_irq_name))) {
+               kfree(afu->psl_irq_name);
+               afu->psl_irq_name = NULL;
+       }
+       return rc;
 }
 
 void cxl_release_psl_irq(struct cxl_afu *afu)
 {
        cxl_unmap_irq(afu->psl_virq, afu);
        cxl_release_one_irq(afu->adapter, afu->psl_hwirq);
+       kfree(afu->psl_irq_name);
+}
+
+void afu_irq_name_free(struct cxl_context *ctx)
+{
+       struct cxl_irq_name *irq_name, *tmp;
+
+       list_for_each_entry_safe(irq_name, tmp, &ctx->irq_names, list) {
+               kfree(irq_name->name);
+               list_del(&irq_name->list);
+               kfree(irq_name);
+       }
 }
 
 int afu_register_irqs(struct cxl_context *ctx, u32 count)
 {
        irq_hw_number_t hwirq;
-       int rc, r, i;
+       int rc, r, i, j = 1;
+       struct cxl_irq_name *irq_name;
 
        if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count)))
                return rc;
@@ -384,15 +429,47 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count)
                                  sizeof(*ctx->irq_bitmap), GFP_KERNEL);
        if (!ctx->irq_bitmap)
                return -ENOMEM;
+
+       /*
+        * Allocate names first.  If any fail, bail out before allocating
+        * actual hardware IRQs.
+        */
+       INIT_LIST_HEAD(&ctx->irq_names);
+       for (r = 1; r < CXL_IRQ_RANGES; r++) {
+               for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+                       irq_name = kmalloc(sizeof(struct cxl_irq_name),
+                                          GFP_KERNEL);
+                       if (!irq_name)
+                               goto out;
+                       irq_name->name = kasprintf(GFP_KERNEL, "cxl-%s-pe%i-%i",
+                                                  dev_name(&ctx->afu->dev),
+                                                  ctx->pe, j);
+                       if (!irq_name->name) {
+                               kfree(irq_name);
+                               goto out;
+                       }
+                       /* Add to tail so next look get the correct order */
+                       list_add_tail(&irq_name->list, &ctx->irq_names);
+                       j++;
+               }
+       }
+
+       /* We've allocated all memory now, so let's do the irq allocations */
+       irq_name = list_first_entry(&ctx->irq_names, struct cxl_irq_name, list);
        for (r = 1; r < CXL_IRQ_RANGES; r++) {
                hwirq = ctx->irqs.offset[r];
                for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
                        cxl_map_irq(ctx->afu->adapter, hwirq,
-                                    cxl_irq_afu, ctx);
+                                   cxl_irq_afu, ctx, irq_name->name);
+                       irq_name = list_next_entry(irq_name, list);
                }
        }
 
        return 0;
+
+out:
+       afu_irq_name_free(ctx);
+       return -ENOMEM;
 }
 
 void afu_release_irqs(struct cxl_context *ctx)
@@ -410,5 +487,6 @@ void afu_release_irqs(struct cxl_context *ctx)
                }
        }
 
+       afu_irq_name_free(ctx);
        cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
 }