Blob Blame History Raw
From: Sebastian Ott <sebott@linux.ibm.com>
Date: Wed, 27 Feb 2019 13:56:08 +0100
Subject: s390/airq: provide cacheline aligned ivs
Git-commit: 414cbd1e3d14ec0e60666a0fb9d8ae2d77eb7c63
Patch-mainline: v5.2-rc1
References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388

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>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/s390/include/asm/airq.h |   10 ++++++----
 drivers/s390/cio/airq.c      |   39 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 40 insertions(+), 9 deletions(-)

--- a/arch/s390/include/asm/airq.h
+++ b/arch/s390/include/asm/airq.h
@@ -34,13 +34,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);
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -26,6 +26,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
@@ -128,10 +130,21 @@ struct airq_iv *airq_iv_create(unsigned
 	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)
@@ -164,7 +177,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;
@@ -180,7 +196,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);
 }
@@ -274,3 +293,13 @@ unsigned long airq_iv_scan(struct airq_i
 	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);