intmem.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * Simple allocator for internal RAM in ETRAX FS
  3. *
  4. * Copyright (c) 2004 Axis Communications AB.
  5. */
  6. #include <linux/list.h>
  7. #include <linux/slab.h>
  8. #include <asm/io.h>
  9. #include <asm/arch/memmap.h>
  10. #define STATUS_FREE 0
  11. #define STATUS_ALLOCATED 1
  12. struct intmem_allocation {
  13. struct list_head entry;
  14. unsigned int size;
  15. unsigned offset;
  16. char status;
  17. };
  18. static struct list_head intmem_allocations;
  19. static void* intmem_virtual;
  20. static void crisv32_intmem_init(void)
  21. {
  22. static int initiated = 0;
  23. if (!initiated) {
  24. struct intmem_allocation* alloc =
  25. (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
  26. INIT_LIST_HEAD(&intmem_allocations);
  27. intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE);
  28. initiated = 1;
  29. alloc->size = MEM_INTMEM_SIZE;
  30. alloc->offset = 0;
  31. alloc->status = STATUS_FREE;
  32. list_add_tail(&alloc->entry, &intmem_allocations);
  33. }
  34. }
  35. void* crisv32_intmem_alloc(unsigned size, unsigned align)
  36. {
  37. struct intmem_allocation* allocation;
  38. struct intmem_allocation* tmp;
  39. void* ret = NULL;
  40. preempt_disable();
  41. crisv32_intmem_init();
  42. list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
  43. int alignment = allocation->offset % align;
  44. alignment = alignment ? align - alignment : alignment;
  45. if (allocation->status == STATUS_FREE &&
  46. allocation->size >= size + alignment) {
  47. if (allocation->size > size + alignment) {
  48. struct intmem_allocation* alloc =
  49. (struct intmem_allocation*)
  50. kmalloc(sizeof *alloc, GFP_ATOMIC);
  51. alloc->status = STATUS_FREE;
  52. alloc->size = allocation->size - size - alignment;
  53. alloc->offset = allocation->offset + size;
  54. list_add(&alloc->entry, &allocation->entry);
  55. if (alignment) {
  56. struct intmem_allocation* tmp;
  57. tmp = (struct intmem_allocation*)
  58. kmalloc(sizeof *tmp, GFP_ATOMIC);
  59. tmp->offset = allocation->offset;
  60. tmp->size = alignment;
  61. tmp->status = STATUS_FREE;
  62. allocation->offset += alignment;
  63. list_add_tail(&tmp->entry, &allocation->entry);
  64. }
  65. }
  66. allocation->status = STATUS_ALLOCATED;
  67. allocation->size = size;
  68. ret = (void*)((int)intmem_virtual + allocation->offset);
  69. }
  70. }
  71. preempt_enable();
  72. return ret;
  73. }
  74. void crisv32_intmem_free(void* addr)
  75. {
  76. struct intmem_allocation* allocation;
  77. struct intmem_allocation* tmp;
  78. if (addr == NULL)
  79. return;
  80. preempt_disable();
  81. crisv32_intmem_init();
  82. list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
  83. if (allocation->offset == (int)(addr - intmem_virtual)) {
  84. struct intmem_allocation* prev =
  85. list_entry(allocation->entry.prev,
  86. struct intmem_allocation, entry);
  87. struct intmem_allocation* next =
  88. list_entry(allocation->entry.next,
  89. struct intmem_allocation, entry);
  90. allocation->status = STATUS_FREE;
  91. /* Join with prev and/or next if also free */
  92. if (prev->status == STATUS_FREE) {
  93. prev->size += allocation->size;
  94. list_del(&allocation->entry);
  95. kfree(allocation);
  96. allocation = prev;
  97. }
  98. if (next->status == STATUS_FREE) {
  99. allocation->size += next->size;
  100. list_del(&next->entry);
  101. kfree(next);
  102. }
  103. preempt_enable();
  104. return;
  105. }
  106. }
  107. preempt_enable();
  108. }
  109. void* crisv32_intmem_phys_to_virt(unsigned long addr)
  110. {
  111. return (void*)(addr - MEM_INTMEM_START+
  112. (unsigned long)intmem_virtual);
  113. }
  114. unsigned long crisv32_intmem_virt_to_phys(void* addr)
  115. {
  116. return (unsigned long)((unsigned long )addr -
  117. (unsigned long)intmem_virtual + MEM_INTMEM_START);
  118. }