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
34static void oce_list_del_node(OCE_LIST_NODE_T *prev_node,
35    OCE_LIST_NODE_T *next_node);
36static void oce_list_remove(OCE_LIST_NODE_T *list_node);
37static 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 */
47void
48oce_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
65void
66oce_list_link_init(OCE_LIST_NODE_T  *list_node)
67{
68	list_node->next = NULL;
69	list_node->prev = NULL;
70}
71
72static inline void
73oce_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
82static inline void
83oce_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
89static inline void
90oce_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
96void
97oce_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
104void
105oce_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
113void
114oce_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
127void
128oce_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
141void *
142oce_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
164void *
165oce_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
191boolean_t
192oce_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
200int
201oce_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
209void
210oce_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
217void
218oce_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
229int
230oce_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