Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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