Date Programmer Description of changes made
-------------------------------------------------------------------
02-Aug-2002 NJC allocator now steps in 1MB increments, rather
- than doubling its size each time.
+ than doubling its size each time.
Also, allocator_init(u_int *) now returns
(in the first arg) the size of the free
space. This is no longer consistent with
# define DUMP_LIST() dump_list()
# ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
-# define PDEBUG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)
+# define PDEBUG(fmt, args...) printk(KERN_DEBUG ALL_MSG fmt, ## args)
# else
/* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
int allocator_step = 1; /* This is the step size in MB */
int allocator_probe = 1; /* This is a flag -- 1=probe, 0=don't probe */
-static unsigned long allocator_buffer = 0; /* physical address */
-static unsigned long allocator_buffer_size = 0; /* kilobytes */
+static unsigned long allocator_buffer; /* physical address */
+static unsigned long allocator_buffer_size; /* kilobytes */
/*
* The allocator keeps a list of DMA areas, so multiple devices
*/
struct allocator_struct {
- unsigned long address;
- unsigned long size;
- struct allocator_struct *next;
+ unsigned long address;
+ unsigned long size;
+ struct allocator_struct *next;
};
-struct allocator_struct *allocator_list = NULL;
+struct allocator_struct *allocator_list;
#ifdef ALL_DEBUG
static int dump_list(void)
{
- struct allocator_struct *ptr;
+ struct allocator_struct *ptr;
- PDEBUG("Current list:\n");
- for (ptr = allocator_list; ptr; ptr = ptr->next) {
- PDEBUG("0x%08lx (size %likB)\n",ptr->address,ptr->size>>10);
- }
- return 0;
+ PDEBUG("Current list:\n");
+ for (ptr = allocator_list; ptr; ptr = ptr->next)
+ PDEBUG("0x%08lx (size %likB)\n", ptr->address, ptr->size>>10);
+ return 0;
}
#endif
* be used straight ahead for DMA, but needs remapping for program use).
*/
-unsigned long allocator_allocate_dma (unsigned long kilobytes, int prio)
+unsigned long allocator_allocate_dma(unsigned long kilobytes, int prio)
{
- struct allocator_struct *ptr = allocator_list, *newptr;
- unsigned long bytes = kilobytes << 10;
-
- /* check if high memory is available */
- if (!allocator_buffer)
- return 0;
-
- /* Round it to a multiple of the pagesize */
- bytes = PAGE_ALIGN(bytes);
- PDEBUG("request for %li bytes\n", bytes);
-
- while (ptr && ptr->next) {
- if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
- break; /* enough space */
- ptr = ptr->next;
- }
- if (!ptr->next) {
- DUMP_LIST();
- PDEBUG("alloc failed\n");
- return 0; /* end of list */
- }
- newptr = kmalloc(sizeof(struct allocator_struct),prio);
- if (!newptr)
- return 0;
-
- /* ok, now stick it after ptr */
- newptr->address = ptr->address + ptr->size;
- newptr->size = bytes;
- newptr->next = ptr->next;
- ptr->next = newptr;
-
- DUMP_LIST();
- PDEBUG("returning 0x%08lx\n",newptr->address);
- return newptr->address;
+ struct allocator_struct *ptr = allocator_list, *newptr;
+ unsigned long bytes = kilobytes << 10;
+
+ /* check if high memory is available */
+ if (!allocator_buffer)
+ return 0;
+
+ /* Round it to a multiple of the pagesize */
+ bytes = PAGE_ALIGN(bytes);
+ PDEBUG("request for %li bytes\n", bytes);
+
+ while (ptr && ptr->next) {
+ if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
+ break; /* enough space */
+ ptr = ptr->next;
+ }
+ if (!ptr->next) {
+ DUMP_LIST();
+ PDEBUG("alloc failed\n");
+ return 0; /* end of list */
+ }
+ newptr = kmalloc(sizeof(struct allocator_struct), prio);
+ if (!newptr)
+ return 0;
+
+ /* ok, now stick it after ptr */
+ newptr->address = ptr->address + ptr->size;
+ newptr->size = bytes;
+ newptr->next = ptr->next;
+ ptr->next = newptr;
+
+ DUMP_LIST();
+ PDEBUG("returning 0x%08lx\n", newptr->address);
+ return newptr->address;
}
-int allocator_free_dma (unsigned long address)
+int allocator_free_dma(unsigned long address)
{
- struct allocator_struct *ptr = allocator_list, *prev;
+ struct allocator_struct *ptr = allocator_list, *prev;
- while (ptr && ptr->next) {
- if (ptr->next->address == address)
- break;
- ptr = ptr->next;
+ while (ptr && ptr->next) {
+ if (ptr->next->address == address)
+ break;
+ ptr = ptr->next;
+ }
+ /* the one being freed is ptr->next */
+ prev = ptr; ptr = ptr->next;
+
+ if (!ptr) {
+ printk(KERN_ERR ALL_MSG
+ "free_dma(0x%08lx) but add. not allocated\n",
+ ptr->address);
+ return -EINVAL;
}
- /* the one being freed is ptr->next */
- prev = ptr; ptr = ptr->next;
-
- if (!ptr) {
- printk(KERN_ERR ALL_MSG "free_dma(0x%08lx) but add. not allocated\n",
- ptr->address);
- return -EINVAL;
- }
- PDEBUGG("freeing: %08lx (%li) next %08lx\n",ptr->address,ptr->size,
- ptr->next->address);
- prev->next = ptr->next;
- kfree(ptr);
-
- /* dump_list(); */
- return 0;
+ PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,
+ ptr->next->address);
+ prev->next = ptr->next;
+ kfree(ptr);
+
+ /* dump_list(); */
+ return 0;
}
/* ========================================================================
*/
int allocator_init(u_long *allocator_max)
{
- /* check how much free memory is there */
-
- volatile void *remapped;
- unsigned long max;
- unsigned long trial_size = allocator_himem<<20;
- unsigned long last_trial = 0;
- unsigned long step = allocator_step<<20;
- unsigned long i=0;
- struct allocator_struct *head, *tail;
- char test_string[]="0123456789abcde"; /* 16 bytes */
-
- PDEBUGG("himem = %i\n",allocator_himem);
- if (allocator_himem < 0) /* don't even try */
- return -EINVAL;
-
- if (!trial_size) trial_size = 1<<20; /* not specified: try one meg */
-
- while (1) {
- remapped = ioremap(__pa(high_memory), trial_size);
- if (!remapped)
- {
- PDEBUGG("%li megs failed!\n",trial_size>>20);
- break;
- }
- PDEBUGG("Trying %li megs (at %p, %p)\n",trial_size>>20,
- (void *)__pa(high_memory), remapped);
- for (i=last_trial; i<trial_size; i+=16) {
- strcpy((char *)(remapped)+i, test_string);
- if (strcmp((char *)(remapped)+i, test_string))
- break;
- }
- iounmap((void *)remapped);
- schedule();
- last_trial = trial_size;
- if (i==trial_size)
- trial_size += step; /* increment, if all went well */
- else
- {
- PDEBUGG("%li megs copy test failed!\n",trial_size>>20);
- break;
- }
- if (!allocator_probe) break;
- }
- PDEBUG("%li megs (%li k, %li b)\n",i>>20,i>>10,i);
- allocator_buffer_size = i>>10; /* kilobytes */
- allocator_buffer = __pa(high_memory);
- if (!allocator_buffer_size) {
- printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
- return -ENOMEM;
- }
-
- /*
- * to simplify things, always have two cells in the list:
- * the first and the last. This avoids some conditionals and
- * extra code when allocating and deallocating: we only play
- * in the middle of the list
- */
- head = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
- if (!head)
- return -ENOMEM;
- tail = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
- if (!tail) {
- kfree(head);
- return -ENOMEM;
- }
-
- max = allocator_buffer_size<<10;
-
- head->size = tail->size = 0;
- head->address = allocator_buffer;
- tail->address = allocator_buffer + max;
- head->next = tail;
- tail->next = NULL;
- allocator_list = head;
-
- *allocator_max = allocator_buffer_size; /* Back to the user code, in KB */
-
- return 0; /* ok, ready */
+ /* check how much free memory is there */
+ void *remapped;
+ unsigned long max;
+ unsigned long trial_size = allocator_himem<<20;
+ unsigned long last_trial = 0;
+ unsigned long step = allocator_step<<20;
+ unsigned long i = 0;
+ struct allocator_struct *head, *tail;
+ char test_string[] = "0123456789abcde"; /* 16 bytes */
+
+ PDEBUGG("himem = %i\n", allocator_himem);
+ if (allocator_himem < 0) /* don't even try */
+ return -EINVAL;
+
+ if (!trial_size)
+ trial_size = 1<<20; /* not specified: try one meg */
+
+ while (1) {
+ remapped = ioremap(__pa(high_memory), trial_size);
+ if (!remapped) {
+ PDEBUGG("%li megs failed!\n", trial_size>>20);
+ break;
+ }
+ PDEBUGG("Trying %li megs (at %p, %p)\n", trial_size>>20,
+ (void *)__pa(high_memory), remapped);
+ for (i = last_trial; i < trial_size; i += 16) {
+ strcpy((char *)(remapped)+i, test_string);
+ if (strcmp((char *)(remapped)+i, test_string))
+ break;
+ }
+ iounmap((void *)remapped);
+ schedule();
+ last_trial = trial_size;
+ if (i == trial_size)
+ trial_size += step; /* increment, if all went well */
+ else {
+ PDEBUGG("%li megs copy test failed!\n", trial_size>>20);
+ break;
+ }
+ if (!allocator_probe)
+ break;
+ }
+ PDEBUG("%li megs (%li k, %li b)\n", i>>20, i>>10, i);
+ allocator_buffer_size = i>>10; /* kilobytes */
+ allocator_buffer = __pa(high_memory);
+ if (!allocator_buffer_size) {
+ printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * to simplify things, always have two cells in the list:
+ * the first and the last. This avoids some conditionals and
+ * extra code when allocating and deallocating: we only play
+ * in the middle of the list
+ */
+ head = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
+ if (!head)
+ return -ENOMEM;
+ tail = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
+ if (!tail) {
+ kfree(head);
+ return -ENOMEM;
+ }
+
+ max = allocator_buffer_size<<10;
+
+ head->size = tail->size = 0;
+ head->address = allocator_buffer;
+ tail->address = allocator_buffer + max;
+ head->next = tail;
+ tail->next = NULL;
+ allocator_list = head;
+
+ /* Back to the user code, in KB */
+ *allocator_max = allocator_buffer_size;
+
+ return 0; /* ok, ready */
}
void allocator_cleanup(void)
{
- struct allocator_struct *ptr, *next;
+ struct allocator_struct *ptr, *next;
- for (ptr = allocator_list; ptr; ptr = next) {
- next = ptr->next;
- PDEBUG("freeing list: 0x%08lx\n",ptr->address);
- kfree(ptr);
- }
+ for (ptr = allocator_list; ptr; ptr = next) {
+ next = ptr->next;
+ PDEBUG("freeing list: 0x%08lx\n", ptr->address);
+ kfree(ptr);
+ }
- allocator_buffer = 0;
- allocator_buffer_size = 0;
- allocator_list = NULL;
+ allocator_buffer = 0;
+ allocator_buffer_size = 0;
+ allocator_list = NULL;
}