ftape-buffer.c 3.2 KB

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