sgbuf2.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * cb710/sgbuf2.c
  4. *
  5. * Copyright by Michał Mirosław, 2008-2009
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/cb710.h>
  10. static bool sg_dwiter_next(struct sg_mapping_iter *miter)
  11. {
  12. if (sg_miter_next(miter)) {
  13. miter->consumed = 0;
  14. return true;
  15. } else
  16. return false;
  17. }
  18. static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter)
  19. {
  20. return miter->length == miter->consumed && !sg_dwiter_next(miter);
  21. }
  22. static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)
  23. {
  24. size_t len, left = 4;
  25. uint32_t data;
  26. void *addr = &data;
  27. do {
  28. len = min(miter->length - miter->consumed, left);
  29. memcpy(addr, miter->addr + miter->consumed, len);
  30. miter->consumed += len;
  31. left -= len;
  32. if (!left)
  33. return data;
  34. addr += len;
  35. } while (sg_dwiter_next(miter));
  36. memset(addr, 0, left);
  37. return data;
  38. }
  39. static inline bool needs_unaligned_copy(const void *ptr)
  40. {
  41. #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
  42. return false;
  43. #else
  44. return ((uintptr_t)ptr & 3) != 0;
  45. #endif
  46. }
  47. static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr)
  48. {
  49. size_t len;
  50. if (sg_dwiter_is_at_end(miter))
  51. return true;
  52. len = miter->length - miter->consumed;
  53. if (likely(len >= 4 && !needs_unaligned_copy(
  54. miter->addr + miter->consumed))) {
  55. *ptr = miter->addr + miter->consumed;
  56. miter->consumed += 4;
  57. return true;
  58. }
  59. return false;
  60. }
  61. /**
  62. * cb710_sg_dwiter_read_next_block() - get next 32-bit word from sg buffer
  63. * @miter: sg mapping iterator used for reading
  64. *
  65. * Description:
  66. * Returns 32-bit word starting at byte pointed to by @miter@
  67. * handling any alignment issues. Bytes past the buffer's end
  68. * are not accessed (read) but are returned as zeroes. @miter@
  69. * is advanced by 4 bytes or to the end of buffer whichever is
  70. * closer.
  71. *
  72. * Context:
  73. * Same requirements as in sg_miter_next().
  74. *
  75. * Returns:
  76. * 32-bit word just read.
  77. */
  78. uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter)
  79. {
  80. uint32_t *ptr = NULL;
  81. if (likely(sg_dwiter_get_next_block(miter, &ptr)))
  82. return ptr ? *ptr : 0;
  83. return sg_dwiter_read_buffer(miter);
  84. }
  85. EXPORT_SYMBOL_GPL(cb710_sg_dwiter_read_next_block);
  86. static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
  87. {
  88. size_t len, left = 4;
  89. void *addr = &data;
  90. do {
  91. len = min(miter->length - miter->consumed, left);
  92. memcpy(miter->addr, addr, len);
  93. miter->consumed += len;
  94. left -= len;
  95. if (!left)
  96. return;
  97. addr += len;
  98. } while (sg_dwiter_next(miter));
  99. }
  100. /**
  101. * cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer
  102. * @miter: sg mapping iterator used for writing
  103. * @data: data to write to sg buffer
  104. *
  105. * Description:
  106. * Writes 32-bit word starting at byte pointed to by @miter@
  107. * handling any alignment issues. Bytes which would be written
  108. * past the buffer's end are silently discarded. @miter@ is
  109. * advanced by 4 bytes or to the end of buffer whichever is closer.
  110. *
  111. * Context:
  112. * Same requirements as in sg_miter_next().
  113. */
  114. void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data)
  115. {
  116. uint32_t *ptr = NULL;
  117. if (likely(sg_dwiter_get_next_block(miter, &ptr))) {
  118. if (ptr)
  119. *ptr = data;
  120. else
  121. return;
  122. } else
  123. sg_dwiter_write_slow(miter, data);
  124. }
  125. EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block);