s390/airq: provide cacheline aligned ivs
authorSebastian Ott <sebott@linux.ibm.com>
Wed, 27 Feb 2019 12:56:08 +0000 (13:56 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 29 Apr 2019 08:47:01 +0000 (10:47 +0200)
Provide the ability to create cachesize aligned interrupt vectors.
These will be used for per-CPU interrupt vectors.

Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/airq.h
drivers/s390/cio/airq.c

index 91e78df365c764d60d7779f3dd8add45fbcf50dc..c10d2ee2dfda4df8bc717d6800c5cd7f30d9e06d 100644 (file)
@@ -35,13 +35,15 @@ struct airq_iv {
        unsigned int *data;     /* 32 bit value associated with each bit */
        unsigned long bits;     /* Number of bits in the vector */
        unsigned long end;      /* Number of highest allocated bit + 1 */
+       unsigned long flags;    /* Allocation flags */
        spinlock_t lock;        /* Lock to protect alloc & free */
 };
 
-#define AIRQ_IV_ALLOC  1       /* Use an allocation bit mask */
-#define AIRQ_IV_BITLOCK        2       /* Allocate the lock bit mask */
-#define AIRQ_IV_PTR    4       /* Allocate the ptr array */
-#define AIRQ_IV_DATA   8       /* Allocate the data array */
+#define AIRQ_IV_ALLOC          1       /* Use an allocation bit mask */
+#define AIRQ_IV_BITLOCK                2       /* Allocate the lock bit mask */
+#define AIRQ_IV_PTR            4       /* Allocate the ptr array */
+#define AIRQ_IV_DATA           8       /* Allocate the data array */
+#define AIRQ_IV_CACHELINE      16      /* Cacheline alignment for the vector */
 
 struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
 void airq_iv_release(struct airq_iv *iv);
index e045e79f061c592be9672a238caaeaef2620f270..4534afc635913aea93ed8f766fc6c650afc0ab1e 100644 (file)
@@ -27,6 +27,8 @@
 static DEFINE_SPINLOCK(airq_lists_lock);
 static struct hlist_head airq_lists[MAX_ISC+1];
 
+static struct kmem_cache *airq_iv_cache;
+
 /**
  * register_adapter_interrupt() - register adapter interrupt handler
  * @airq: pointer to adapter interrupt descriptor
@@ -129,10 +131,21 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
        if (!iv)
                goto out;
        iv->bits = bits;
+       iv->flags = flags;
        size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
-       iv->vector = kzalloc(size, GFP_KERNEL);
-       if (!iv->vector)
-               goto out_free;
+
+       if (flags & AIRQ_IV_CACHELINE) {
+               if ((cache_line_size() * BITS_PER_BYTE) < bits)
+                       goto out_free;
+
+               iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL);
+               if (!iv->vector)
+                       goto out_free;
+       } else {
+               iv->vector = kzalloc(size, GFP_KERNEL);
+               if (!iv->vector)
+                       goto out_free;
+       }
        if (flags & AIRQ_IV_ALLOC) {
                iv->avail = kmalloc(size, GFP_KERNEL);
                if (!iv->avail)
@@ -165,7 +178,10 @@ out_free:
        kfree(iv->ptr);
        kfree(iv->bitlock);
        kfree(iv->avail);
-       kfree(iv->vector);
+       if (iv->flags & AIRQ_IV_CACHELINE)
+               kmem_cache_free(airq_iv_cache, iv->vector);
+       else
+               kfree(iv->vector);
        kfree(iv);
 out:
        return NULL;
@@ -181,7 +197,10 @@ void airq_iv_release(struct airq_iv *iv)
        kfree(iv->data);
        kfree(iv->ptr);
        kfree(iv->bitlock);
-       kfree(iv->vector);
+       if (iv->flags & AIRQ_IV_CACHELINE)
+               kmem_cache_free(airq_iv_cache, iv->vector);
+       else
+               kfree(iv->vector);
        kfree(iv->avail);
        kfree(iv);
 }
@@ -275,3 +294,13 @@ unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
        return bit;
 }
 EXPORT_SYMBOL(airq_iv_scan);
+
+static int __init airq_init(void)
+{
+       airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(),
+                                         cache_line_size(), 0, NULL);
+       if (!airq_iv_cache)
+               return -ENOMEM;
+       return 0;
+}
+subsys_initcall(airq_init);