1221167Sgnn/*-
2221167Sgnn * Copyright(c) 2002-2011 Exar Corp.
3221167Sgnn * All rights reserved.
4221167Sgnn *
5221167Sgnn * Redistribution and use in source and binary forms, with or without
6221167Sgnn * modification are permitted provided the following conditions are met:
7221167Sgnn *
8221167Sgnn *    1. Redistributions of source code must retain the above copyright notice,
9221167Sgnn *       this list of conditions and the following disclaimer.
10221167Sgnn *
11221167Sgnn *    2. Redistributions in binary form must reproduce the above copyright
12221167Sgnn *       notice, this list of conditions and the following disclaimer in the
13221167Sgnn *       documentation and/or other materials provided with the distribution.
14221167Sgnn *
15221167Sgnn *    3. Neither the name of the Exar Corporation nor the names of its
16221167Sgnn *       contributors may be used to endorse or promote products derived from
17221167Sgnn *       this software without specific prior written permission.
18221167Sgnn *
19221167Sgnn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20221167Sgnn * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21221167Sgnn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22221167Sgnn * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23221167Sgnn * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24221167Sgnn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25221167Sgnn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26221167Sgnn * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27221167Sgnn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28221167Sgnn * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29221167Sgnn * POSSIBILITY OF SUCH DAMAGE.
30221167Sgnn */
31221167Sgnn/*$FreeBSD$*/
32221167Sgnn
33221167Sgnn#include <dev/vxge/vxgehal/vxgehal.h>
34221167Sgnn
35221167Sgnn/*
36221167Sgnn * vxge_queue_item_data - Get item's data.
37221167Sgnn * @item: Queue item.
38221167Sgnn *
39221167Sgnn * Returns:  item data(variable size). Note that vxge_queue_t
40221167Sgnn * contains items comprized of a fixed vxge_queue_item_t "header"
41221167Sgnn * and a variable size data. This function returns the variable
42221167Sgnn * user-defined portion of the queue item.
43221167Sgnn */
44221167Sgnnvoid *
45221167Sgnnvxge_queue_item_data(vxge_queue_item_t *item)
46221167Sgnn{
47221167Sgnn	return (char *) item + sizeof(vxge_queue_item_t);
48221167Sgnn}
49221167Sgnn
50221167Sgnn/*
51221167Sgnn * __queue_consume - (Lockless) dequeue an item from the specified queue.
52221167Sgnn *
53221167Sgnn * @queue: Event queue.
54221167Sgnn * @data_max_size: Maximum size of the data
55221167Sgnn * @item: Queue item
56221167Sgnn * See vxge_queue_consume().
57221167Sgnn */
58221167Sgnnstatic vxge_queue_status_e
59221167Sgnn__queue_consume(vxge_queue_t *queue,
60221167Sgnn    u32 data_max_size,
61221167Sgnn    vxge_queue_item_t *item)
62221167Sgnn{
63221167Sgnn	int real_size;
64221167Sgnn	vxge_queue_item_t *elem;
65221167Sgnn	__hal_device_t *hldev;
66221167Sgnn
67221167Sgnn	vxge_assert(queue != NULL);
68221167Sgnn
69221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
70221167Sgnn
71221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
72221167Sgnn	    __FILE__, __func__, __LINE__);
73221167Sgnn
74221167Sgnn	vxge_hal_trace_log_queue(
75221167Sgnn	    "queue = 0x"VXGE_OS_STXFMT", size = %d, item = 0x"VXGE_OS_STXFMT,
76221167Sgnn	    (ptr_t) queue, data_max_size, (ptr_t) item);
77221167Sgnn
78221167Sgnn	if (vxge_list_is_empty(&queue->list_head)) {
79221167Sgnn		vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
80221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_QUEUE_IS_EMPTY);
81221167Sgnn		return (VXGE_QUEUE_IS_EMPTY);
82221167Sgnn	}
83221167Sgnn
84221167Sgnn	elem = (vxge_queue_item_t *) queue->list_head.next;
85221167Sgnn	if (elem->data_size > data_max_size) {
86221167Sgnn		vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
87221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_QUEUE_NOT_ENOUGH_SPACE);
88221167Sgnn		return (VXGE_QUEUE_NOT_ENOUGH_SPACE);
89221167Sgnn	}
90221167Sgnn
91221167Sgnn	vxge_list_remove(&elem->item);
92221167Sgnn	real_size = elem->data_size + sizeof(vxge_queue_item_t);
93221167Sgnn	if (queue->head_ptr == elem) {
94221167Sgnn		queue->head_ptr = (char *) queue->head_ptr + real_size;
95221167Sgnn		vxge_hal_info_log_queue("event_type: %d \
96221167Sgnn		    removing from the head: "
97221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT
98221167Sgnn		    ":0x0x"VXGE_OS_STXFMT" elem 0x0x"VXGE_OS_STXFMT" length %d",
99221167Sgnn		    elem->event_type, (ptr_t) queue->start_ptr,
100221167Sgnn		    (ptr_t) queue->head_ptr, (ptr_t) queue->tail_ptr,
101221167Sgnn		    (ptr_t) queue->end_ptr, (ptr_t) elem, real_size);
102221167Sgnn	} else if ((char *) queue->tail_ptr - real_size == (char *) elem) {
103221167Sgnn		queue->tail_ptr = (char *) queue->tail_ptr - real_size;
104221167Sgnn		vxge_hal_info_log_queue("event_type: %d \
105221167Sgnn		    removing from the tail: "
106221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT
107221167Sgnn		    ":0x"VXGE_OS_STXFMT" elem 0x"VXGE_OS_STXFMT" length %d",
108221167Sgnn		    elem->event_type, (ptr_t) queue->start_ptr,
109221167Sgnn		    (ptr_t) queue->head_ptr, (ptr_t) queue->tail_ptr,
110221167Sgnn		    (ptr_t) queue->end_ptr, (ptr_t) elem, real_size);
111221167Sgnn	} else {
112221167Sgnn		vxge_hal_info_log_queue("event_type: %d \
113221167Sgnn		    removing from the list: "
114221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT
115221167Sgnn		    ":0x"VXGE_OS_STXFMT" elem 0x"VXGE_OS_STXFMT" length %d",
116221167Sgnn		    elem->event_type, (ptr_t) queue->start_ptr,
117221167Sgnn		    (ptr_t) queue->head_ptr, (ptr_t) queue->tail_ptr,
118221167Sgnn		    (ptr_t) queue->end_ptr, (ptr_t) elem, real_size);
119221167Sgnn	}
120221167Sgnn	vxge_assert(queue->tail_ptr >= queue->head_ptr);
121221167Sgnn	vxge_assert(queue->tail_ptr >= queue->start_ptr &&
122221167Sgnn	    queue->tail_ptr <= queue->end_ptr);
123221167Sgnn	vxge_assert(queue->head_ptr >= queue->start_ptr &&
124221167Sgnn	    queue->head_ptr < queue->end_ptr);
125221167Sgnn	vxge_os_memcpy(item, elem, sizeof(vxge_queue_item_t));
126221167Sgnn	vxge_os_memcpy(vxge_queue_item_data(item), vxge_queue_item_data(elem),
127221167Sgnn	    elem->data_size);
128221167Sgnn
129221167Sgnn	if (vxge_list_is_empty(&queue->list_head)) {
130221167Sgnn		/* reset buffer pointers just to be clean */
131221167Sgnn		queue->head_ptr = queue->tail_ptr = queue->start_ptr;
132221167Sgnn	}
133221167Sgnn
134221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
135221167Sgnn	    __FILE__, __func__, __LINE__);
136221167Sgnn
137221167Sgnn	return (VXGE_QUEUE_OK);
138221167Sgnn}
139221167Sgnn
140221167Sgnn/*
141221167Sgnn * vxge_queue_produce - Enqueue an item (see vxge_queue_item_t {})
142221167Sgnn *			 into the specified queue.
143221167Sgnn * @queueh: Queue handle.
144221167Sgnn * @event_type: Event type. One of the enumerated event types
145221167Sgnn *		 that both consumer and producer "understand".
146221167Sgnn *		 For an example, please refer to vxge_hal_event_e.
147221167Sgnn * @context: Opaque (void *) "context", for instance event producer object.
148221167Sgnn * @is_critical: For critical event, e.g. ECC.
149221167Sgnn * @data_size: Size of the @data.
150221167Sgnn * @data: User data of variable @data_size that is _copied_ into
151221167Sgnn *	the new queue item (see vxge_queue_item_t {}). Upon return
152221167Sgnn *	from the call the @data memory can be re-used or released.
153221167Sgnn *
154221167Sgnn * Enqueue a new item.
155221167Sgnn *
156221167Sgnn * Returns: VXGE_QUEUE_OK - success.
157221167Sgnn * VXGE_QUEUE_IS_FULL - Queue is full.
158221167Sgnn * VXGE_QUEUE_OUT_OF_MEMORY - Memory allocation failed.
159221167Sgnn *
160221167Sgnn * See also: vxge_queue_item_t {}, vxge_queue_consume().
161221167Sgnn */
162221167Sgnnvxge_queue_status_e
163221167Sgnnvxge_queue_produce(vxge_queue_h queueh,
164221167Sgnn    u32 event_type,
165221167Sgnn    void *context,
166221167Sgnn    u32 is_critical,
167221167Sgnn    const u32 data_size,
168221167Sgnn    void *data)
169221167Sgnn{
170221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
171221167Sgnn	int real_size = data_size + sizeof(vxge_queue_item_t);
172221167Sgnn	__hal_device_t *hldev;
173221167Sgnn	vxge_queue_item_t *elem;
174221167Sgnn	unsigned long flags = 0;
175221167Sgnn
176221167Sgnn	vxge_assert(queueh != NULL);
177221167Sgnn
178221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
179221167Sgnn
180221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
181221167Sgnn	    __FILE__, __func__, __LINE__);
182221167Sgnn
183221167Sgnn	vxge_hal_trace_log_queue(
184221167Sgnn	    "queueh = 0x"VXGE_OS_STXFMT", event_type = %d, "
185221167Sgnn	    "context = 0x"VXGE_OS_STXFMT", is_critical = %d, "
186221167Sgnn	    "data_size = %d, data = 0x"VXGE_OS_STXFMT,
187221167Sgnn	    (ptr_t) queueh, event_type, (ptr_t) context,
188221167Sgnn	    is_critical, data_size, (ptr_t) data);
189221167Sgnn
190221167Sgnn	vxge_assert(real_size <= VXGE_QUEUE_BUF_SIZE);
191221167Sgnn
192221167Sgnn	vxge_os_spin_lock_irq(&queue->lock, flags);
193221167Sgnn
194221167Sgnn	if (is_critical && !queue->has_critical_event) {
195221167Sgnn		unsigned char item_buf[sizeof(vxge_queue_item_t) +
196221167Sgnn		    VXGE_DEFAULT_EVENT_MAX_DATA_SIZE];
197221167Sgnn		vxge_queue_item_t *item =
198221167Sgnn		    (vxge_queue_item_t *) (void *)item_buf;
199221167Sgnn
200221167Sgnn		while (__queue_consume(queue, VXGE_DEFAULT_EVENT_MAX_DATA_SIZE,
201221167Sgnn		    item) != VXGE_QUEUE_IS_EMPTY) {
202221167Sgnn		}		/* do nothing */
203221167Sgnn	}
204221167Sgnn
205221167Sgnntry_again:
206221167Sgnn	if ((char *) queue->tail_ptr + real_size <= (char *) queue->end_ptr) {
207221167Sgnn		elem = (vxge_queue_item_t *) queue->tail_ptr;
208221167Sgnn		queue->tail_ptr = (void *)((char *) queue->tail_ptr + real_size);
209221167Sgnn		vxge_hal_info_log_queue("event_type: %d adding to the tail: "
210221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT
211221167Sgnn		    ":0x"VXGE_OS_STXFMT" elem 0x"VXGE_OS_STXFMT" length %d",
212221167Sgnn		    event_type, (ptr_t) queue->start_ptr,
213221167Sgnn		    (ptr_t) queue->head_ptr, (ptr_t) queue->tail_ptr,
214221167Sgnn		    (ptr_t) queue->end_ptr, (ptr_t) elem, real_size);
215221167Sgnn	} else if ((char *) queue->head_ptr - real_size >=
216221167Sgnn	    (char *) queue->start_ptr) {
217221167Sgnn		elem = (vxge_queue_item_t *)
218221167Sgnn		    ((void *)((char *) queue->head_ptr - real_size));
219221167Sgnn		queue->head_ptr = elem;
220221167Sgnn		vxge_hal_info_log_queue("event_type: %d adding to the head: "
221221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT":"
222221167Sgnn		    "0x"VXGE_OS_STXFMT":0x"VXGE_OS_STXFMT" length %d",
223221167Sgnn		    event_type, (ptr_t) queue->start_ptr,
224221167Sgnn		    (ptr_t) queue->head_ptr, (ptr_t) queue->tail_ptr,
225221167Sgnn		    (ptr_t) queue->end_ptr, real_size);
226221167Sgnn	} else {
227221167Sgnn		vxge_queue_status_e status;
228221167Sgnn
229221167Sgnn		if (queue->pages_current >= queue->pages_max) {
230221167Sgnn			vxge_os_spin_unlock_irq(&queue->lock, flags);
231221167Sgnn			vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
232221167Sgnn			    __FILE__, __func__, __LINE__, VXGE_QUEUE_IS_FULL);
233221167Sgnn			return (VXGE_QUEUE_IS_FULL);
234221167Sgnn		}
235221167Sgnn
236221167Sgnn		if (queue->has_critical_event) {
237221167Sgnn			vxge_os_spin_unlock_irq(&queue->lock, flags);
238221167Sgnn			vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
239221167Sgnn			    __FILE__, __func__, __LINE__, VXGE_QUEUE_IS_FULL);
240221167Sgnn			return (VXGE_QUEUE_IS_FULL);
241221167Sgnn		}
242221167Sgnn
243221167Sgnn		/* grow */
244221167Sgnn		status = vxge_io_queue_grow(queueh);
245221167Sgnn		if (status != VXGE_QUEUE_OK) {
246221167Sgnn			vxge_os_spin_unlock_irq(&queue->lock, flags);
247221167Sgnn			vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
248221167Sgnn			    __FILE__, __func__, __LINE__, status);
249221167Sgnn			return (status);
250221167Sgnn		}
251221167Sgnn
252221167Sgnn		goto try_again;
253221167Sgnn	}
254221167Sgnn	vxge_assert(queue->tail_ptr >= queue->head_ptr);
255221167Sgnn	vxge_assert(queue->tail_ptr >= queue->start_ptr &&
256221167Sgnn	    queue->tail_ptr <= queue->end_ptr);
257221167Sgnn	vxge_assert(queue->head_ptr >= queue->start_ptr &&
258221167Sgnn	    queue->head_ptr < queue->end_ptr);
259221167Sgnn	elem->data_size = data_size;
260221167Sgnn	elem->event_type = (vxge_hal_event_e) event_type;
261221167Sgnn	elem->is_critical = is_critical;
262221167Sgnn	if (is_critical)
263221167Sgnn		queue->has_critical_event = 1;
264221167Sgnn	elem->context = context;
265221167Sgnn	vxge_os_memcpy(vxge_queue_item_data(elem), data, data_size);
266221167Sgnn	vxge_list_insert_before(&elem->item, &queue->list_head);
267221167Sgnn	vxge_os_spin_unlock_irq(&queue->lock, flags);
268221167Sgnn
269221167Sgnn	/* no lock taken! */
270221167Sgnn	queue->queued_func(queue->queued_data, event_type);
271221167Sgnn
272221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
273221167Sgnn	    __FILE__, __func__, __LINE__);
274221167Sgnn
275221167Sgnn	return (VXGE_QUEUE_OK);
276221167Sgnn}
277221167Sgnn
278221167Sgnn
279221167Sgnn/*
280221167Sgnn * vxge_queue_create - Create protected first-in-first-out queue.
281221167Sgnn * @devh: HAL device handle.
282221167Sgnn * @pages_initial: Number of pages to be initially allocated at the
283221167Sgnn * time of queue creation.
284221167Sgnn * @pages_max: Max number of pages that can be allocated in the queue.
285221167Sgnn * @queued_func: Optional callback function to be called each time a new item is
286221167Sgnn * added to the queue.
287221167Sgnn * @queued_data: Argument to the callback function.
288221167Sgnn *
289221167Sgnn * Create protected (fifo) queue.
290221167Sgnn *
291221167Sgnn * Returns: Pointer to vxge_queue_t structure,
292221167Sgnn * NULL - on failure.
293221167Sgnn *
294221167Sgnn * See also: vxge_queue_item_t {}, vxge_queue_destroy().
295221167Sgnn */
296221167Sgnnvxge_queue_h
297221167Sgnnvxge_queue_create(vxge_hal_device_h devh,
298221167Sgnn    u32 pages_initial,
299221167Sgnn    u32 pages_max,
300221167Sgnn    vxge_queued_f queued_func,
301221167Sgnn    void *queued_data)
302221167Sgnn{
303221167Sgnn	vxge_queue_t *queue;
304221167Sgnn	__hal_device_t *hldev = (__hal_device_t *) devh;
305221167Sgnn
306221167Sgnn	vxge_assert(devh != NULL);
307221167Sgnn
308221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
309221167Sgnn	    __FILE__, __func__, __LINE__);
310221167Sgnn
311221167Sgnn	vxge_hal_trace_log_queue(
312221167Sgnn	    "devh = 0x"VXGE_OS_STXFMT", pages_initial = %d, "
313221167Sgnn	    "pages_max = %d, queued_func = 0x"VXGE_OS_STXFMT", "
314221167Sgnn	    "queued_data = 0x"VXGE_OS_STXFMT, (ptr_t) devh, pages_initial,
315221167Sgnn	    pages_max, (ptr_t) queued_func, (ptr_t) queued_data);
316221167Sgnn
317221167Sgnn	if ((queue = (vxge_queue_t *) vxge_os_malloc(hldev->header.pdev,
318221167Sgnn	    sizeof(vxge_queue_t))) == NULL) {
319221167Sgnn		vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
320221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_QUEUE_OUT_OF_MEMORY);
321221167Sgnn		return (NULL);
322221167Sgnn	}
323221167Sgnn
324221167Sgnn	queue->queued_func = queued_func;
325221167Sgnn	queue->queued_data = queued_data;
326221167Sgnn	queue->hldev = devh;
327221167Sgnn	queue->pdev = hldev->header.pdev;
328221167Sgnn	queue->irqh = hldev->header.irqh;
329221167Sgnn	queue->pages_current = pages_initial;
330221167Sgnn	queue->start_ptr = vxge_os_malloc(hldev->header.pdev,
331221167Sgnn	    queue->pages_current * VXGE_QUEUE_BUF_SIZE);
332221167Sgnn	if (queue->start_ptr == NULL) {
333221167Sgnn		vxge_os_free(hldev->header.pdev, queue, sizeof(vxge_queue_t));
334221167Sgnn		vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
335221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_QUEUE_OUT_OF_MEMORY);
336221167Sgnn		return (NULL);
337221167Sgnn	}
338221167Sgnn	queue->head_ptr = queue->tail_ptr = queue->start_ptr;
339221167Sgnn	queue->end_ptr = (char *) queue->start_ptr +
340221167Sgnn	    queue->pages_current * VXGE_QUEUE_BUF_SIZE;
341221167Sgnn	vxge_os_spin_lock_init_irq(&queue->lock, queue->irqh);
342221167Sgnn	queue->pages_initial = pages_initial;
343221167Sgnn	queue->pages_max = pages_max;
344221167Sgnn	vxge_list_init(&queue->list_head);
345221167Sgnn
346221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
347221167Sgnn	    __FILE__, __func__, __LINE__);
348221167Sgnn
349221167Sgnn	return (queue);
350221167Sgnn}
351221167Sgnn
352221167Sgnn/*
353221167Sgnn * vxge_queue_destroy - Destroy vxge_queue_t object.
354221167Sgnn * @queueh: Queue handle.
355221167Sgnn *
356221167Sgnn * Destroy the specified vxge_queue_t object.
357221167Sgnn *
358221167Sgnn * See also: vxge_queue_item_t {}, vxge_queue_create().
359221167Sgnn */
360221167Sgnnvoid
361221167Sgnnvxge_queue_destroy(vxge_queue_h queueh)
362221167Sgnn{
363221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
364221167Sgnn	__hal_device_t *hldev;
365221167Sgnn
366221167Sgnn	vxge_assert(queueh != NULL);
367221167Sgnn
368221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
369221167Sgnn
370221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
371221167Sgnn	    __FILE__, __func__, __LINE__);
372221167Sgnn
373221167Sgnn	vxge_hal_trace_log_queue("queueh = 0x"VXGE_OS_STXFMT,
374221167Sgnn	    (ptr_t) queueh);
375221167Sgnn
376221167Sgnn	vxge_os_spin_lock_destroy_irq(&queue->lock, queue->irqh);
377221167Sgnn	if (!vxge_list_is_empty(&queue->list_head)) {
378221167Sgnn		vxge_hal_trace_log_queue("destroying non-empty queue 0x"
379221167Sgnn		    VXGE_OS_STXFMT, (ptr_t) queue);
380221167Sgnn	}
381221167Sgnn	vxge_os_free(queue->pdev, queue->start_ptr, queue->pages_current *
382221167Sgnn	    VXGE_QUEUE_BUF_SIZE);
383221167Sgnn
384221167Sgnn	vxge_os_free(queue->pdev, queue, sizeof(vxge_queue_t));
385221167Sgnn
386221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
387221167Sgnn	    __FILE__, __func__, __LINE__);
388221167Sgnn}
389221167Sgnn
390221167Sgnn/*
391221167Sgnn * vxge_io_queue_grow - Dynamically increases the size of the queue.
392221167Sgnn * @queueh: Queue handle.
393221167Sgnn *
394221167Sgnn * This function is called in the case of no slot avaialble in the queue
395298955Spfg * to accommodate the newly received event.
396221167Sgnn * Note that queue cannot grow beyond the max size specified for the
397221167Sgnn * queue.
398221167Sgnn *
399221167Sgnn * Returns VXGE_QUEUE_OK: On success.
400221167Sgnn * VXGE_QUEUE_OUT_OF_MEMORY : No memory is available.
401221167Sgnn */
402221167Sgnnvxge_queue_status_e
403221167Sgnnvxge_io_queue_grow(vxge_queue_h queueh)
404221167Sgnn{
405221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
406221167Sgnn	__hal_device_t *hldev;
407221167Sgnn	void *newbuf, *oldbuf;
408221167Sgnn	vxge_list_t *item;
409221167Sgnn	vxge_queue_item_t *elem;
410221167Sgnn
411221167Sgnn	vxge_assert(queueh != NULL);
412221167Sgnn
413221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
414221167Sgnn
415221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
416221167Sgnn	    __FILE__, __func__, __LINE__);
417221167Sgnn
418221167Sgnn	vxge_hal_trace_log_queue("queueh = 0x"VXGE_OS_STXFMT,
419221167Sgnn	    (ptr_t) queueh);
420221167Sgnn
421221167Sgnn	vxge_hal_info_log_queue("queue 0x"VXGE_OS_STXFMT":%d is growing",
422221167Sgnn	    (ptr_t) queue, queue->pages_current);
423221167Sgnn
424221167Sgnn	newbuf = vxge_os_malloc(queue->pdev,
425221167Sgnn	    (queue->pages_current + 1) * VXGE_QUEUE_BUF_SIZE);
426221167Sgnn	if (newbuf == NULL) {
427221167Sgnn		vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
428221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_QUEUE_OUT_OF_MEMORY);
429221167Sgnn		return (VXGE_QUEUE_OUT_OF_MEMORY);
430221167Sgnn	}
431221167Sgnn
432221167Sgnn	vxge_os_memcpy(newbuf, queue->start_ptr,
433221167Sgnn	    queue->pages_current * VXGE_QUEUE_BUF_SIZE);
434221167Sgnn	oldbuf = queue->start_ptr;
435221167Sgnn
436221167Sgnn	/* adjust queue sizes */
437221167Sgnn	queue->start_ptr = newbuf;
438221167Sgnn	queue->end_ptr = (char *) newbuf +
439221167Sgnn	    (queue->pages_current + 1) * VXGE_QUEUE_BUF_SIZE;
440221167Sgnn	queue->tail_ptr = (char *) newbuf +
441221167Sgnn	/* LINTED */
442221167Sgnn	    ((char *) queue->tail_ptr - (char *) oldbuf);
443221167Sgnn	queue->head_ptr = (char *) newbuf +
444221167Sgnn	/* LINTED */
445221167Sgnn	    ((char *) queue->head_ptr - (char *) oldbuf);
446221167Sgnn	vxge_assert(!vxge_list_is_empty(&queue->list_head));
447221167Sgnn	queue->list_head.next = (vxge_list_t *) (void *)((char *) newbuf +
448221167Sgnn	/* LINTED */
449221167Sgnn	    ((char *) queue->list_head.next - (char *) oldbuf));
450221167Sgnn	queue->list_head.prev = (vxge_list_t *) (void *)((char *) newbuf +
451221167Sgnn	/* LINTED */
452221167Sgnn	    ((char *) queue->list_head.prev - (char *) oldbuf));
453221167Sgnn	/* adjust queue list */
454221167Sgnn	vxge_list_for_each(item, &queue->list_head) {
455221167Sgnn		elem = vxge_container_of(item, vxge_queue_item_t, item);
456221167Sgnn		if (elem->item.next != &queue->list_head) {
457221167Sgnn			elem->item.next =
458221167Sgnn			    (vxge_list_t *) (void *)((char *) newbuf +
459221167Sgnn			/* LINTED */
460221167Sgnn			    ((char *) elem->item.next - (char *) oldbuf));
461221167Sgnn		}
462221167Sgnn		if (elem->item.prev != &queue->list_head) {
463221167Sgnn			elem->item.prev =
464221167Sgnn			    (vxge_list_t *) (void *)((char *) newbuf +
465221167Sgnn			/* LINTED */
466221167Sgnn			    ((char *) elem->item.prev - (char *) oldbuf));
467221167Sgnn		}
468221167Sgnn	}
469221167Sgnn	vxge_os_free(queue->pdev, oldbuf,
470221167Sgnn	    queue->pages_current * VXGE_QUEUE_BUF_SIZE);
471221167Sgnn	queue->pages_current++;
472221167Sgnn
473221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
474221167Sgnn	    __FILE__, __func__, __LINE__);
475221167Sgnn	return (VXGE_QUEUE_OK);
476221167Sgnn}
477221167Sgnn
478221167Sgnn/*
479221167Sgnn * vxge_queue_consume - Dequeue an item from the specified queue.
480221167Sgnn * @queueh: Queue handle.
481221167Sgnn * @data_max_size: Maximum expected size of the item.
482221167Sgnn * @item: Memory area into which the item is _copied_ upon return
483221167Sgnn *	from the function.
484221167Sgnn *
485221167Sgnn * Dequeue an item from the queue. The caller is required to provide
486221167Sgnn * enough space for the item.
487221167Sgnn *
488221167Sgnn * Returns: VXGE_QUEUE_OK - success.
489221167Sgnn * VXGE_QUEUE_IS_EMPTY - Queue is empty.
490221167Sgnn * VXGE_QUEUE_NOT_ENOUGH_SPACE - Requested item size(@data_max_size)
491298955Spfg * is too small to accommodate an item from the queue.
492221167Sgnn *
493221167Sgnn * See also: vxge_queue_item_t {}, vxge_queue_produce().
494221167Sgnn */
495221167Sgnnvxge_queue_status_e
496221167Sgnnvxge_queue_consume(vxge_queue_h queueh,
497221167Sgnn    u32 data_max_size,
498221167Sgnn    vxge_queue_item_t *item)
499221167Sgnn{
500221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
501221167Sgnn	__hal_device_t *hldev;
502221167Sgnn	unsigned long flags = 0;
503221167Sgnn	vxge_queue_status_e status;
504221167Sgnn
505221167Sgnn	vxge_assert(queueh != NULL);
506221167Sgnn
507221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
508221167Sgnn
509221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
510221167Sgnn	    __FILE__, __func__, __LINE__);
511221167Sgnn
512221167Sgnn	vxge_hal_trace_log_queue(
513221167Sgnn	    "queueh = 0x"VXGE_OS_STXFMT", data_max_size = %d, "
514221167Sgnn	    "item = 0x"VXGE_OS_STXFMT, (ptr_t) queueh,
515221167Sgnn	    data_max_size, (ptr_t) item);
516221167Sgnn
517221167Sgnn	vxge_os_spin_lock_irq(&queue->lock, flags);
518221167Sgnn	status = __queue_consume(queue, data_max_size, item);
519221167Sgnn	vxge_os_spin_unlock_irq(&queue->lock, flags);
520221167Sgnn
521221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = %d",
522221167Sgnn	    __FILE__, __func__, __LINE__, status);
523221167Sgnn	return (status);
524221167Sgnn}
525221167Sgnn
526221167Sgnn
527221167Sgnn/*
528221167Sgnn * vxge_queue_flush - Flush, or empty, the queue.
529221167Sgnn * @queueh: Queue handle.
530221167Sgnn *
531221167Sgnn * Flush the queue, i.e. make it empty by consuming all events
532221167Sgnn * without invoking the event processing logic (callbacks, etc.)
533221167Sgnn */
534221167Sgnnvoid
535221167Sgnnvxge_queue_flush(vxge_queue_h queueh)
536221167Sgnn{
537221167Sgnn	unsigned char item_buf[sizeof(vxge_queue_item_t) +
538221167Sgnn	    VXGE_DEFAULT_EVENT_MAX_DATA_SIZE];
539221167Sgnn	vxge_queue_item_t *item = (vxge_queue_item_t *) (void *)item_buf;
540221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
541221167Sgnn	__hal_device_t *hldev;
542221167Sgnn
543221167Sgnn	vxge_assert(queueh != NULL);
544221167Sgnn
545221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
546221167Sgnn
547221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
548221167Sgnn	    __FILE__, __func__, __LINE__);
549221167Sgnn
550221167Sgnn	vxge_hal_trace_log_queue("queueh = 0x"VXGE_OS_STXFMT,
551221167Sgnn	    (ptr_t) queueh);
552221167Sgnn
553221167Sgnn	/* flush queue by consuming all enqueued items */
554221167Sgnn	while (vxge_queue_consume(queueh, VXGE_DEFAULT_EVENT_MAX_DATA_SIZE,
555221167Sgnn	    item) != VXGE_QUEUE_IS_EMPTY) {
556221167Sgnn		/* do nothing */
557221167Sgnn		vxge_hal_trace_log_queue("item 0x"VXGE_OS_STXFMT"(%d) flushed",
558221167Sgnn		    (ptr_t) item, item->event_type);
559221167Sgnn	}
560221167Sgnn
561221167Sgnn	(void) vxge_queue_get_reset_critical(queueh);
562221167Sgnn
563221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
564221167Sgnn	    __FILE__, __func__, __LINE__);
565221167Sgnn}
566221167Sgnn
567221167Sgnn/*
568221167Sgnn * vxge_queue_get_reset_critical - Check for critical events in the queue,
569221167Sgnn * @queueh: Queue handle.
570221167Sgnn *
571221167Sgnn * Check for critical event(s) in the queue, and reset the
572221167Sgnn * "has-critical-event" flag upon return.
573221167Sgnn * Returns: 1 - if the queue contains atleast one critical event.
574221167Sgnn * 0 - If there are no critical events in the queue.
575221167Sgnn */
576221167Sgnnu32
577221167Sgnnvxge_queue_get_reset_critical(vxge_queue_h queueh)
578221167Sgnn{
579221167Sgnn	vxge_queue_t *queue = (vxge_queue_t *) queueh;
580221167Sgnn	int c = queue->has_critical_event;
581221167Sgnn	__hal_device_t *hldev;
582221167Sgnn
583221167Sgnn	vxge_assert(queueh != NULL);
584221167Sgnn
585221167Sgnn	hldev = (__hal_device_t *) queue->hldev;
586221167Sgnn
587221167Sgnn	vxge_hal_trace_log_queue("==> %s:%s:%d",
588221167Sgnn	    __FILE__, __func__, __LINE__);
589221167Sgnn
590221167Sgnn	vxge_hal_trace_log_queue("queueh = 0x"VXGE_OS_STXFMT,
591221167Sgnn	    (ptr_t) queueh);
592221167Sgnn
593221167Sgnn	queue->has_critical_event = 0;
594221167Sgnn
595221167Sgnn	vxge_hal_trace_log_queue("<== %s:%s:%d Result = 0",
596221167Sgnn	    __FILE__, __func__, __LINE__);
597221167Sgnn	return (c);
598221167Sgnn}
599