Re: [PATCH v5 4/8] s390/airq: use DMA memory for adapter interrupts

Michael Mueller
2019-06-13T08:26:08Z

On 12.06.19 13:12, Halil Pasic wrote:
> Protected virtualization guests have to use shared pages for airq
> notifier bit vectors, because hypervisor needs to write these bits.

because the hypervisor

>
> Let us make sure we allocate DMA memory for the notifier bit vectors by
> replacing the kmem_cache with a dma_cache and kalloc() with
> cio_dma_zalloc().
>
> Signed-off-by: Halil Pasic <pasic@linux.ibm.com>
> Reviewed-by: Sebastian Ott <sebott@linux.ibm.com>
> ---
> arch/s390/include/asm/airq.h | 2 ++
> drivers/s390/cio/airq.c | 37 ++++++++++++++++++++++--------------
> drivers/s390/cio/cio.h | 2 ++
> drivers/s390/cio/css.c | 1 +
> 4 files changed, 28 insertions(+), 14 deletions(-)
>
> diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h
> index c10d2ee2dfda..01936fdfaddb 100644
> --- a/arch/s390/include/asm/airq.h
> +++ b/arch/s390/include/asm/airq.h
> @@ -11,6 +11,7 @@
> #define _ASM_S390_AIRQ_H
>
> #include <linux/bit_spinlock.h>
> +#include <linux/dma-mapping.h>
>
> struct airq_struct {
> struct hlist_node list; /* Handler queueing. */
> @@ -29,6 +30,7 @@ void unregister_adapter_interrupt(struct airq_struct *airq);
> /* Adapter interrupt bit vector */
> struct airq_iv {
> unsigned long *vector; /* Adapter interrupt bit vector */
> + dma_addr_t vector_dma; /* Adapter interrupt bit vector dma */
> unsigned long *avail; /* Allocation bit mask for the bit vector */
> unsigned long *bitlock; /* Lock bit mask for the bit vector */
> unsigned long *ptr; /* Pointer associated with each bit */
> diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
> index 4534afc63591..427b2e24a8ce 100644
> --- a/drivers/s390/cio/airq.c
> +++ b/drivers/s390/cio/airq.c
> @@ -16,9 +16,11 @@
> #include <linux/mutex.h>
> #include <linux/rculist.h>
> #include <linux/slab.h>
> +#include <linux/dmapool.h>
>
> #include <asm/airq.h>
> #include <asm/isc.h>
> +#include <asm/cio.h>
>
> #include "cio.h"
> #include "cio_debug.h"
> @@ -27,7 +29,7 @@
> static DEFINE_SPINLOCK(airq_lists_lock);
> static struct hlist_head airq_lists[MAX_ISC+1];
>
> -static struct kmem_cache *airq_iv_cache;
> +static struct dma_pool *airq_iv_cache;
>
> /**
> * register_adapter_interrupt() - register adapter interrupt handler
> @@ -115,6 +117,11 @@ void __init init_airq_interrupts(void)
> setup_irq(THIN_INTERRUPT, &airq_interrupt);
> }
>
> +static inline unsigned long iv_size(unsigned long bits)
> +{
> + return BITS_TO_LONGS(bits) * sizeof(unsigned long);
> +}
> +
> /**
> * airq_iv_create - create an interrupt vector
> * @bits: number of bits in the interrupt vector
> @@ -132,17 +139,19 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
> goto out;
> iv->bits = bits;
> iv->flags = flags;
> - size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
> + size = iv_size(bits);
>
> if (flags & AIRQ_IV_CACHELINE) {
> - if ((cache_line_size() * BITS_PER_BYTE) < bits)
> + if ((cache_line_size() * BITS_PER_BYTE) < bits
> + || !airq_iv_cache)
> goto out_free;
>
> - iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL);
> + iv->vector = dma_pool_zalloc(airq_iv_cache, GFP_KERNEL,
> + &iv->vector_dma);
> if (!iv->vector)
> goto out_free;
> } else {
> - iv->vector = kzalloc(size, GFP_KERNEL);
> + iv->vector = cio_dma_zalloc(size);
> if (!iv->vector)
> goto out_free;
> }
> @@ -178,10 +187,10 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
> kfree(iv->ptr);
> kfree(iv->bitlock);
> kfree(iv->avail);
> - if (iv->flags & AIRQ_IV_CACHELINE)
> - kmem_cache_free(airq_iv_cache, iv->vector);
> + if (iv->flags & AIRQ_IV_CACHELINE && iv->vector)
> + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
> else
> - kfree(iv->vector);
> + cio_dma_free(iv->vector, size);
> kfree(iv);
> out:
> return NULL;
> @@ -198,9 +207,9 @@ void airq_iv_release(struct airq_iv *iv)
> kfree(iv->ptr);
> kfree(iv->bitlock);
> if (iv->flags & AIRQ_IV_CACHELINE)
> - kmem_cache_free(airq_iv_cache, iv->vector);
> + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
> else
> - kfree(iv->vector);
> + cio_dma_free(iv->vector, iv_size(iv->bits));
> kfree(iv->avail);
> kfree(iv);
> }
> @@ -295,12 +304,12 @@ unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
> }
> EXPORT_SYMBOL(airq_iv_scan);
>
> -static int __init airq_init(void)
> +int __init airq_init(void)
> {
> - airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(),
> - cache_line_size(), 0, NULL);
> + airq_iv_cache = dma_pool_create("airq_iv_cache", cio_get_dma_css_dev(),
> + cache_line_size(),
> + cache_line_size(), PAGE_SIZE);
> if (!airq_iv_cache)
> return -ENOMEM;
> return 0;
> }
> -subsys_initcall(airq_init);
> diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
> index 06a91743335a..4d6c7d16416e 100644
> --- a/drivers/s390/cio/cio.h
> +++ b/drivers/s390/cio/cio.h
> @@ -135,6 +135,8 @@ extern int cio_commit_config(struct subchannel *sch);
> int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
> int cio_tm_intrg(struct subchannel *sch);
>
> +extern int __init airq_init(void);
> +
> /* Use with care. */
> #ifdef CONFIG_CCW_CONSOLE
> extern struct subchannel *cio_probe_console(void);
> diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
> index e0f19f1e82a0..1b867c941b86 100644
> --- a/drivers/s390/cio/css.c
> +++ b/drivers/s390/cio/css.c
> @@ -1184,6 +1184,7 @@ static int __init css_bus_init(void)
> ret = cio_dma_pool_init();
> if (ret)
> goto out_unregister_pmn;
> + airq_init();
> css_init_done = 1;
>
> /* Enable default isc for I/O subchannels. */
>

Reviewed-by: Michael Mueller <mimu@linux.ibm.com>

Michael