^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Martin Schwidefsky <schwidefsky@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Bugreports.to..: <Linux390@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright IBM Corp. 2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * History of changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 07/24/00 new file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 05/04/02 code restructuring.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #ifndef _S390_IDALS_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define _S390_IDALS_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/cio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Test if an address/length pair needs an idal list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) idal_is_needed(void *vaddr, unsigned int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return ((__pa(vaddr) + length - 1) >> 31) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Return the number of idal words needed for an address/length pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static inline unsigned int idal_nr_words(void *vaddr, unsigned int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Create the list of idal words for an address/length pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static inline unsigned long *idal_create_words(unsigned long *idaws,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) void *vaddr, unsigned int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long paddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned int cidaw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) paddr = __pa(vaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *idaws++ = paddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) paddr &= -IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) while (--cidaw > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) paddr += IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *idaws++ = paddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return idaws;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Sets the address of the data in CCW.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * If necessary it allocates an IDAL and sets the appropriate flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) set_normalized_cda(struct ccw1 * ccw, void *vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) unsigned int nridaws;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long *idal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (ccw->flags & CCW_FLAG_IDA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) nridaws = idal_nr_words(vaddr, ccw->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (nridaws > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) idal = kmalloc(nridaws * sizeof(unsigned long),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) GFP_ATOMIC | GFP_DMA );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (idal == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) idal_create_words(idal, vaddr, ccw->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ccw->flags |= CCW_FLAG_IDA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) vaddr = idal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ccw->cda = (__u32)(unsigned long) vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * Releases any allocated IDAL related to the CCW.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) clear_normalized_cda(struct ccw1 * ccw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (ccw->flags & CCW_FLAG_IDA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) kfree((void *)(unsigned long) ccw->cda);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ccw->flags &= ~CCW_FLAG_IDA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ccw->cda = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * Idal buffer extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct idal_buffer {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) size_t page_order;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) void *data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * Allocate an idal buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static inline struct idal_buffer *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) idal_buffer_alloc(size_t size, int page_order)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct idal_buffer *ib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int nr_chunks, nr_ptrs, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ib = kmalloc(struct_size(ib, data, nr_ptrs), GFP_DMA | GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (ib == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ib->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ib->page_order = page_order;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) for (i = 0; i < nr_ptrs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if ((i & (nr_chunks - 1)) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ib->data[i] = (void *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) __get_free_pages(GFP_KERNEL, page_order);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (ib->data[i] != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) // Not enough memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) while (i >= nr_chunks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) i -= nr_chunks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) free_pages((unsigned long) ib->data[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ib->page_order);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) kfree(ib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return ib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * Free an idal buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) idal_buffer_free(struct idal_buffer *ib)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) int nr_chunks, nr_ptrs, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) for (i = 0; i < nr_ptrs; i += nr_chunks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) free_pages((unsigned long) ib->data[i], ib->page_order);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) kfree(ib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * Test if a idal list is really needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) __idal_buffer_is_needed(struct idal_buffer *ib)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return ib->size > (4096ul << ib->page_order) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) idal_is_needed(ib->data[0], ib->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * Set channel data address to idal buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) idal_buffer_set_cda(struct idal_buffer *ib, struct ccw1 *ccw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (__idal_buffer_is_needed(ib)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) // setup idals;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ccw->cda = (u32)(addr_t) ib->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ccw->flags |= CCW_FLAG_IDA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) // we do not need idals - use direct addressing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ccw->cda = (u32)(addr_t) ib->data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ccw->count = ib->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * Copy count bytes from an idal buffer to user memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static inline size_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) idal_buffer_to_user(struct idal_buffer *ib, void __user *to, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) size_t left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) BUG_ON(count > ib->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) for (i = 0; count > IDA_BLOCK_SIZE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (left)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return left + count - IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) to = (void __user *) to + IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) count -= IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return copy_to_user(to, ib->data[i], count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * Copy count bytes from user memory to an idal buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static inline size_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) idal_buffer_from_user(struct idal_buffer *ib, const void __user *from, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) size_t left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) BUG_ON(count > ib->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) for (i = 0; count > IDA_BLOCK_SIZE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (left)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return left + count - IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) from = (void __user *) from + IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) count -= IDA_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return copy_from_user(ib->data[i], from, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) #endif