net/virtio: rationalize queue flushing
[dpdk.git] / lib / librte_ring / rte_ring_generic.h
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /*
35  * Derived from FreeBSD's bufring.h
36  *
37  **************************************************************************
38  *
39  * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
40  * All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions are met:
44  *
45  * 1. Redistributions of source code must retain the above copyright notice,
46  *    this list of conditions and the following disclaimer.
47  *
48  * 2. The name of Kip Macy nor the names of other
49  *    contributors may be used to endorse or promote products derived from
50  *    this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
53  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
56  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
59  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
60  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62  * POSSIBILITY OF SUCH DAMAGE.
63  *
64  ***************************************************************************/
65
66 #ifndef _RTE_RING_GENERIC_H_
67 #define _RTE_RING_GENERIC_H_
68
69 static __rte_always_inline void
70 update_tail(struct rte_ring_headtail *ht, uint32_t old_val, uint32_t new_val,
71                 uint32_t single, uint32_t enqueue)
72 {
73         if (enqueue)
74                 rte_smp_wmb();
75         else
76                 rte_smp_rmb();
77         /*
78          * If there are other enqueues/dequeues in progress that preceded us,
79          * we need to wait for them to complete
80          */
81         if (!single)
82                 while (unlikely(ht->tail != old_val))
83                         rte_pause();
84
85         ht->tail = new_val;
86 }
87
88 /**
89  * @internal This function updates the producer head for enqueue
90  *
91  * @param r
92  *   A pointer to the ring structure
93  * @param is_sp
94  *   Indicates whether multi-producer path is needed or not
95  * @param n
96  *   The number of elements we will want to enqueue, i.e. how far should the
97  *   head be moved
98  * @param behavior
99  *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
100  *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
101  * @param old_head
102  *   Returns head value as it was before the move, i.e. where enqueue starts
103  * @param new_head
104  *   Returns the current/new head value i.e. where enqueue finishes
105  * @param free_entries
106  *   Returns the amount of free space in the ring BEFORE head was moved
107  * @return
108  *   Actual number of objects enqueued.
109  *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
110  */
111 static __rte_always_inline unsigned int
112 __rte_ring_move_prod_head(struct rte_ring *r, int is_sp,
113                 unsigned int n, enum rte_ring_queue_behavior behavior,
114                 uint32_t *old_head, uint32_t *new_head,
115                 uint32_t *free_entries)
116 {
117         const uint32_t capacity = r->capacity;
118         unsigned int max = n;
119         int success;
120
121         do {
122                 /* Reset n to the initial burst count */
123                 n = max;
124
125                 *old_head = r->prod.head;
126
127                 /* add rmb barrier to avoid load/load reorder in weak
128                  * memory model. It is noop on x86
129                  */
130                 rte_smp_rmb();
131
132                 const uint32_t cons_tail = r->cons.tail;
133                 /*
134                  *  The subtraction is done between two unsigned 32bits value
135                  * (the result is always modulo 32 bits even if we have
136                  * *old_head > cons_tail). So 'free_entries' is always between 0
137                  * and capacity (which is < size).
138                  */
139                 *free_entries = (capacity + cons_tail - *old_head);
140
141                 /* check that we have enough room in ring */
142                 if (unlikely(n > *free_entries))
143                         n = (behavior == RTE_RING_QUEUE_FIXED) ?
144                                         0 : *free_entries;
145
146                 if (n == 0)
147                         return 0;
148
149                 *new_head = *old_head + n;
150                 if (is_sp)
151                         r->prod.head = *new_head, success = 1;
152                 else
153                         success = rte_atomic32_cmpset(&r->prod.head,
154                                         *old_head, *new_head);
155         } while (unlikely(success == 0));
156         return n;
157 }
158
159 /**
160  * @internal This function updates the consumer head for dequeue
161  *
162  * @param r
163  *   A pointer to the ring structure
164  * @param is_sc
165  *   Indicates whether multi-consumer path is needed or not
166  * @param n
167  *   The number of elements we will want to enqueue, i.e. how far should the
168  *   head be moved
169  * @param behavior
170  *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
171  *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
172  * @param old_head
173  *   Returns head value as it was before the move, i.e. where dequeue starts
174  * @param new_head
175  *   Returns the current/new head value i.e. where dequeue finishes
176  * @param entries
177  *   Returns the number of entries in the ring BEFORE head was moved
178  * @return
179  *   - Actual number of objects dequeued.
180  *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
181  */
182 static __rte_always_inline unsigned int
183 __rte_ring_move_cons_head(struct rte_ring *r, int is_sc,
184                 unsigned int n, enum rte_ring_queue_behavior behavior,
185                 uint32_t *old_head, uint32_t *new_head,
186                 uint32_t *entries)
187 {
188         unsigned int max = n;
189         int success;
190
191         /* move cons.head atomically */
192         do {
193                 /* Restore n as it may change every loop */
194                 n = max;
195
196                 *old_head = r->cons.head;
197
198                 /* add rmb barrier to avoid load/load reorder in weak
199                  * memory model. It is noop on x86
200                  */
201                 rte_smp_rmb();
202
203                 const uint32_t prod_tail = r->prod.tail;
204                 /* The subtraction is done between two unsigned 32bits value
205                  * (the result is always modulo 32 bits even if we have
206                  * cons_head > prod_tail). So 'entries' is always between 0
207                  * and size(ring)-1.
208                  */
209                 *entries = (prod_tail - *old_head);
210
211                 /* Set the actual entries for dequeue */
212                 if (n > *entries)
213                         n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
214
215                 if (unlikely(n == 0))
216                         return 0;
217
218                 *new_head = *old_head + n;
219                 if (is_sc)
220                         r->cons.head = *new_head, success = 1;
221                 else
222                         success = rte_atomic32_cmpset(&r->cons.head, *old_head,
223                                         *new_head);
224         } while (unlikely(success == 0));
225         return n;
226 }
227
228 #endif /* _RTE_RING_GENERIC_H_ */