sgbuf2.c 3.4 KB

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