ethernet-mem.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * This file is based on code from OCTEON SDK by Cavium Networks.
  3. *
  4. * Copyright (c) 2003-2010 Cavium Networks
  5. *
  6. * This file is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License, Version 2, as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/netdevice.h>
  12. #include <linux/slab.h>
  13. #include <asm/octeon/octeon.h>
  14. #include "ethernet-mem.h"
  15. #include "ethernet-defines.h"
  16. #include <asm/octeon/cvmx-fpa.h>
  17. /**
  18. * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
  19. * @pool: Pool to allocate an skbuff for
  20. * @size: Size of the buffer needed for the pool
  21. * @elements: Number of buffers to allocate
  22. *
  23. * Returns the actual number of buffers allocated.
  24. */
  25. static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
  26. {
  27. int freed = elements;
  28. while (freed) {
  29. struct sk_buff *skb = dev_alloc_skb(size + 256);
  30. if (unlikely(!skb))
  31. break;
  32. skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
  33. *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
  34. cvmx_fpa_free(skb->data, pool, size / 128);
  35. freed--;
  36. }
  37. return elements - freed;
  38. }
  39. /**
  40. * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
  41. * @pool: Pool to allocate an skbuff for
  42. * @size: Size of the buffer needed for the pool
  43. * @elements: Number of buffers to allocate
  44. */
  45. static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
  46. {
  47. char *memory;
  48. do {
  49. memory = cvmx_fpa_alloc(pool);
  50. if (memory) {
  51. struct sk_buff *skb =
  52. *(struct sk_buff **)(memory - sizeof(void *));
  53. elements--;
  54. dev_kfree_skb(skb);
  55. }
  56. } while (memory);
  57. if (elements < 0)
  58. pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
  59. pool, elements);
  60. else if (elements > 0)
  61. pr_warn("Freeing of pool %u is missing %d skbuffs\n",
  62. pool, elements);
  63. }
  64. /**
  65. * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
  66. * @pool: Pool to populate
  67. * @size: Size of each buffer in the pool
  68. * @elements: Number of buffers to allocate
  69. *
  70. * Returns the actual number of buffers allocated.
  71. */
  72. static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
  73. {
  74. char *memory;
  75. char *fpa;
  76. int freed = elements;
  77. while (freed) {
  78. /*
  79. * FPA memory must be 128 byte aligned. Since we are
  80. * aligning we need to save the original pointer so we
  81. * can feed it to kfree when the memory is returned to
  82. * the kernel.
  83. *
  84. * We allocate an extra 256 bytes to allow for
  85. * alignment and space for the original pointer saved
  86. * just before the block.
  87. */
  88. memory = kmalloc(size + 256, GFP_ATOMIC);
  89. if (unlikely(!memory)) {
  90. pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
  91. elements * size, pool);
  92. break;
  93. }
  94. fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
  95. *((char **)fpa - 1) = memory;
  96. cvmx_fpa_free(fpa, pool, 0);
  97. freed--;
  98. }
  99. return elements - freed;
  100. }
  101. /**
  102. * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
  103. * @pool: FPA pool to free
  104. * @size: Size of each buffer in the pool
  105. * @elements: Number of buffers that should be in the pool
  106. */
  107. static void cvm_oct_free_hw_memory(int pool, int size, int elements)
  108. {
  109. char *memory;
  110. char *fpa;
  111. do {
  112. fpa = cvmx_fpa_alloc(pool);
  113. if (fpa) {
  114. elements--;
  115. fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
  116. memory = *((char **)fpa - 1);
  117. kfree(memory);
  118. }
  119. } while (fpa);
  120. if (elements < 0)
  121. pr_warn("Freeing of pool %u had too many buffers (%d)\n",
  122. pool, elements);
  123. else if (elements > 0)
  124. pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
  125. pool, elements);
  126. }
  127. int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
  128. {
  129. int freed;
  130. if (pool == CVMX_FPA_PACKET_POOL)
  131. freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
  132. else
  133. freed = cvm_oct_fill_hw_memory(pool, size, elements);
  134. return freed;
  135. }
  136. void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
  137. {
  138. if (pool == CVMX_FPA_PACKET_POOL)
  139. cvm_oct_free_hw_skbuff(pool, size, elements);
  140. else
  141. cvm_oct_free_hw_memory(pool, size, elements);
  142. }