Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / char / ftape / lowlevel / ftape-buffer.c
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 <linux/slab.h>
28 #include <linux/mm.h>
29 #include <linux/mman.h>
30 #include <asm/dma.h>
31
32 #include <linux/ftape.h>
33 #include "../lowlevel/ftape-rw.h"
34 #include "../lowlevel/ftape-read.h"
35 #include "../lowlevel/ftape-tracing.h"
36
37 /*  DMA'able memory allocation stuff.
38  */
39
40 static inline void *dmaalloc(size_t size)
41 {
42         unsigned long addr;
43
44         if (size == 0) {
45                 return NULL;
46         }
47         addr = __get_dma_pages(GFP_KERNEL, get_order(size));
48         if (addr) {
49                 struct page *page;
50
51                 for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++)
52                         SetPageReserved(page);
53         }
54         return (void *)addr;
55 }
56
57 static inline void dmafree(void *addr, size_t size)
58 {
59         if (size > 0) {
60                 struct page *page;
61
62                 for (page = virt_to_page((unsigned long)addr);
63                      page < virt_to_page((unsigned long)addr+size); page++)
64                         ClearPageReserved(page);
65                 free_pages((unsigned long) addr, get_order(size));
66         }
67 }
68
69 static int add_one_buffer(void)
70 {
71         TRACE_FUN(ft_t_flow);
72         
73         if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) {
74                 TRACE_EXIT -ENOMEM;
75         }
76         ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL);
77         if (ft_buffer[ft_nr_buffers] == NULL) {
78                 TRACE_EXIT -ENOMEM;
79         }
80         memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct));
81         ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE);
82         if (ft_buffer[ft_nr_buffers]->address == NULL) {
83                 kfree(ft_buffer[ft_nr_buffers]);
84                 ft_buffer[ft_nr_buffers] = NULL;
85                 TRACE_EXIT -ENOMEM;
86         }
87         ft_nr_buffers ++;
88         TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p",
89               ft_nr_buffers,
90               ft_buffer[ft_nr_buffers-1],
91               ft_buffer[ft_nr_buffers-1]->address);
92         TRACE_EXIT 0;
93 }
94
95 static void del_one_buffer(void)
96 {
97         TRACE_FUN(ft_t_flow);
98         if (ft_nr_buffers > 0) {
99                 TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p",
100                       ft_nr_buffers,
101                       ft_buffer[ft_nr_buffers-1],
102                       ft_buffer[ft_nr_buffers-1]->address);
103                 ft_nr_buffers --;
104                 dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE);
105                 kfree(ft_buffer[ft_nr_buffers]);
106                 ft_buffer[ft_nr_buffers] = NULL;
107         }
108         TRACE_EXIT;
109 }
110
111 int ftape_set_nr_buffers(int cnt)
112 {
113         int delta = cnt - ft_nr_buffers;
114         TRACE_FUN(ft_t_flow);
115
116         if (delta > 0) {
117                 while (delta--) {
118                         if (add_one_buffer() < 0) {
119                                 TRACE_EXIT -ENOMEM;
120                         }
121                 }
122         } else if (delta < 0) {
123                 while (delta++) {
124                         del_one_buffer();
125                 }
126         }
127         ftape_zap_read_buffers();
128         TRACE_EXIT 0;
129 }