/* * Copyright (C) 1997 Claus-Justus Heine This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $ * $Revision: 1.3 $ * $Date: 1997/10/16 23:33:11 $ * * This file contains the allocator/dealloctor for ftape's dynamic dma * buffer. */ #include #include #include #include #include #include #include #include "../lowlevel/ftape-rw.h" #include "../lowlevel/ftape-read.h" #include "../lowlevel/ftape-tracing.h" /* DMA'able memory allocation stuff. */ static inline void *dmaalloc(size_t size) { unsigned long addr; if (size == 0) { return NULL; } addr = __get_dma_pages(GFP_KERNEL, get_order(size)); if (addr) { struct page *page; for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) mem_map_reserve(page); } return (void *)addr; } static inline void dmafree(void *addr, size_t size) { if (size > 0) { struct page *page; for (page = virt_to_page((unsigned long)addr); page < virt_to_page((unsigned long)addr+size); page++) mem_map_unreserve(page); free_pages((unsigned long) addr, get_order(size)); } } static int add_one_buffer(void) { TRACE_FUN(ft_t_flow); if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) { TRACE_EXIT -ENOMEM; } ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL); if (ft_buffer[ft_nr_buffers] == NULL) { TRACE_EXIT -ENOMEM; } memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct)); ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE); if (ft_buffer[ft_nr_buffers]->address == NULL) { kfree(ft_buffer[ft_nr_buffers]); ft_buffer[ft_nr_buffers] = NULL; TRACE_EXIT -ENOMEM; } ft_nr_buffers ++; TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p", ft_nr_buffers, ft_buffer[ft_nr_buffers-1], ft_buffer[ft_nr_buffers-1]->address); TRACE_EXIT 0; } static void del_one_buffer(void) { TRACE_FUN(ft_t_flow); if (ft_nr_buffers > 0) { TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p", ft_nr_buffers, ft_buffer[ft_nr_buffers-1], ft_buffer[ft_nr_buffers-1]->address); ft_nr_buffers --; dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE); kfree(ft_buffer[ft_nr_buffers]); ft_buffer[ft_nr_buffers] = NULL; } TRACE_EXIT; } int ftape_set_nr_buffers(int cnt) { int delta = cnt - ft_nr_buffers; TRACE_FUN(ft_t_flow); if (delta > 0) { while (delta--) { if (add_one_buffer() < 0) { TRACE_EXIT -ENOMEM; } } } else if (delta < 0) { while (delta++) { del_one_buffer(); } } ftape_zap_read_buffers(); TRACE_EXIT 0; }