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 /* Copyright © 2003-2011 Emulex. All rights reserved.  */
23 
24 /*
25  * Source file containing the implementation of the driver
26  * helper functions
27  */
28 
29 #include <oce_impl.h>
30 
31 static void oce_list_del_node(OCE_LIST_NODE_T *prev_node,
32     OCE_LIST_NODE_T *next_node);
33 static void oce_list_remove(OCE_LIST_NODE_T *list_node);
34 static void oce_list_insert_node(OCE_LIST_NODE_T  *list_node,
35     OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node);
36 /*
37  * function to breakup a block of memory into pages and return the address
38  * in an array
39  *
40  * dbuf - pointer to structure describing DMA-able memory
41  * pa_list - [OUT] pointer to an array to return the PA of pages
42  * list_size - number of entries in pa_list
43  */
44 void
oce_page_list(oce_dma_buf_t * dbuf,struct phys_addr * pa_list,int list_size)45 oce_page_list(oce_dma_buf_t *dbuf,
46     struct phys_addr *pa_list, int list_size)
47 {
48 	int i = 0;
49 	uint64_t paddr = 0;
50 
51 	ASSERT(dbuf != NULL);
52 	ASSERT(pa_list != NULL);
53 
54 	paddr = DBUF_PA(dbuf);
55 	for (i = 0; i < list_size; i++) {
56 		pa_list[i].lo = ADDR_LO(paddr);
57 		pa_list[i].hi = ADDR_HI(paddr);
58 		paddr += PAGE_4K;
59 	}
60 } /* oce_page_list */
61 
62 void
oce_list_link_init(OCE_LIST_NODE_T * list_node)63 oce_list_link_init(OCE_LIST_NODE_T  *list_node)
64 {
65 	list_node->next = NULL;
66 	list_node->prev = NULL;
67 }
68 
69 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)70 oce_list_insert_node(OCE_LIST_NODE_T  *list_node, OCE_LIST_NODE_T *prev_node,
71     OCE_LIST_NODE_T *next_node)
72 {
73 	next_node->prev = list_node;
74 	list_node->next = next_node;
75 	list_node->prev = prev_node;
76 	prev_node->next = list_node;
77 }
78 
79 static inline void
oce_list_del_node(OCE_LIST_NODE_T * prev_node,OCE_LIST_NODE_T * next_node)80 oce_list_del_node(OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node)
81 {
82 	next_node->prev = prev_node;
83 	prev_node->next = next_node;
84 }
85 
86 static inline void
oce_list_remove(OCE_LIST_NODE_T * list_node)87 oce_list_remove(OCE_LIST_NODE_T *list_node)
88 {
89 	oce_list_del_node(list_node->prev, list_node->next);
90 	list_node->next = list_node->prev = NULL;
91 }
92 
93 void
oce_list_create(OCE_LIST_T * list_hdr,void * arg)94 oce_list_create(OCE_LIST_T  *list_hdr, void *arg)
95 {
96 	list_hdr->head.next = list_hdr->head.prev = &list_hdr->head;
97 	mutex_init(&list_hdr->list_lock, NULL, MUTEX_DRIVER, arg);
98 	list_hdr->nitems = 0;
99 }
100 
101 void
oce_list_destroy(OCE_LIST_T * list_hdr)102 oce_list_destroy(OCE_LIST_T *list_hdr)
103 {
104 	ASSERT(list_hdr->nitems == 0);
105 	list_hdr->head.next = list_hdr->head.prev = NULL;
106 	mutex_destroy(&list_hdr->list_lock);
107 
108 }
109 
110 void
oce_list_insert_tail(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)111 oce_list_insert_tail(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
112 {
113 	OCE_LIST_NODE_T *head = &list_hdr->head;
114 
115 	ASSERT(list_hdr != NULL);
116 	ASSERT(list_node != NULL);
117 
118 	mutex_enter(&list_hdr->list_lock);
119 	oce_list_insert_node(list_node, head->prev, head);
120 	list_hdr->nitems++;
121 	mutex_exit(&list_hdr->list_lock);
122 }
123 
124 void
oce_list_insert_head(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)125 oce_list_insert_head(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
126 {
127 	OCE_LIST_NODE_T *head = &list_hdr->head;
128 
129 	ASSERT(list_hdr != NULL);
130 	ASSERT(list_node != NULL);
131 
132 	mutex_enter(&list_hdr->list_lock);
133 	oce_list_insert_node(list_node, head, head->next);
134 	list_hdr->nitems++;
135 	mutex_exit(&list_hdr->list_lock);
136 }
137 
138 void *
oce_list_remove_tail(OCE_LIST_T * list_hdr)139 oce_list_remove_tail(OCE_LIST_T *list_hdr)
140 {
141 	OCE_LIST_NODE_T *list_node;
142 
143 	if (list_hdr == NULL) {
144 		return (NULL);
145 	}
146 
147 	mutex_enter(&list_hdr->list_lock);
148 
149 	if (list_hdr->nitems <= 0) {
150 		mutex_exit(&list_hdr->list_lock);
151 		return (NULL);
152 	}
153 
154 	list_node = list_hdr->head.prev;
155 	oce_list_remove(list_node);
156 	list_hdr->nitems--;
157 	mutex_exit(&list_hdr->list_lock);
158 	return (list_node);
159 }
160 
161 void *
oce_list_remove_head(OCE_LIST_T * list_hdr)162 oce_list_remove_head(OCE_LIST_T  *list_hdr)
163 {
164 	OCE_LIST_NODE_T *list_node;
165 
166 	if (list_hdr == NULL) {
167 		return (NULL);
168 	}
169 
170 	mutex_enter(&list_hdr->list_lock);
171 
172 	if (list_hdr->nitems <= 0) {
173 		mutex_exit(&list_hdr->list_lock);
174 		return (NULL);
175 	}
176 
177 	list_node = list_hdr->head.next;
178 
179 	if (list_node != NULL) {
180 		oce_list_remove(list_node);
181 		list_hdr->nitems--;
182 	}
183 
184 	mutex_exit(&list_hdr->list_lock);
185 	return (list_node);
186 }
187 
188 boolean_t
oce_list_is_empty(OCE_LIST_T * list_hdr)189 oce_list_is_empty(OCE_LIST_T *list_hdr)
190 {
191 	if (list_hdr == NULL)
192 		return (B_TRUE);
193 	else
194 		return (list_hdr->nitems <= 0);
195 }
196 
197 int
oce_list_items_avail(OCE_LIST_T * list_hdr)198 oce_list_items_avail(OCE_LIST_T *list_hdr)
199 {
200 	if (list_hdr == NULL)
201 		return (0);
202 	else
203 		return (list_hdr->nitems);
204 }
205 
206 void
oce_list_remove_node(OCE_LIST_T * list_hdr,OCE_LIST_NODE_T * list_node)207 oce_list_remove_node(OCE_LIST_T  *list_hdr, OCE_LIST_NODE_T *list_node)
208 {
209 	mutex_enter(&list_hdr->list_lock);
210 	oce_list_remove(list_node);
211 	mutex_exit(&list_hdr->list_lock);
212 }
213 
214 void
oce_gen_hkey(char * hkey,int key_size)215 oce_gen_hkey(char *hkey, int key_size)
216 {
217 	int i;
218 	int nkeys = key_size/sizeof (uint32_t);
219 	for (i = 0; i < nkeys; i++) {
220 		(void) random_get_pseudo_bytes(
221 		    (uint8_t *)&hkey[i * sizeof (uint32_t)],
222 		    sizeof (uint32_t));
223 	}
224 }
225 
226 int
oce_atomic_reserve(uint32_t * count_p,uint32_t n)227 oce_atomic_reserve(uint32_t *count_p, uint32_t n)
228 {
229 	uint32_t oldval;
230 	uint32_t newval;
231 
232 	/*
233 	 * ATOMICALLY
234 	 */
235 	do {
236 		oldval = *count_p;
237 		if (oldval < n)
238 			return (-1);
239 		newval = oldval - n;
240 
241 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
242 
243 	return (newval);
244 }
245