1 /*
2  *      Copyright (C) 1997 Claus-Justus Heine
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; see the file COPYING.  If not, write to
16  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18  *
19  * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $
20  * $Revision: 1.3 $
21  * $Date: 1997/10/16 23:33:11 $
22  *
23  *  This file contains the allocator/dealloctor for ftape's dynamic dma
24  *  buffer.
25  */
26 
27 #include <asm/segment.h>
28 #include <linux/slab.h>
29 #include <linux/mm.h>
30 #include <linux/mman.h>
31 #include <linux/wrapper.h>
32 #include <asm/dma.h>
33 
34 #include <linux/ftape.h>
35 #include "../lowlevel/ftape-rw.h"
36 #include "../lowlevel/ftape-read.h"
37 #include "../lowlevel/ftape-tracing.h"
38 
39 /*  DMA'able memory allocation stuff.
40  */
41 
dmaalloc(size_t size)42 static inline void *dmaalloc(size_t size)
43 {
44 	unsigned long addr;
45 
46 	if (size == 0) {
47 		return NULL;
48 	}
49 	addr = __get_dma_pages(GFP_KERNEL, get_order(size));
50 	if (addr) {
51 		struct page *page;
52 
53 		for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++)
54 			mem_map_reserve(page);
55 	}
56 	return (void *)addr;
57 }
58 
dmafree(void * addr,size_t size)59 static inline void dmafree(void *addr, size_t size)
60 {
61 	if (size > 0) {
62 		struct page *page;
63 
64 		for (page = virt_to_page((unsigned long)addr);
65 		     page < virt_to_page((unsigned long)addr+size); page++)
66 			mem_map_unreserve(page);
67 		free_pages((unsigned long) addr, get_order(size));
68 	}
69 }
70 
add_one_buffer(void)71 static int add_one_buffer(void)
72 {
73 	TRACE_FUN(ft_t_flow);
74 
75 	if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) {
76 		TRACE_EXIT -ENOMEM;
77 	}
78 	ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL);
79 	if (ft_buffer[ft_nr_buffers] == NULL) {
80 		TRACE_EXIT -ENOMEM;
81 	}
82 	memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct));
83 	ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE);
84 	if (ft_buffer[ft_nr_buffers]->address == NULL) {
85 		kfree(ft_buffer[ft_nr_buffers]);
86 		ft_buffer[ft_nr_buffers] = NULL;
87 		TRACE_EXIT -ENOMEM;
88 	}
89 	ft_nr_buffers ++;
90 	TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p",
91 	      ft_nr_buffers,
92 	      ft_buffer[ft_nr_buffers-1],
93 	      ft_buffer[ft_nr_buffers-1]->address);
94 	TRACE_EXIT 0;
95 }
96 
del_one_buffer(void)97 static void del_one_buffer(void)
98 {
99 	TRACE_FUN(ft_t_flow);
100 	if (ft_nr_buffers > 0) {
101 		TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p",
102 		      ft_nr_buffers,
103 		      ft_buffer[ft_nr_buffers-1],
104 		      ft_buffer[ft_nr_buffers-1]->address);
105 		ft_nr_buffers --;
106 		dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE);
107 		kfree(ft_buffer[ft_nr_buffers]);
108 		ft_buffer[ft_nr_buffers] = NULL;
109 	}
110 	TRACE_EXIT;
111 }
112 
ftape_set_nr_buffers(int cnt)113 int ftape_set_nr_buffers(int cnt)
114 {
115 	int delta = cnt - ft_nr_buffers;
116 	TRACE_FUN(ft_t_flow);
117 
118 	if (delta > 0) {
119 		while (delta--) {
120 			if (add_one_buffer() < 0) {
121 				TRACE_EXIT -ENOMEM;
122 			}
123 		}
124 	} else if (delta < 0) {
125 		while (delta++) {
126 			del_one_buffer();
127 		}
128 	}
129 	ftape_zap_read_buffers();
130 	TRACE_EXIT 0;
131 }
132