summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.ibm.com>2019-02-27 13:56:08 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-04-29 10:47:01 +0200
commit414cbd1e3d14ec0e60666a0fb9d8ae2d77eb7c63 (patch)
tree565130f83fe06b97a58484a0025c7348bba43e1a /drivers/s390
parentb1f548645cb587c14f5e751b9163939d0723885f (diff)
downloadlinux-414cbd1e3d14ec0e60666a0fb9d8ae2d77eb7c63.tar.bz2
s390/airq: provide cacheline aligned ivs
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>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/airq.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index e045e79f061c..4534afc63591 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -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);