fed up with those stupid warnings
[mmotm.git] / lib / ioq.c
bloba6c86644df4c7e679f9eb6f5f7e69913df085a2d
1 /*
2 * Copyright 2009 Novell. All Rights Reserved.
4 * See include/linux/ioq.h for documentation
6 * Author:
7 * Gregory Haskins <ghaskins@novell.com>
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <linux/sched.h>
24 #include <linux/ioq.h>
25 #include <linux/bitops.h>
26 #include <linux/module.h>
28 #ifndef NULL
29 #define NULL 0
30 #endif
32 static int ioq_iter_setpos(struct ioq_iterator *iter, u32 pos)
34 struct ioq *ioq = iter->ioq;
36 BUG_ON(pos >= ioq->count);
38 iter->pos = pos;
39 iter->desc = &ioq->ring[pos];
41 return 0;
44 static inline u32 modulo_inc(u32 val, u32 mod)
46 BUG_ON(val >= mod);
48 if (val == (mod - 1))
49 return 0;
51 return val + 1;
54 static inline int idx_full(struct ioq_ring_idx *idx)
56 return idx->full && (idx->head == idx->tail);
59 int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
60 long offset, int flags)
62 struct ioq_ring_idx *idx = iter->idx;
63 u32 pos;
65 switch (type) {
66 case ioq_seek_next:
67 pos = modulo_inc(iter->pos, iter->ioq->count);
68 break;
69 case ioq_seek_tail:
70 pos = idx->tail;
71 break;
72 case ioq_seek_head:
73 pos = idx->head;
74 break;
75 case ioq_seek_set:
76 if (offset >= iter->ioq->count)
77 return -1;
78 pos = offset;
79 break;
80 default:
81 return -EINVAL;
84 return ioq_iter_setpos(iter, pos);
86 EXPORT_SYMBOL_GPL(ioq_iter_seek);
88 static int ioq_ring_count(struct ioq_ring_idx *idx, int count)
90 if (idx->full && (idx->head == idx->tail))
91 return count;
92 else if (idx->tail >= idx->head)
93 return idx->tail - idx->head;
94 else
95 return (idx->tail + count) - idx->head;
98 static void idx_tail_push(struct ioq_ring_idx *idx, int count)
100 u32 tail = modulo_inc(idx->tail, count);
102 if (idx->head == tail) {
103 rmb();
106 * Setting full here may look racy, but note that we havent
107 * flipped the owner bit yet. So it is impossible for the
108 * remote locale to move head in such a way that this operation
109 * becomes invalid
111 idx->full = 1;
112 wmb();
115 idx->tail = tail;
118 int ioq_iter_push(struct ioq_iterator *iter, int flags)
120 struct ioq_ring_head *head_desc = iter->ioq->head_desc;
121 struct ioq_ring_idx *idx = iter->idx;
122 int ret;
125 * Its only valid to push if we are currently pointed at the tail
127 if (iter->pos != idx->tail || iter->desc->sown != iter->ioq->locale)
128 return -EINVAL;
130 idx_tail_push(idx, iter->ioq->count);
131 if (iter->dualidx) {
132 idx_tail_push(&head_desc->idx[ioq_idxtype_inuse],
133 iter->ioq->count);
134 if (head_desc->idx[ioq_idxtype_inuse].tail !=
135 head_desc->idx[ioq_idxtype_valid].tail) {
136 SHM_SIGNAL_FAULT(iter->ioq->signal,
137 "Tails not synchronized");
138 return -EINVAL;
142 wmb(); /* the index must be visible before the sown, or signal */
144 if (iter->flipowner) {
145 iter->desc->sown = !iter->ioq->locale;
146 wmb(); /* sown must be visible before we signal */
149 ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
151 if (iter->update)
152 ioq_signal(iter->ioq, 0);
154 return ret;
156 EXPORT_SYMBOL_GPL(ioq_iter_push);
158 int ioq_iter_pop(struct ioq_iterator *iter, int flags)
160 struct ioq_ring_idx *idx = iter->idx;
161 int ret;
164 * Its only valid to pop if we are currently pointed at the head
166 if (iter->pos != idx->head || iter->desc->sown != iter->ioq->locale)
167 return -EINVAL;
169 idx->head = modulo_inc(idx->head, iter->ioq->count);
170 wmb(); /* head must be visible before full */
172 if (idx->full) {
173 idx->full = 0;
174 wmb(); /* full must be visible before sown */
177 if (iter->flipowner) {
178 iter->desc->sown = !iter->ioq->locale;
179 wmb(); /* sown must be visible before we signal */
182 ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
184 if (iter->update)
185 ioq_signal(iter->ioq, 0);
187 return ret;
189 EXPORT_SYMBOL_GPL(ioq_iter_pop);
191 static struct ioq_ring_idx *idxtype_to_idx(struct ioq *ioq,
192 enum ioq_idx_type type)
194 struct ioq_ring_idx *idx;
196 switch (type) {
197 case ioq_idxtype_valid:
198 case ioq_idxtype_inuse:
199 idx = &ioq->head_desc->idx[type];
200 break;
201 default:
202 panic("IOQ: illegal index type: %d", type);
203 break;
206 return idx;
209 int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
210 enum ioq_idx_type type, int flags)
212 iter->ioq = ioq;
213 iter->update = (flags & IOQ_ITER_AUTOUPDATE);
214 iter->flipowner = !(flags & IOQ_ITER_NOFLIPOWNER);
215 iter->pos = -1;
216 iter->desc = NULL;
217 iter->dualidx = 0;
219 if (type == ioq_idxtype_both) {
221 * "both" is a special case, so we set the dualidx flag.
223 * However, we also just want to use the valid-index
224 * for normal processing, so override that here
226 type = ioq_idxtype_valid;
227 iter->dualidx = 1;
230 iter->idx = idxtype_to_idx(ioq, type);
232 return 0;
234 EXPORT_SYMBOL_GPL(ioq_iter_init);
236 int ioq_count(struct ioq *ioq, enum ioq_idx_type type)
238 return ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
240 EXPORT_SYMBOL_GPL(ioq_count);
242 int ioq_remain(struct ioq *ioq, enum ioq_idx_type type)
244 int count = ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
246 return ioq->count - count;
248 EXPORT_SYMBOL_GPL(ioq_remain);
250 int ioq_size(struct ioq *ioq)
252 return ioq->count;
254 EXPORT_SYMBOL_GPL(ioq_size);
256 int ioq_full(struct ioq *ioq, enum ioq_idx_type type)
258 struct ioq_ring_idx *idx = idxtype_to_idx(ioq, type);
260 return idx_full(idx);
262 EXPORT_SYMBOL_GPL(ioq_full);
264 static void ioq_shm_signal(struct shm_signal_notifier *notifier)
266 struct ioq *ioq = container_of(notifier, struct ioq, shm_notifier);
268 if (waitqueue_active(&ioq->wq))
269 wake_up(&ioq->wq);
271 if (ioq->notifier)
272 ioq->notifier->signal(ioq->notifier);
275 void ioq_init(struct ioq *ioq,
276 struct ioq_ops *ops,
277 enum ioq_locality locale,
278 struct ioq_ring_head *head,
279 struct shm_signal *signal,
280 size_t count)
282 memset(ioq, 0, sizeof(*ioq));
283 kref_init(&ioq->kref);
284 init_waitqueue_head(&ioq->wq);
286 ioq->ops = ops;
287 ioq->locale = locale;
288 ioq->head_desc = head;
289 ioq->ring = &head->ring[0];
290 ioq->count = count;
291 ioq->signal = signal;
293 ioq->shm_notifier.signal = &ioq_shm_signal;
294 signal->notifier = &ioq->shm_notifier;
296 EXPORT_SYMBOL_GPL(ioq_init);