iommu-helper.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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. void iommu_area_reserve(unsigned long *map, unsigned long i, int len)
  29. {
  30. unsigned long end = i + len;
  31. while (i < end) {
  32. __set_bit(i, map);
  33. i++;
  34. }
  35. }
  36. int iommu_is_span_boundary(unsigned int index, unsigned int nr,
  37. unsigned long shift,
  38. unsigned long boundary_size)
  39. {
  40. BUG_ON(!is_power_of_2(boundary_size));
  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 (iommu_is_span_boundary(index, nr, shift, boundary_size)) {
  54. /* we could do more effectively */
  55. start = index + 1;
  56. goto again;
  57. }
  58. iommu_area_reserve(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);
  72. unsigned long iommu_num_pages(unsigned long addr, unsigned long len,
  73. unsigned long io_page_size)
  74. {
  75. unsigned long size = (addr & (io_page_size - 1)) + len;
  76. return DIV_ROUND_UP(size, io_page_size);
  77. }
  78. EXPORT_SYMBOL(iommu_num_pages);