0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/cb710.h>
0010
0011 static bool sg_dwiter_next(struct sg_mapping_iter *miter)
0012 {
0013 if (sg_miter_next(miter)) {
0014 miter->consumed = 0;
0015 return true;
0016 } else
0017 return false;
0018 }
0019
0020 static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter)
0021 {
0022 return miter->length == miter->consumed && !sg_dwiter_next(miter);
0023 }
0024
0025 static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)
0026 {
0027 size_t len, left = 4;
0028 uint32_t data;
0029 void *addr = &data;
0030
0031 do {
0032 len = min(miter->length - miter->consumed, left);
0033 memcpy(addr, miter->addr + miter->consumed, len);
0034 miter->consumed += len;
0035 left -= len;
0036 if (!left)
0037 return data;
0038 addr += len;
0039 } while (sg_dwiter_next(miter));
0040
0041 memset(addr, 0, left);
0042 return data;
0043 }
0044
0045 static inline bool needs_unaligned_copy(const void *ptr)
0046 {
0047 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
0048 return false;
0049 #else
0050 return ((uintptr_t)ptr & 3) != 0;
0051 #endif
0052 }
0053
0054 static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr)
0055 {
0056 size_t len;
0057
0058 if (sg_dwiter_is_at_end(miter))
0059 return true;
0060
0061 len = miter->length - miter->consumed;
0062
0063 if (likely(len >= 4 && !needs_unaligned_copy(
0064 miter->addr + miter->consumed))) {
0065 *ptr = miter->addr + miter->consumed;
0066 miter->consumed += 4;
0067 return true;
0068 }
0069
0070 return false;
0071 }
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter)
0091 {
0092 uint32_t *ptr = NULL;
0093
0094 if (likely(sg_dwiter_get_next_block(miter, &ptr)))
0095 return ptr ? *ptr : 0;
0096
0097 return sg_dwiter_read_buffer(miter);
0098 }
0099 EXPORT_SYMBOL_GPL(cb710_sg_dwiter_read_next_block);
0100
0101 static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
0102 {
0103 size_t len, left = 4;
0104 void *addr = &data;
0105
0106 do {
0107 len = min(miter->length - miter->consumed, left);
0108 memcpy(miter->addr, addr, len);
0109 miter->consumed += len;
0110 left -= len;
0111 if (!left)
0112 return;
0113 addr += len;
0114 } while (sg_dwiter_next(miter));
0115 }
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data)
0132 {
0133 uint32_t *ptr = NULL;
0134
0135 if (likely(sg_dwiter_get_next_block(miter, &ptr))) {
0136 if (ptr)
0137 *ptr = data;
0138 else
0139 return;
0140 } else
0141 sg_dwiter_write_slow(miter, data);
0142 }
0143 EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block);
0144