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 /*
35  * inline function to get a list of pages from a dbuf
36  *
37  * dbuf - memory map from which to get the pa
38  * pa_list - physical address array to fill
39  * list_size - size of the array
40  *
41  * return none
42  */
43 
44 static void oce_list_del_node(OCE_LIST_NODE_T *prev_node,
45     OCE_LIST_NODE_T *next_node);
46 static void oce_list_remove(OCE_LIST_NODE_T *list_node);
47 static void oce_list_insert_node(OCE_LIST_NODE_T  *list_node,
48     OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node);
49 /*
50  * function to breakup a block of memory into pages and return the address
51  * in an array
52  *
53  * dbuf - pointer to structure describing DMA-able memory
54  * pa_list - [OUT] pointer to an array to return the PA of pages
55  * list_size - number of entries in pa_list
56  */
57 void
58 oce_page_list(oce_dma_buf_t *dbuf,
59     struct phys_addr *pa_list, int list_size)
60 {
61 	int i = 0;
62 	uint64_t paddr = 0;
63 
64 	ASSERT(dbuf != NULL);
65 	ASSERT(pa_list != NULL);
66 
67 	paddr = DBUF_PA(dbuf);
68 	for (i = 0; i < list_size; i++) {
69 		pa_list[i].lo = ADDR_LO(paddr);
70 		pa_list[i].hi = ADDR_HI(paddr);
71 		paddr += PAGE_4K;
72 	}
73 } /* oce_page_list */
74 
75 static inline void
76 oce_list_insert_node(OCE_LIST_NODE_T  *list_node, OCE_LIST_NODE_T *prev_node,
77     OCE_LIST_NODE_T *next_node)
78 {
79 	next_node->prev = list_node;
80 	list_node->next = next_node;
81 	list_node->prev = prev_node;
82 	prev_node->next = list_node;
83 }
84 
85 static inline void
86 oce_list_del_node(OCE_LIST_NODE_T *prev_node, OCE_LIST_NODE_T *next_node)
87 {
88 	next_node->prev = prev_node;
89 	prev_node->next = next_node;
90 }
91 
92 static inline void
93 oce_list_remove(OCE_LIST_NODE_T *list_node)
94 {
95 	oce_list_del_node(list_node->prev, list_node->next);
96 	list_node->next = list_node->prev = NULL;
97 }
98 
99 void
100 oce_list_create(OCE_LIST_T  *list_hdr, void *arg)
101 {
102 	list_hdr->head.next = list_hdr->head.prev = &list_hdr->head;
103 	mutex_init(&list_hdr->list_lock, NULL, MUTEX_DRIVER, arg);
104 	list_hdr->nitems = 0;
105 }
106 
107 void
108 oce_list_destroy(OCE_LIST_T *list_hdr)
109 {
110 	ASSERT(list_hdr->nitems == 0);
111 	list_hdr->head.next = list_hdr->head.prev = NULL;
112 	mutex_destroy(&list_hdr->list_lock);
113 
114 }
115 
116 void
117 oce_list_insert_tail(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
118 {
119 	OCE_LIST_NODE_T *head = &list_hdr->head;
120 
121 	ASSERT(list_hdr != NULL);
122 	ASSERT(list_node != NULL);
123 
124 	mutex_enter(&list_hdr->list_lock);
125 	oce_list_insert_node(list_node, head->prev, head);
126 	list_hdr->nitems++;
127 	mutex_exit(&list_hdr->list_lock);
128 }
129 
130 void
131 oce_list_insert_head(OCE_LIST_T *list_hdr, OCE_LIST_NODE_T *list_node)
132 {
133 	OCE_LIST_NODE_T *head = &list_hdr->head;
134 
135 	ASSERT(list_hdr != NULL);
136 	ASSERT(list_node != NULL);
137 
138 	mutex_enter(&list_hdr->list_lock);
139 	oce_list_insert_node(list_node, head, head->next);
140 	list_hdr->nitems++;
141 	mutex_exit(&list_hdr->list_lock);
142 }
143 
144 void *
145 oce_list_remove_tail(OCE_LIST_T *list_hdr)
146 {
147 	OCE_LIST_NODE_T *list_node;
148 
149 	if (list_hdr == NULL) {
150 		return (NULL);
151 	}
152 
153 	mutex_enter(&list_hdr->list_lock);
154 
155 	if (list_hdr->nitems <= 0) {
156 		mutex_exit(&list_hdr->list_lock);
157 		return (NULL);
158 	}
159 
160 	list_node = list_hdr->head.prev;
161 	oce_list_remove(list_node);
162 	list_hdr->nitems--;
163 	mutex_exit(&list_hdr->list_lock);
164 	return (list_node);
165 }
166 
167 void *
168 oce_list_remove_head(OCE_LIST_T  *list_hdr)
169 {
170 	OCE_LIST_NODE_T *list_node;
171 
172 	if (list_hdr == NULL) {
173 		return (NULL);
174 	}
175 
176 	mutex_enter(&list_hdr->list_lock);
177 
178 	if (list_hdr->nitems <= 0) {
179 		mutex_exit(&list_hdr->list_lock);
180 		return (NULL);
181 	}
182 
183 	list_node = list_hdr->head.next;
184 
185 	if (list_node != NULL) {
186 		oce_list_remove(list_node);
187 		list_hdr->nitems--;
188 	}
189 
190 	mutex_exit(&list_hdr->list_lock);
191 	return (list_node);
192 }
193 
194 boolean_t
195 oce_list_is_empty(OCE_LIST_T *list_hdr)
196 {
197 	if (list_hdr == NULL)
198 		return (B_TRUE);
199 	else
200 		return (list_hdr->nitems <= 0);
201 }
202 
203 int
204 oce_list_items_avail(OCE_LIST_T *list_hdr)
205 {
206 	if (list_hdr == NULL)
207 		return (0);
208 	else
209 		return (list_hdr->nitems);
210 }
211 
212 void
213 oce_list_remove_node(OCE_LIST_T  *list_hdr, OCE_LIST_NODE_T *list_node)
214 {
215 	mutex_enter(&list_hdr->list_lock);
216 	oce_list_remove(list_node);
217 	mutex_exit(&list_hdr->list_lock);
218 }
219