Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sgbuf2.c
Go to the documentation of this file.
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 
14 static bool sg_dwiter_next(struct sg_mapping_iter *miter)
15 {
16  if (sg_miter_next(miter)) {
17  miter->consumed = 0;
18  return true;
19  } else
20  return false;
21 }
22 
23 static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter)
24 {
25  return miter->length == miter->consumed && !sg_dwiter_next(miter);
26 }
27 
28 static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)
29 {
30  size_t len, left = 4;
31  uint32_t data;
32  void *addr = &data;
33 
34  do {
35  len = min(miter->length - miter->consumed, left);
36  memcpy(addr, miter->addr + miter->consumed, len);
37  miter->consumed += len;
38  left -= len;
39  if (!left)
40  return data;
41  addr += len;
42  } while (sg_dwiter_next(miter));
43 
44  memset(addr, 0, left);
45  return data;
46 }
47 
48 static inline bool needs_unaligned_copy(const void *ptr)
49 {
50 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
51  return false;
52 #else
53  return ((ptr - NULL) & 3) != 0;
54 #endif
55 }
56 
57 static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr)
58 {
59  size_t len;
60 
61  if (sg_dwiter_is_at_end(miter))
62  return true;
63 
64  len = miter->length - miter->consumed;
65 
66  if (likely(len >= 4 && !needs_unaligned_copy(
67  miter->addr + miter->consumed))) {
68  *ptr = miter->addr + miter->consumed;
69  miter->consumed += 4;
70  return true;
71  }
72 
73  return false;
74 }
75 
94 {
95  uint32_t *ptr = NULL;
96 
97  if (likely(sg_dwiter_get_next_block(miter, &ptr)))
98  return ptr ? *ptr : 0;
99 
100  return sg_dwiter_read_buffer(miter);
101 }
103 
104 static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
105 {
106  size_t len, left = 4;
107  void *addr = &data;
108 
109  do {
110  len = min(miter->length - miter->consumed, left);
111  memcpy(miter->addr, addr, len);
112  miter->consumed += len;
113  left -= len;
114  if (!left)
115  return;
116  addr += len;
117  } while (sg_dwiter_next(miter));
118 }
119 
134 {
135  uint32_t *ptr = NULL;
136 
137  if (likely(sg_dwiter_get_next_block(miter, &ptr))) {
138  if (ptr)
139  *ptr = data;
140  else
141  return;
142  } else
143  sg_dwiter_write_slow(miter, data);
144 }
146