2 * Copyright 2009 Novell. All Rights Reserved.
4 * See include/linux/ioq.h for documentation
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>
32 static int ioq_iter_setpos(struct ioq_iterator
*iter
, u32 pos
)
34 struct ioq
*ioq
= iter
->ioq
;
36 BUG_ON(pos
>= ioq
->count
);
39 iter
->desc
= &ioq
->ring
[pos
];
44 static inline u32
modulo_inc(u32 val
, u32 mod
)
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
;
67 pos
= modulo_inc(iter
->pos
, iter
->ioq
->count
);
76 if (offset
>= iter
->ioq
->count
)
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
))
92 else if (idx
->tail
>= idx
->head
)
93 return idx
->tail
- idx
->head
;
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
) {
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
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
;
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
)
130 idx_tail_push(idx
, iter
->ioq
->count
);
132 idx_tail_push(&head_desc
->idx
[ioq_idxtype_inuse
],
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");
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
);
152 ioq_signal(iter
->ioq
, 0);
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
;
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
)
169 idx
->head
= modulo_inc(idx
->head
, iter
->ioq
->count
);
170 wmb(); /* head must be visible before full */
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
);
185 ioq_signal(iter
->ioq
, 0);
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
;
197 case ioq_idxtype_valid
:
198 case ioq_idxtype_inuse
:
199 idx
= &ioq
->head_desc
->idx
[type
];
202 panic("IOQ: illegal index type: %d", type
);
209 int ioq_iter_init(struct ioq
*ioq
, struct ioq_iterator
*iter
,
210 enum ioq_idx_type type
, int flags
)
213 iter
->update
= (flags
& IOQ_ITER_AUTOUPDATE
);
214 iter
->flipowner
= !(flags
& IOQ_ITER_NOFLIPOWNER
);
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
;
230 iter
->idx
= idxtype_to_idx(ioq
, type
);
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
)
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
))
272 ioq
->notifier
->signal(ioq
->notifier
);
275 void ioq_init(struct ioq
*ioq
,
277 enum ioq_locality locale
,
278 struct ioq_ring_head
*head
,
279 struct shm_signal
*signal
,
282 memset(ioq
, 0, sizeof(*ioq
));
283 kref_init(&ioq
->kref
);
284 init_waitqueue_head(&ioq
->wq
);
287 ioq
->locale
= locale
;
288 ioq
->head_desc
= head
;
289 ioq
->ring
= &head
->ring
[0];
291 ioq
->signal
= signal
;
293 ioq
->shm_notifier
.signal
= &ioq_shm_signal
;
294 signal
->notifier
= &ioq
->shm_notifier
;
296 EXPORT_SYMBOL_GPL(ioq_init
);