Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/airq: use DMA memory for adapter interrupts

Protected virtualization guests have to use shared pages for airq
notifier bit vectors, because the hypervisor needs to write these bits.

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>
Reviewed-by: Michael Mueller <mimu@linux.ibm.com>
Tested-by: Michael Mueller <mimu@linux.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

authored by

Halil Pasic and committed by
Heiko Carstens
b50623e5 37db8985

+28 -14
+2
arch/s390/include/asm/airq.h
··· 11 11 #define _ASM_S390_AIRQ_H 12 12 13 13 #include <linux/bit_spinlock.h> 14 + #include <linux/dma-mapping.h> 14 15 15 16 struct airq_struct { 16 17 struct hlist_node list; /* Handler queueing. */ ··· 30 29 /* Adapter interrupt bit vector */ 31 30 struct airq_iv { 32 31 unsigned long *vector; /* Adapter interrupt bit vector */ 32 + dma_addr_t vector_dma; /* Adapter interrupt bit vector dma */ 33 33 unsigned long *avail; /* Allocation bit mask for the bit vector */ 34 34 unsigned long *bitlock; /* Lock bit mask for the bit vector */ 35 35 unsigned long *ptr; /* Pointer associated with each bit */
+23 -14
drivers/s390/cio/airq.c
··· 16 16 #include <linux/mutex.h> 17 17 #include <linux/rculist.h> 18 18 #include <linux/slab.h> 19 + #include <linux/dmapool.h> 19 20 20 21 #include <asm/airq.h> 21 22 #include <asm/isc.h> 23 + #include <asm/cio.h> 22 24 23 25 #include "cio.h" 24 26 #include "cio_debug.h" ··· 29 27 static DEFINE_SPINLOCK(airq_lists_lock); 30 28 static struct hlist_head airq_lists[MAX_ISC+1]; 31 29 32 - static struct kmem_cache *airq_iv_cache; 30 + static struct dma_pool *airq_iv_cache; 33 31 34 32 /** 35 33 * register_adapter_interrupt() - register adapter interrupt handler ··· 117 115 setup_irq(THIN_INTERRUPT, &airq_interrupt); 118 116 } 119 117 118 + static inline unsigned long iv_size(unsigned long bits) 119 + { 120 + return BITS_TO_LONGS(bits) * sizeof(unsigned long); 121 + } 122 + 120 123 /** 121 124 * airq_iv_create - create an interrupt vector 122 125 * @bits: number of bits in the interrupt vector ··· 139 132 goto out; 140 133 iv->bits = bits; 141 134 iv->flags = flags; 142 - size = BITS_TO_LONGS(bits) * sizeof(unsigned long); 135 + size = iv_size(bits); 143 136 144 137 if (flags & AIRQ_IV_CACHELINE) { 145 - if ((cache_line_size() * BITS_PER_BYTE) < bits) 138 + if ((cache_line_size() * BITS_PER_BYTE) < bits 139 + || !airq_iv_cache) 146 140 goto out_free; 147 141 148 - iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL); 142 + iv->vector = dma_pool_zalloc(airq_iv_cache, GFP_KERNEL, 143 + &iv->vector_dma); 149 144 if (!iv->vector) 150 145 goto out_free; 151 146 } else { 152 - iv->vector = kzalloc(size, GFP_KERNEL); 147 + iv->vector = cio_dma_zalloc(size); 153 148 if (!iv->vector) 154 149 goto out_free; 155 150 } ··· 187 178 kfree(iv->ptr); 188 179 kfree(iv->bitlock); 189 180 kfree(iv->avail); 190 - if (iv->flags & AIRQ_IV_CACHELINE) 191 - kmem_cache_free(airq_iv_cache, iv->vector); 181 + if (iv->flags & AIRQ_IV_CACHELINE && iv->vector) 182 + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); 192 183 else 193 - kfree(iv->vector); 184 + cio_dma_free(iv->vector, size); 194 185 kfree(iv); 195 186 out: 196 187 return NULL; ··· 207 198 kfree(iv->ptr); 208 199 kfree(iv->bitlock); 209 200 if (iv->flags & AIRQ_IV_CACHELINE) 210 - kmem_cache_free(airq_iv_cache, iv->vector); 201 + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); 211 202 else 212 - kfree(iv->vector); 203 + cio_dma_free(iv->vector, iv_size(iv->bits)); 213 204 kfree(iv->avail); 214 205 kfree(iv); 215 206 } ··· 304 295 } 305 296 EXPORT_SYMBOL(airq_iv_scan); 306 297 307 - static int __init airq_init(void) 298 + int __init airq_init(void) 308 299 { 309 - airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(), 310 - cache_line_size(), 0, NULL); 300 + airq_iv_cache = dma_pool_create("airq_iv_cache", cio_get_dma_css_dev(), 301 + cache_line_size(), 302 + cache_line_size(), PAGE_SIZE); 311 303 if (!airq_iv_cache) 312 304 return -ENOMEM; 313 305 return 0; 314 306 } 315 - subsys_initcall(airq_init);
+2
drivers/s390/cio/cio.h
··· 135 135 int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); 136 136 int cio_tm_intrg(struct subchannel *sch); 137 137 138 + extern int __init airq_init(void); 139 + 138 140 /* Use with care. */ 139 141 #ifdef CONFIG_CCW_CONSOLE 140 142 extern struct subchannel *cio_probe_console(void);
+1
drivers/s390/cio/css.c
··· 1184 1184 ret = cio_dma_pool_init(); 1185 1185 if (ret) 1186 1186 goto out_unregister_pmn; 1187 + airq_init(); 1187 1188 css_init_done = 1; 1188 1189 1189 1190 /* Enable default isc for I/O subchannels. */