allocator.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * allocator.c -- allocate after high_memory, if available
  3.  *
  4.  * NOTE: this is different from my previous allocator, the one that
  5.  *       assembles pages, which revealed itself both slow and unreliable.
  6.  *
  7.  * Copyright (C) 1998   rubini@linux.it (Alessandro Rubini)
  8.  *
  9.  *   This program is free software; you can redistribute it and/or modify
  10.  *   it under the terms of the GNU General Public License as published by
  11.  *   the Free Software Foundation; either version 2 of the License, or
  12.  *   (at your option) any later version.
  13.  *
  14.  *   This program is distributed in the hope that it will be useful,
  15.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *   GNU General Public License for more details.
  18.  *
  19.  *   You should have received a copy of the GNU General Public License
  20.  *   along with this program; if not, write to the Free Software
  21.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  */
  24. #ifndef __KERNEL__
  25. #  define __KERNEL__
  26. #endif
  27. #ifndef MODULE
  28. #  define MODULE
  29. #endif
  30. #include <linux/version.h>
  31. #include "sysdep-2.1.h"
  32. #if LINUX_VERSION_CODE < VERSION_CODE(2,0,0)
  33. #  error "This module needs Linux 2.0 or newer"
  34. #else
  35. #include <linux/sched.h>
  36. #include <linux/kernel.h>
  37. #include <linux/fs.h>
  38. #include <linux/proc_fs.h>
  39. #include <linux/errno.h>
  40. #include <linux/types.h>
  41. #include <asm/page.h>
  42. #define ALL_MSG "allocator: "
  43. #undef PDEBUG             /* undef it, just in case */
  44. #ifdef ALL_DEBUG
  45. #  define __static
  46. #  ifdef __KERNEL__
  47.      /* This one if debugging is on, and kernel space */
  48. #    define PDEBUG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)
  49. #  else
  50.      /* This one for user space */
  51. #    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
  52. #  endif
  53. #else
  54. #  define PDEBUG(fmt, args...) /* not debugging: nothing */
  55. #  define __static static
  56. #endif
  57. #undef PDEBUGG
  58. #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
  59. /* This is meant to be a parameter: 0 = probe, pos. = megs, neg. = disable */
  60. int allocator_himem = 0;
  61. static unsigned long allocator_buffer      = 0;  /* physical address */
  62. static unsigned long allocator_buffer_size = 0;  /* kilobytes */
  63. /*
  64.  * The allocator keeps a list of DMA areas, so multiple devices
  65.  * can coexist. The list is kept sorted by address
  66.  */
  67. struct allocator_struct {
  68.     unsigned long address;
  69.     unsigned long size;
  70.     struct allocator_struct *next;
  71. };
  72. struct allocator_struct *allocator_list = NULL;
  73. #if 0
  74. static int dump_list(void)
  75. {
  76.     struct allocator_struct *ptr;
  77.     PDEBUG("Current list:n");
  78.     for (ptr = allocator_list; ptr; ptr = ptr->next) {
  79.         PDEBUG("0x%08lx (size %likB)n",ptr->address,ptr->size>>10);
  80.     }
  81.     return 0;
  82. }
  83. #endif
  84. /* ========================================================================
  85.  * This function is the actual allocator.
  86.  *
  87.  * If space is available in high memory (as detected at load time), that
  88.  * one is returned. The return value is a physical address (i.e., it can
  89.  * be used straight ahead for DMA, but needs remapping for program use).
  90.  */
  91. unsigned long allocator_allocate_dma (unsigned long kilobytes, int prio)
  92. {
  93.     struct allocator_struct *ptr = allocator_list, *newptr;
  94.     /* check if high memory is available */
  95.     if (!allocator_buffer)
  96.         return 0;
  97.     PDEBUG("request for %ikn",(int)kilobytes);
  98.     while (ptr && ptr->next) {
  99.         if (ptr->next->address - (ptr->address+ptr->size) >= (kilobytes<<10))
  100.             break; /* enough space */
  101.         ptr = ptr->next;
  102.     }
  103.     if (!ptr->next) {
  104.         /* dump_list(); */
  105.         PDEBUG("alloc failedn");
  106.         return 0; /* end of list */
  107.     }
  108.     newptr = kmalloc(sizeof(struct allocator_struct),prio);
  109.     if (!newptr)
  110.         return 0;
  111.     /* ok, now stick it after ptr */
  112.     newptr->address = ptr->address + ptr->size;
  113.     newptr->size = kilobytes<<10;
  114.     newptr->next = ptr->next;
  115.     ptr->next = newptr;
  116.     /* dump_list(); */
  117.     PDEBUG("returning 0x%08lxn",newptr->address);
  118.     return newptr->address;
  119. }
  120. int allocator_free_dma (unsigned long address)
  121. {
  122.     struct allocator_struct *ptr = allocator_list, *prev;
  123.     while (ptr && ptr->next) {
  124.         if (ptr->next->address == address)
  125.             break;
  126. ptr = ptr->next;
  127. }
  128.     /* the one being freed is ptr->next */
  129.     prev = ptr; ptr = ptr->next;
  130.     if (!ptr) {
  131.         printk(KERN_ERR ALL_MSG "free_dma(0x%08lx) but add. not allocatedn",
  132.                ptr->address);
  133.         return -EINVAL;
  134.     }
  135.     PDEBUGG("freeing: %08lx (%li) next %08lxn",ptr->address,ptr->size,
  136.    ptr->next->address);
  137.     prev->next = ptr->next;
  138.     kfree(ptr);
  139.     /* dump_list(); */
  140.     return 0;
  141. }
  142. /* ========================================================================
  143.  * Init and cleanup
  144.  *
  145.  * On cleanup everything is released. If the list is not empty, that a
  146.  * problem of our clients
  147.  */
  148. int allocator_init(void)
  149. {
  150.     /* check how much free memory is there */
  151.     volatile void *remapped;
  152.     unsigned long trial_size = allocator_himem<<20;
  153.     unsigned long last_trial = 0;
  154.     int step = !(allocator_himem); /* no step if size known */
  155.     unsigned long i=0;
  156.     struct allocator_struct *head, *tail;
  157.     char test_string[]="0123456789abcde"; /* 16 bytes */
  158.     PDEBUGG("himem = %in",allocator_himem);
  159.     if (allocator_himem < 0) /* don't even try */
  160.         return -EINVAL;
  161.     if (!trial_size) trial_size = 1<<20; /* not specified: try one meg */
  162.     while (1) {
  163.         remapped = ioremap((int)high_memory,trial_size);
  164.         if (!remapped)
  165.             break;
  166.         PDEBUGG("Trying %li megsn",trial_size>>20);
  167.         for (i=last_trial; i<trial_size; i+=16) {
  168.             strcpy((char *)(remapped)+i, test_string);
  169.             if (strcmp((char *)remapped+i, test_string))
  170.                 break;
  171.         }
  172.         iounmap((void *)remapped);
  173.         schedule();
  174.         last_trial = trial_size;
  175.         if (i==trial_size)
  176.             trial_size <<= step; /* double, if all went well */
  177.         else
  178.             break;
  179.         if (!step) break;
  180.     }
  181.     PDEBUG("%li megs (%li k, %li b)n",i>>20,i>>10,i);
  182.     allocator_buffer_size = i>>10; /* kilobytes */
  183.     allocator_buffer = (int)high_memory;
  184.     if (!allocator_buffer_size) {
  185.         printk(KERN_WARNING ALL_MSG "no free high memory to usen");
  186.         return -ENOMEM;
  187.     }
  188.     /*
  189.      * to simplify things, always have two cells in the list:
  190.      * the first and the last. This avoids some conditionals and
  191.      * extra code when allocating and deallocating: we only play
  192.      * in the middle of the list
  193.      */
  194.     head = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
  195.     if (!head)
  196.         return -ENOMEM;
  197.     tail = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
  198.     if (!tail) {
  199.         kfree(head);
  200.         return -ENOMEM;
  201.     }
  202.     head->size = tail->size = 0;
  203.     head->address = allocator_buffer;
  204.     tail->address = allocator_buffer + (allocator_buffer_size<<10);
  205.     head->next = tail;
  206.     tail->next = NULL;
  207.     allocator_list = head;
  208.     return 0; /* ok, ready */
  209. }
  210. void allocator_cleanup(void)
  211. {
  212.     struct allocator_struct *ptr, *next;
  213.     for (ptr = allocator_list; ptr; ptr = next) {
  214.         next = ptr->next;
  215.         PDEBUG("freeing list: 0x%08lxn",ptr->address);
  216.         kfree(ptr);
  217.     }
  218.     allocator_buffer      = 0;
  219.     allocator_buffer_size = 0;
  220.     allocator_list = NULL;
  221. }
  222. #endif /* 1.99.4 or newer */