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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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