ethernet-mem.c 3.9 KB

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