1171095Ssam/*-
2171095Ssam * Copyright (c) 2002-2007 Neterion, Inc.
3171095Ssam * All rights reserved.
4171095Ssam *
5171095Ssam * Redistribution and use in source and binary forms, with or without
6171095Ssam * modification, are permitted provided that the following conditions
7171095Ssam * are met:
8171095Ssam * 1. Redistributions of source code must retain the above copyright
9171095Ssam *    notice, this list of conditions and the following disclaimer.
10171095Ssam * 2. Redistributions in binary form must reproduce the above copyright
11171095Ssam *    notice, this list of conditions and the following disclaimer in the
12171095Ssam *    documentation and/or other materials provided with the distribution.
13171095Ssam *
14171095Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15171095Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16171095Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17171095Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18171095Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19171095Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20171095Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21171095Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22171095Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23171095Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24171095Ssam * SUCH DAMAGE.
25171095Ssam *
26171095Ssam * $FreeBSD: releng/11.0/sys/dev/nxge/xgehal/xgehal-channel.c 173139 2007-10-29 14:19:32Z rwatson $
27171095Ssam */
28171095Ssam
29171095Ssam#include <dev/nxge/include/xgehal-channel.h>
30171095Ssam#include <dev/nxge/include/xgehal-fifo.h>
31171095Ssam#include <dev/nxge/include/xgehal-ring.h>
32171095Ssam#include <dev/nxge/include/xgehal-device.h>
33171095Ssam#include <dev/nxge/include/xgehal-regs.h>
34171095Ssam
35171095Ssam/*
36171095Ssam * __hal_channel_dtr_next_reservelist
37171095Ssam *
38171095Ssam * Walking through the all available DTRs.
39171095Ssam */
40171095Ssamstatic xge_hal_status_e
41171095Ssam__hal_channel_dtr_next_reservelist(xge_hal_channel_h channelh,
42173139Srwatson	    xge_hal_dtr_h *dtrh)
43171095Ssam{
44171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
45171095Ssam
46171095Ssam	if (channel->reserve_top >= channel->reserve_length) {
47173139Srwatson	    return XGE_HAL_INF_NO_MORE_FREED_DESCRIPTORS;
48171095Ssam	}
49171095Ssam
50171095Ssam	*dtrh = channel->reserve_arr[channel->reserve_top++];
51171095Ssam
52171095Ssam	return XGE_HAL_OK;
53171095Ssam}
54171095Ssam
55171095Ssam/*
56171095Ssam * __hal_channel_dtr_next_freelist
57171095Ssam *
58171095Ssam * Walking through the "freed" DTRs.
59171095Ssam */
60171095Ssamstatic xge_hal_status_e
61171095Ssam__hal_channel_dtr_next_freelist(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
62171095Ssam{
63171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
64171095Ssam
65171095Ssam	if (channel->reserve_initial == channel->free_length) {
66173139Srwatson	    return XGE_HAL_INF_NO_MORE_FREED_DESCRIPTORS;
67171095Ssam	}
68171095Ssam
69171095Ssam	*dtrh = channel->free_arr[channel->free_length++];
70171095Ssam
71171095Ssam	return XGE_HAL_OK;
72171095Ssam}
73171095Ssam
74171095Ssam/*
75171095Ssam * __hal_channel_dtr_next_not_completed - Get the _next_ posted but
76171095Ssam *                                     not completed descriptor.
77171095Ssam *
78171095Ssam * Walking through the "not completed" DTRs.
79171095Ssam */
80171095Ssamstatic xge_hal_status_e
81171095Ssam__hal_channel_dtr_next_not_completed(xge_hal_channel_h channelh,
82173139Srwatson	    xge_hal_dtr_h *dtrh)
83171095Ssam{
84171095Ssam	xge_hal_ring_rxd_1_t *rxdp; /* doesn't matter 1, 3 or 5... */
85171095Ssam	__hal_channel_dtr_try_complete(channelh, dtrh);
86171095Ssam	if (*dtrh == NULL) {
87173139Srwatson	    return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
88171095Ssam	}
89171095Ssam
90171095Ssam	rxdp = (xge_hal_ring_rxd_1_t *)*dtrh;
91171095Ssam	xge_assert(rxdp->host_control!=0);
92171095Ssam
93171095Ssam	__hal_channel_dtr_complete(channelh);
94171095Ssam
95171095Ssam	return XGE_HAL_OK;
96171095Ssam}
97171095Ssam
98171095Ssamxge_hal_channel_t*
99171095Ssam__hal_channel_allocate(xge_hal_device_h devh, int post_qid,
100173139Srwatson	    xge_hal_channel_type_e type)
101171095Ssam{
102171095Ssam	xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
103171095Ssam	xge_hal_channel_t *channel;
104171095Ssam	int size = 0;
105171095Ssam
106171095Ssam	switch(type) {
107173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_FIFO:
108173139Srwatson	        xge_assert(post_qid + 1 >= XGE_HAL_MIN_FIFO_NUM &&
109173139Srwatson	             post_qid + 1 <= XGE_HAL_MAX_FIFO_NUM);
110173139Srwatson	        size = sizeof(xge_hal_fifo_t);
111173139Srwatson	        break;
112173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_RING:
113173139Srwatson	        xge_assert(post_qid + 1 >= XGE_HAL_MIN_RING_NUM &&
114173139Srwatson	            post_qid + 1 <= XGE_HAL_MAX_RING_NUM);
115173139Srwatson	        size = sizeof(xge_hal_ring_t);
116173139Srwatson	        break;
117173139Srwatson	    default :
118173139Srwatson	        xge_assert(size);
119173139Srwatson	        break;
120171095Ssam
121171095Ssam	}
122171095Ssam
123171095Ssam
124171095Ssam	/* allocate FIFO channel */
125171095Ssam	channel = (xge_hal_channel_t *) xge_os_malloc(hldev->pdev, size);
126171095Ssam	if (channel == NULL) {
127173139Srwatson	    return NULL;
128171095Ssam	}
129171095Ssam	xge_os_memzero(channel, size);
130171095Ssam
131173139Srwatson	channel->pdev       = hldev->pdev;
132173139Srwatson	channel->regh0      = hldev->regh0;
133173139Srwatson	channel->regh1      = hldev->regh1;
134173139Srwatson	channel->type       = type;
135173139Srwatson	channel->devh       = devh;
136173139Srwatson	channel->post_qid   = post_qid;
137173139Srwatson	channel->compl_qid  = 0;
138171095Ssam
139171095Ssam	return channel;
140171095Ssam}
141171095Ssam
142171095Ssamvoid __hal_channel_free(xge_hal_channel_t *channel)
143171095Ssam{
144171095Ssam	int size = 0;
145171095Ssam
146171095Ssam	xge_assert(channel->pdev);
147171095Ssam
148171095Ssam	switch(channel->type) {
149173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_FIFO:
150173139Srwatson	        size = sizeof(xge_hal_fifo_t);
151173139Srwatson	        break;
152173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_RING:
153173139Srwatson	        size = sizeof(xge_hal_ring_t);
154173139Srwatson	        break;
155173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
156173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
157173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
158173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
159173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
160173139Srwatson	        xge_assert(size);
161173139Srwatson	        break;
162173139Srwatson	    default:
163173139Srwatson	        break;
164171095Ssam	}
165171095Ssam
166171095Ssam	xge_os_free(channel->pdev, channel, size);
167171095Ssam}
168171095Ssam
169171095Ssamxge_hal_status_e
170171095Ssam__hal_channel_initialize (xge_hal_channel_h channelh,
171173139Srwatson	    xge_hal_channel_attr_t *attr, void **reserve_arr,
172173139Srwatson	    int reserve_initial, int reserve_max, int reserve_threshold)
173171095Ssam{
174171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
175171095Ssam	xge_hal_device_t *hldev;
176171095Ssam
177171095Ssam	hldev = (xge_hal_device_t *)channel->devh;
178171095Ssam
179171095Ssam	channel->dtr_term = attr->dtr_term;
180171095Ssam	channel->dtr_init = attr->dtr_init;
181171095Ssam	channel->callback = attr->callback;
182171095Ssam	channel->userdata = attr->userdata;
183171095Ssam	channel->flags = attr->flags;
184171095Ssam	channel->per_dtr_space = attr->per_dtr_space;
185171095Ssam
186171095Ssam	channel->reserve_arr = reserve_arr;
187171095Ssam	channel->reserve_initial = reserve_initial;
188171095Ssam	channel->reserve_max = reserve_max;
189171095Ssam	channel->reserve_length = channel->reserve_initial;
190171095Ssam	channel->reserve_threshold = reserve_threshold;
191171095Ssam	channel->reserve_top = 0;
192171095Ssam	channel->saved_arr = (void **) xge_os_malloc(hldev->pdev,
193173139Srwatson	                   sizeof(void*)*channel->reserve_max);
194171095Ssam	if (channel->saved_arr == NULL) {
195173139Srwatson	    return XGE_HAL_ERR_OUT_OF_MEMORY;
196171095Ssam	}
197171095Ssam	xge_os_memzero(channel->saved_arr, sizeof(void*)*channel->reserve_max);
198171095Ssam	channel->free_arr = channel->saved_arr;
199171095Ssam	channel->free_length = channel->reserve_initial;
200171095Ssam	channel->work_arr = (void **) xge_os_malloc(hldev->pdev,
201173139Srwatson	              sizeof(void*)*channel->reserve_max);
202171095Ssam	if (channel->work_arr == NULL) {
203173139Srwatson	    return XGE_HAL_ERR_OUT_OF_MEMORY;
204171095Ssam	}
205171095Ssam	xge_os_memzero(channel->work_arr,
206173139Srwatson	                   sizeof(void*)*channel->reserve_max);
207171095Ssam	channel->post_index = 0;
208171095Ssam	channel->compl_index = 0;
209171095Ssam	channel->length = channel->reserve_initial;
210171095Ssam
211171095Ssam	channel->orig_arr = (void **) xge_os_malloc(hldev->pdev,
212173139Srwatson	                    sizeof(void*)*channel->reserve_max);
213171095Ssam	if (channel->orig_arr == NULL)
214173139Srwatson	    return XGE_HAL_ERR_OUT_OF_MEMORY;
215171095Ssam
216171095Ssam	xge_os_memzero(channel->orig_arr, sizeof(void*)*channel->reserve_max);
217171095Ssam
218171095Ssam#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
219171095Ssam	xge_os_spin_lock_init_irq(&channel->free_lock, hldev->irqh);
220171095Ssam#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
221171095Ssam	xge_os_spin_lock_init(&channel->free_lock, hldev->pdev);
222171095Ssam#endif
223171095Ssam
224171095Ssam	return XGE_HAL_OK;
225171095Ssam}
226171095Ssam
227171095Ssamvoid __hal_channel_terminate(xge_hal_channel_h channelh)
228171095Ssam{
229171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
230171095Ssam	xge_hal_device_t *hldev;
231171095Ssam
232171095Ssam	hldev = (xge_hal_device_t *)channel->devh;
233171095Ssam
234171095Ssam	xge_assert(channel->pdev);
235171095Ssam	/* undo changes made at channel_initialize() */
236171095Ssam	if (channel->work_arr) {
237173139Srwatson	    xge_os_free(channel->pdev, channel->work_arr,
238173139Srwatson	              sizeof(void*)*channel->reserve_max);
239173139Srwatson	    channel->work_arr = NULL;
240171095Ssam	}
241171095Ssam
242171095Ssam	if (channel->saved_arr) {
243173139Srwatson	    xge_os_free(channel->pdev, channel->saved_arr,
244173139Srwatson	              sizeof(void*)*channel->reserve_max);
245173139Srwatson	    channel->saved_arr = NULL;
246171095Ssam	}
247171095Ssam
248171095Ssam	if (channel->orig_arr) {
249173139Srwatson	    xge_os_free(channel->pdev, channel->orig_arr,
250173139Srwatson	              sizeof(void*)*channel->reserve_max);
251173139Srwatson	    channel->orig_arr = NULL;
252171095Ssam	}
253171095Ssam
254171095Ssam#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
255171095Ssam	xge_os_spin_lock_destroy_irq(&channel->free_lock, hldev->irqh);
256171095Ssam#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
257171095Ssam	xge_os_spin_lock_destroy(&channel->free_lock, hldev->pdev);
258171095Ssam#endif
259171095Ssam}
260171095Ssam
261171095Ssam/**
262171095Ssam * xge_hal_channel_open - Open communication channel.
263171095Ssam * @devh: HAL device, pointer to xge_hal_device_t structure.
264171095Ssam * @attr: Contains attributes required to open
265171095Ssam *        the channel.
266171095Ssam * @channelh:  The channel handle. On success (XGE_HAL_OK) HAL fills
267171095Ssam * this "out" parameter with a valid channel handle.
268171095Ssam * @reopen: See  xge_hal_channel_reopen_e{}.
269171095Ssam *
270171095Ssam * Open communication channel with the device.
271171095Ssam *
272171095Ssam * HAL uses (persistent) channel configuration to allocate both channel
273171095Ssam * and Xframe Tx and Rx descriptors.
274171095Ssam * Notes:
275171095Ssam *     1) The channel config data is fed into HAL prior to
276171095Ssam *        xge_hal_channel_open().
277171095Ssam *
278171095Ssam *     2) The corresponding hardware queues must be already configured and
279171095Ssam *        enabled.
280171095Ssam *
281171095Ssam *     3) Either down or up queue may be omitted, in which case the channel
282171095Ssam *        is treated as _unidirectional_.
283171095Ssam *
284171095Ssam *     4) Post and completion queue may be the same, in which case the channel
285171095Ssam *        is said to have "in-band completions".
286171095Ssam *
287171095Ssam * Note that free_channels list is not protected. i.e. caller must provide
288171095Ssam * safe context.
289171095Ssam *
290171095Ssam * Returns: XGE_HAL_OK  - success.
291171095Ssam * XGE_HAL_ERR_CHANNEL_NOT_FOUND - Unable to locate the channel.
292171095Ssam * XGE_HAL_ERR_OUT_OF_MEMORY - Memory allocation failed.
293171095Ssam *
294171095Ssam * See also: xge_hal_channel_attr_t{}.
295171095Ssam * Usage: See ex_open{}.
296171095Ssam */
297171095Ssamxge_hal_status_e
298171095Ssamxge_hal_channel_open(xge_hal_device_h devh,
299173139Srwatson	         xge_hal_channel_attr_t *attr,
300173139Srwatson	         xge_hal_channel_h *channelh,
301173139Srwatson	         xge_hal_channel_reopen_e reopen)
302171095Ssam{
303171095Ssam	xge_list_t *item;
304171095Ssam	int i;
305171095Ssam	xge_hal_status_e status = XGE_HAL_OK;
306171095Ssam	xge_hal_channel_t *channel = NULL;
307171095Ssam	xge_hal_device_t *device = (xge_hal_device_t *)devh;
308171095Ssam
309171095Ssam	xge_assert(device);
310171095Ssam	xge_assert(attr);
311171095Ssam
312171095Ssam	*channelh = NULL;
313171095Ssam
314171095Ssam	/* find channel */
315173139Srwatson	xge_list_for_each(item, &device->free_channels) {
316173139Srwatson	    xge_hal_channel_t *tmp;
317171095Ssam
318173139Srwatson	    tmp = xge_container_of(item, xge_hal_channel_t, item);
319173139Srwatson	    if (tmp->type == attr->type &&
320173139Srwatson	    tmp->post_qid == attr->post_qid &&
321173139Srwatson	    tmp->compl_qid == attr->compl_qid) {
322173139Srwatson	        channel = tmp;
323173139Srwatson	        break;
324173139Srwatson	    }
325173139Srwatson	}
326171095Ssam
327173139Srwatson	if (channel == NULL) {
328173139Srwatson	    return XGE_HAL_ERR_CHANNEL_NOT_FOUND;
329171095Ssam	}
330171095Ssam
331171095Ssam	xge_assert((channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) ||
332173139Srwatson	    (channel->type == XGE_HAL_CHANNEL_TYPE_RING));
333171095Ssam
334171095Ssam	if (reopen == XGE_HAL_CHANNEL_OC_NORMAL) {
335173139Srwatson	    /* allocate memory, initialize pointers, etc */
336173139Srwatson	    switch(channel->type) {
337173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_FIFO:
338173139Srwatson	            status = __hal_fifo_open(channel, attr);
339173139Srwatson	            break;
340173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_RING:
341173139Srwatson	            status = __hal_ring_open(channel, attr);
342173139Srwatson	            break;
343173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
344173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
345173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
346173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
347173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
348173139Srwatson	            status = XGE_HAL_FAIL;
349173139Srwatson	            break;
350173139Srwatson	        default:
351173139Srwatson	            break;
352173139Srwatson	    }
353171095Ssam
354173139Srwatson	    if (status == XGE_HAL_OK) {
355173139Srwatson	        for (i = 0; i < channel->reserve_initial; i++) {
356173139Srwatson	            channel->orig_arr[i] =
357173139Srwatson	                channel->reserve_arr[i];
358173139Srwatson	        }
359173139Srwatson	    }
360173139Srwatson	    else
361173139Srwatson	        return status;
362171095Ssam	} else {
363171095Ssam	        xge_assert(reopen == XGE_HAL_CHANNEL_RESET_ONLY);
364171095Ssam
365173139Srwatson	    for (i = 0; i < channel->reserve_initial; i++) {
366173139Srwatson	        channel->reserve_arr[i] = channel->orig_arr[i];
367173139Srwatson	        channel->free_arr[i] = NULL;
368173139Srwatson	    }
369173139Srwatson	    channel->free_length = channel->reserve_initial;
370173139Srwatson	    channel->reserve_length = channel->reserve_initial;
371173139Srwatson	    channel->reserve_top = 0;
372173139Srwatson	    channel->post_index = 0;
373173139Srwatson	    channel->compl_index = 0;
374173139Srwatson	            if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
375173139Srwatson	        status = __hal_ring_initial_replenish(channel,
376173139Srwatson	                              reopen);
377173139Srwatson	                    if (status != XGE_HAL_OK)
378173139Srwatson	                            return status;
379173139Srwatson	    }
380171095Ssam	}
381171095Ssam
382171095Ssam	/* move channel to the open state list */
383171095Ssam
384171095Ssam	switch(channel->type) {
385173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_FIFO:
386173139Srwatson	        xge_list_remove(&channel->item);
387173139Srwatson	        xge_list_insert(&channel->item, &device->fifo_channels);
388173139Srwatson	        break;
389173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_RING:
390173139Srwatson	        xge_list_remove(&channel->item);
391173139Srwatson	        xge_list_insert(&channel->item, &device->ring_channels);
392173139Srwatson	        break;
393173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
394173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
395173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
396173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
397173139Srwatson	    case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
398173139Srwatson	        xge_assert(channel->type == XGE_HAL_CHANNEL_TYPE_FIFO ||
399173139Srwatson	               channel->type == XGE_HAL_CHANNEL_TYPE_RING);
400173139Srwatson	        break;
401173139Srwatson	    default:
402173139Srwatson	        break;
403171095Ssam	}
404171095Ssam	channel->is_open = 1;
405173139Srwatson	channel->terminating = 0;
406171095Ssam	/*
407171095Ssam	 * The magic check the argument validity, has to be
408171095Ssam	 * removed before 03/01/2005.
409171095Ssam	 */
410171095Ssam	channel->magic = XGE_HAL_MAGIC;
411171095Ssam
412171095Ssam	*channelh = channel;
413171095Ssam
414171095Ssam	return XGE_HAL_OK;
415171095Ssam}
416171095Ssam
417171095Ssam/**
418171095Ssam * xge_hal_channel_abort - Abort the channel.
419171095Ssam * @channelh: Channel handle.
420171095Ssam * @reopen: See  xge_hal_channel_reopen_e{}.
421171095Ssam *
422171095Ssam * Terminate (via xge_hal_channel_dtr_term_f{}) all channel descriptors.
423171095Ssam * Currently used internally only by HAL, as part of its
424171095Ssam * xge_hal_channel_close() and xge_hal_channel_open() in case
425171095Ssam * of fatal error.
426171095Ssam *
427171095Ssam * See also: xge_hal_channel_dtr_term_f{}.
428171095Ssam */
429171095Ssamvoid xge_hal_channel_abort(xge_hal_channel_h channelh,
430173139Srwatson	                       xge_hal_channel_reopen_e reopen)
431171095Ssam{
432171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
433171095Ssam	xge_hal_dtr_h dtr;
434171095Ssam#ifdef XGE_OS_MEMORY_CHECK
435171095Ssam	int check_cnt = 0;
436171095Ssam#endif
437171095Ssam	int free_length_sav;
438171095Ssam	int reserve_top_sav;
439171095Ssam
440171095Ssam	if (channel->dtr_term == NULL) {
441173139Srwatson	    return;
442171095Ssam	}
443171095Ssam
444171095Ssam	free_length_sav = channel->free_length;
445171095Ssam	while (__hal_channel_dtr_next_freelist(channelh, &dtr) == XGE_HAL_OK) {
446171095Ssam#ifdef XGE_OS_MEMORY_CHECK
447171095Ssam#ifdef XGE_DEBUG_ASSERT
448173139Srwatson	    if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
449173139Srwatson	        xge_assert(!__hal_fifo_txdl_priv(dtr)->allocated);
450173139Srwatson	    } else {
451173139Srwatson	        if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
452173139Srwatson	            xge_assert(!__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)->allocated);
453173139Srwatson	        }
454173139Srwatson	    }
455171095Ssam#endif
456173139Srwatson	    check_cnt++;
457171095Ssam#endif
458173139Srwatson	    channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_FREED,
459173139Srwatson	              channel->userdata, reopen);
460171095Ssam	}
461171095Ssam	channel->free_length = free_length_sav;
462171095Ssam
463171095Ssam	while (__hal_channel_dtr_next_not_completed(channelh, &dtr) ==
464171095Ssam	       XGE_HAL_OK) {
465171095Ssam#ifdef XGE_OS_MEMORY_CHECK
466171095Ssam#ifdef XGE_DEBUG_ASSERT
467173139Srwatson	    if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
468173139Srwatson	        xge_assert(__hal_fifo_txdl_priv(dtr)->allocated);
469173139Srwatson	    } else {
470173139Srwatson	        if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
471173139Srwatson	        xge_assert(__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)
472173139Srwatson	               ->allocated);
473173139Srwatson	        }
474173139Srwatson	    }
475171095Ssam#endif
476173139Srwatson	    check_cnt++;
477171095Ssam#endif
478173139Srwatson	    channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_POSTED,
479173139Srwatson	              channel->userdata, reopen);
480171095Ssam
481171095Ssam	}
482171095Ssam
483171095Ssam	reserve_top_sav = channel->reserve_top;
484171095Ssam	while (__hal_channel_dtr_next_reservelist(channelh, &dtr) ==
485173139Srwatson	                        XGE_HAL_OK) {
486171095Ssam#ifdef XGE_OS_MEMORY_CHECK
487171095Ssam#ifdef XGE_DEBUG_ASSERT
488173139Srwatson	    if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
489173139Srwatson	        xge_assert(!__hal_fifo_txdl_priv(dtr)->allocated);
490173139Srwatson	    } else {
491173139Srwatson	        if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
492173139Srwatson	        xge_assert(!__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)->allocated);
493173139Srwatson	        }
494173139Srwatson	    }
495171095Ssam#endif
496173139Srwatson	    check_cnt++;
497171095Ssam#endif
498173139Srwatson	    channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_AVAIL,
499173139Srwatson	              channel->userdata, reopen);
500171095Ssam	}
501171095Ssam	channel->reserve_top = reserve_top_sav;
502171095Ssam
503171095Ssam	xge_assert(channel->reserve_length ==
504173139Srwatson	            (channel->free_length + channel->reserve_top));
505171095Ssam
506171095Ssam#ifdef XGE_OS_MEMORY_CHECK
507171095Ssam	xge_assert(check_cnt == channel->reserve_initial);
508171095Ssam#endif
509171095Ssam
510171095Ssam}
511171095Ssam
512171095Ssam/**
513171095Ssam * xge_hal_channel_close - Close communication channel.
514171095Ssam * @channelh: The channel handle.
515171095Ssam * @reopen: See  xge_hal_channel_reopen_e{}.
516171095Ssam *
517171095Ssam * Will close previously opened channel and deallocate associated resources.
518171095Ssam * Channel must be opened otherwise assert will be generated.
519171095Ssam * Note that free_channels list is not protected. i.e. caller must provide
520171095Ssam * safe context.
521171095Ssam */
522171095Ssamvoid xge_hal_channel_close(xge_hal_channel_h channelh,
523173139Srwatson	                       xge_hal_channel_reopen_e reopen)
524171095Ssam{
525171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
526171095Ssam	xge_hal_device_t *hldev;
527171095Ssam	xge_list_t *item;
528171095Ssam	xge_assert(channel);
529171095Ssam	xge_assert(channel->type < XGE_HAL_CHANNEL_TYPE_MAX);
530171095Ssam
531171095Ssam	hldev = (xge_hal_device_t *)channel->devh;
532171095Ssam	channel->is_open = 0;
533171095Ssam	channel->magic = XGE_HAL_DEAD;
534171095Ssam
535173139Srwatson	/* sanity check: make sure channel is not in free list */
536173139Srwatson	xge_list_for_each(item, &hldev->free_channels) {
537173139Srwatson	    xge_hal_channel_t *tmp;
538171095Ssam
539173139Srwatson	    tmp = xge_container_of(item, xge_hal_channel_t, item);
540173139Srwatson	    xge_assert(!tmp->is_open);
541173139Srwatson	    if (channel == tmp) {
542173139Srwatson	        return;
543173139Srwatson	    }
544171095Ssam	}
545171095Ssam
546171095Ssam	xge_hal_channel_abort(channel, reopen);
547171095Ssam
548171095Ssam	xge_assert((channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) ||
549173139Srwatson	       (channel->type == XGE_HAL_CHANNEL_TYPE_RING));
550171095Ssam
551171095Ssam	if (reopen == XGE_HAL_CHANNEL_OC_NORMAL) {
552173139Srwatson	    /* de-allocate */
553173139Srwatson	    switch(channel->type) {
554173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_FIFO:
555173139Srwatson	            __hal_fifo_close(channelh);
556173139Srwatson	            break;
557173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_RING:
558173139Srwatson	            __hal_ring_close(channelh);
559173139Srwatson	            break;
560173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
561173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
562173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
563173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
564173139Srwatson	        case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
565173139Srwatson	            xge_assert(channel->type == XGE_HAL_CHANNEL_TYPE_FIFO ||
566173139Srwatson	                   channel->type == XGE_HAL_CHANNEL_TYPE_RING);
567173139Srwatson	            break;
568173139Srwatson	        default:
569173139Srwatson	            break;
570173139Srwatson	    }
571171095Ssam	}
572171095Ssam	else
573171095Ssam	        xge_assert(reopen == XGE_HAL_CHANNEL_RESET_ONLY);
574171095Ssam
575171095Ssam	/* move channel back to free state list */
576171095Ssam	xge_list_remove(&channel->item);
577173139Srwatson	xge_list_insert(&channel->item, &hldev->free_channels);
578171095Ssam
579173139Srwatson	if (xge_list_is_empty(&hldev->fifo_channels) &&
580173139Srwatson	    xge_list_is_empty(&hldev->ring_channels)) {
581173139Srwatson	    /* clear msix_idx in case of following HW reset */
582173139Srwatson	    hldev->reset_needed_after_close = 1;
583171095Ssam	}
584171095Ssam}
585