1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Source file containing the implementation of the driver
29 * helper functions
30 */
31
32 #include <oce_impl.h>
33
34 static void oce_list_del_node(OCE_LIST_NODE_T *prev_node,
35 OCE_LIST_NODE_T *next_node);
36 static void oce_list_remove(OCE_LIST_NODE_T *list_node);
37 static void oce_list_insert_node(OCE_LIST_NODE_T *list_node,
38 OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node);
39 /*
40 * function to breakup a block of memory into pages and return the address
41 * in an array
42 *
43 * dbuf - pointer to structure describing DMA-able memory
44 * pa_list - [OUT] pointer to an array to return the PA of pages
45 * list_size - number of entries in pa_list
46 */
47 void
oce_page_list(oce_dma_buf_t * dbuf,struct phys_addr * pa_list,int list_size)48 oce_page_list(oce_dma_buf_t *dbuf,
49 struct phys_addr *pa_list, int list_size)
50 {
51 int i = 0;
52 uint64_t paddr = 0;
53
54 ASSERT(dbuf != NULL);
55 ASSERT(pa_list != NULL);
56
57 paddr = DBUF_PA(dbuf);
58 for (i = 0; i < list_size; i++) {
59 pa_list[i].lo = ADDR_LO(paddr);
60 pa_list[i].hi = ADDR_HI(paddr);
61 paddr += PAGE_4K;
62 }
63 } /* oce_page_list */
64
65 void
oce_list_link_init(OCE_LIST_NODE_T * list_node)66 oce_list_link_init(OCE_LIST_NODE_T *list_node)
67 {
68 list_node->next = NULL;
69 list_node->prev = NULL;
70 }
71
72 static inline void
oce_list_insert_node(OCE_LIST_NODE_T * list_node,OCE_LIST_NODE_T * prev_node,OCE_LIST_NODE_T * next_node)73 oce_list_insert_node(OCE_LIST_NODE_T *list_node, OCE_LIST_NODE_T *prev_node,
74 OCE_LIST_NODE_T *next_node)
75 {
76 next_node->prev = list_node;
77 list_node->next = next_node;
78 list_node->prev = prev_node;
79 prev_node->next = list_node;
80 }
81
82 static inline void
oce_list_del_node(OCE_LIST_NODE_T * prev_node,OCE_LIST_NODE_T * next_node)83 oce_list_del_node(OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node)
84 {
85 next_node->prev = prev_node;
86 prev_node->next = next_node;
87 }
88
89 static inline void
oce_list_remove(OCE_LIST_NODE_T * list_node)90 oce_list_remove(OCE_LIST_NODE_T *list_node)
91 {
92 oce_list_del_node(list_node->prev, list_node->next);
93 list_node->next = list_node->prev = NULL;
94 }
95
96 void
oce_list_create(OCE_LIST_T * list_hdr,void * arg)97 oce_list_create(OCE_LIST_T *list_hdr, void *arg)
98 {
99 list_hdr->head.next = list_hdr->head.prev = &list_hdr->head;
100 mutex_init(&list_hdr->list_lock, NULL, MUTEX_DRIVER, arg);
101 list_hdr->nitems = 0;
102 }
103
104 void
oce_list_destroy(OCE_LIST_T * list_hdr)105 oce_list_destroy(OCE_LIST_T *list_hdr)
106 {
107 ASSERT(list_hdr->nitems == 0);
108 list_hdr->head.next = list_hdr->head.prev = NULL;
109 mutex_destroy(&list_hdr->list_lock);
110
111 }
112
113 void
oce_list_insert_tail(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)114 oce_list_insert_tail(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
115 {
116 OCE_LIST_NODE_T *head = &list_hdr->head;
117
118 ASSERT(list_hdr != NULL);
119 ASSERT(list_node != NULL);
120
121 mutex_enter(&list_hdr->list_lock);
122 oce_list_insert_node(list_node, head->prev, head);
123 list_hdr->nitems++;
124 mutex_exit(&list_hdr->list_lock);
125 }
126
127 void
oce_list_insert_head(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)128 oce_list_insert_head(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
129 {
130 OCE_LIST_NODE_T *head = &list_hdr->head;
131
132 ASSERT(list_hdr != NULL);
133 ASSERT(list_node != NULL);
134
135 mutex_enter(&list_hdr->list_lock);
136 oce_list_insert_node(list_node, head, head->next);
137 list_hdr->nitems++;
138 mutex_exit(&list_hdr->list_lock);
139 }
140
141 void *
oce_list_remove_tail(OCE_LIST_T * list_hdr)142 oce_list_remove_tail(OCE_LIST_T *list_hdr)
143 {
144 OCE_LIST_NODE_T *list_node;
145
146 if (list_hdr == NULL) {
147 return (NULL);
148 }
149
150 mutex_enter(&list_hdr->list_lock);
151
152 if (list_hdr->nitems <= 0) {
153 mutex_exit(&list_hdr->list_lock);
154 return (NULL);
155 }
156
157 list_node = list_hdr->head.prev;
158 oce_list_remove(list_node);
159 list_hdr->nitems--;
160 mutex_exit(&list_hdr->list_lock);
161 return (list_node);
162 }
163
164 void *
oce_list_remove_head(OCE_LIST_T * list_hdr)165 oce_list_remove_head(OCE_LIST_T *list_hdr)
166 {
167 OCE_LIST_NODE_T *list_node;
168
169 if (list_hdr == NULL) {
170 return (NULL);
171 }
172
173 mutex_enter(&list_hdr->list_lock);
174
175 if (list_hdr->nitems <= 0) {
176 mutex_exit(&list_hdr->list_lock);
177 return (NULL);
178 }
179
180 list_node = list_hdr->head.next;
181
182 if (list_node != NULL) {
183 oce_list_remove(list_node);
184 list_hdr->nitems--;
185 }
186
187 mutex_exit(&list_hdr->list_lock);
188 return (list_node);
189 }
190
191 boolean_t
oce_list_is_empty(OCE_LIST_T * list_hdr)192 oce_list_is_empty(OCE_LIST_T *list_hdr)
193 {
194 if (list_hdr == NULL)
195 return (B_TRUE);
196 else
197 return (list_hdr->nitems <= 0);
198 }
199
200 int
oce_list_items_avail(OCE_LIST_T * list_hdr)201 oce_list_items_avail(OCE_LIST_T *list_hdr)
202 {
203 if (list_hdr == NULL)
204 return (0);
205 else
206 return (list_hdr->nitems);
207 }
208
209 void
oce_list_remove_node(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)210 oce_list_remove_node(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
211 {
212 mutex_enter(&list_hdr->list_lock);
213 oce_list_remove(list_node);
214 mutex_exit(&list_hdr->list_lock);
215 }
216
217 void
oce_gen_hkey(char * hkey,int key_size)218 oce_gen_hkey(char *hkey, int key_size)
219 {
220 int i;
221 int nkeys = key_size/sizeof (uint32_t);
222 for (i = 0; i < nkeys; i++) {
223 (void) random_get_pseudo_bytes(
224 (uint8_t *)&hkey[i * sizeof (uint32_t)],
225 sizeof (uint32_t));
226 }
227 }
228
229 int
oce_atomic_reserve(uint32_t * count_p,uint32_t n)230 oce_atomic_reserve(uint32_t *count_p, uint32_t n)
231 {
232 uint32_t oldval;
233 uint32_t newval;
234
235 /*
236 * ATOMICALLY
237 */
238 do {
239 oldval = *count_p;
240 if (oldval < n)
241 return (-1);
242 newval = oldval - n;
243
244 } while (atomic_cas_32(count_p, oldval, newval) != oldval);
245
246 return (newval);
247 }
248