iommu-helper.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /*
  2. * IOMMU helper functions for the free area management
  3. */
  4. #include <linux/module.h>
  5. #include <linux/bitops.h>
  6. static unsigned long find_next_zero_area(unsigned long *map,
  7. unsigned long size,
  8. unsigned long start,
  9. unsigned int nr,
  10. unsigned long align_mask)
  11. {
  12. unsigned long index, end, i;
  13. again:
  14. index = find_next_zero_bit(map, size, start);
  15. /* Align allocation */
  16. index = (index + align_mask) & ~align_mask;
  17. end = index + nr;
  18. if (end >= size)
  19. return -1;
  20. for (i = index; i < end; i++) {
  21. if (test_bit(i, map)) {
  22. start = i+1;
  23. goto again;
  24. }
  25. }
  26. return index;
  27. }
  28. static inline void set_bit_area(unsigned long *map, unsigned long i,
  29. int len)
  30. {
  31. unsigned long end = i + len;
  32. while (i < end) {
  33. __set_bit(i, map);
  34. i++;
  35. }
  36. }
  37. static inline int is_span_boundary(unsigned int index, unsigned int nr,
  38. unsigned long shift,
  39. unsigned long boundary_size)
  40. {
  41. shift = (shift + index) & (boundary_size - 1);
  42. return shift + nr > boundary_size;
  43. }
  44. unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
  45. unsigned long start, unsigned int nr,
  46. unsigned long shift, unsigned long boundary_size,
  47. unsigned long align_mask)
  48. {
  49. unsigned long index;
  50. again:
  51. index = find_next_zero_area(map, size, start, nr, align_mask);
  52. if (index != -1) {
  53. if (is_span_boundary(index, nr, shift, boundary_size)) {
  54. /* we could do more effectively */
  55. start = index + 1;
  56. goto again;
  57. }
  58. set_bit_area(map, index, nr);
  59. }
  60. return index;
  61. }
  62. EXPORT_SYMBOL(iommu_area_alloc);
  63. void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
  64. {
  65. unsigned long end = start + nr;
  66. while (start < end) {
  67. __clear_bit(start, map);
  68. start++;
  69. }
  70. }
  71. EXPORT_SYMBOL(iommu_area_free);