iommu-helper.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. int iommu_is_span_boundary(unsigned int index, unsigned int nr,
  38. unsigned long shift,
  39. unsigned long boundary_size)
  40. {
  41. BUG_ON(!is_power_of_2(boundary_size));
  42. shift = (shift + index) & (boundary_size - 1);
  43. return shift + nr > boundary_size;
  44. }
  45. unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
  46. unsigned long start, unsigned int nr,
  47. unsigned long shift, unsigned long boundary_size,
  48. unsigned long align_mask)
  49. {
  50. unsigned long index;
  51. again:
  52. index = find_next_zero_area(map, size, start, nr, align_mask);
  53. if (index != -1) {
  54. if (iommu_is_span_boundary(index, nr, shift, boundary_size)) {
  55. /* we could do more effectively */
  56. start = index + 1;
  57. goto again;
  58. }
  59. set_bit_area(map, index, nr);
  60. }
  61. return index;
  62. }
  63. EXPORT_SYMBOL(iommu_area_alloc);
  64. void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
  65. {
  66. unsigned long end = start + nr;
  67. while (start < end) {
  68. __clear_bit(start, map);
  69. start++;
  70. }
  71. }
  72. EXPORT_SYMBOL(iommu_area_free);