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$
27171095Ssam */
28171095Ssam
29171095Ssam#ifdef XGE_DEBUG_FP
30171095Ssam#include <dev/nxge/include/xgehal-channel.h>
31171095Ssam#endif
32171095Ssam
33171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
34173139Srwatson__hal_channel_dtr_alloc(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
35171095Ssam{
36171095Ssam	void **tmp_arr;
37173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
38173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
39173139Srwatson	unsigned long flags = 0;
40171095Ssam#endif
41173139Srwatson	if (channel->terminating) {
42173139Srwatson	    return XGE_HAL_FAIL;
43173139Srwatson	}
44171095Ssam
45173139Srwatson	if (channel->reserve_length - channel->reserve_top >
46173139Srwatson	                    channel->reserve_threshold) {
47171095Ssam
48171095Ssam_alloc_after_swap:
49173139Srwatson	    *dtrh = channel->reserve_arr[--channel->reserve_length];
50171095Ssam
51173139Srwatson	    xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated, "
52173139Srwatson	               "channel %d:%d:%d, reserve_idx %d",
53173139Srwatson	               (unsigned long long)(ulong_t)*dtrh,
54173139Srwatson	               channel->type, channel->post_qid,
55173139Srwatson	               channel->compl_qid, channel->reserve_length);
56171095Ssam
57173139Srwatson	    return XGE_HAL_OK;
58171095Ssam	}
59171095Ssam
60173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
61171095Ssam	xge_os_spin_lock_irq(&channel->free_lock, flags);
62173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
63171095Ssam	xge_os_spin_lock(&channel->free_lock);
64171095Ssam#endif
65171095Ssam
66173139Srwatson	/* switch between empty and full arrays */
67171095Ssam
68173139Srwatson	/* the idea behind such a design is that by having free and reserved
69173139Srwatson	 * arrays separated we basically separated irq and non-irq parts.
70173139Srwatson	 * i.e. no additional lock need to be done when we free a resource */
71171095Ssam
72173139Srwatson	if (channel->reserve_initial - channel->free_length >
73173139Srwatson	                channel->reserve_threshold) {
74171095Ssam
75173139Srwatson	    tmp_arr = channel->reserve_arr;
76173139Srwatson	    channel->reserve_arr = channel->free_arr;
77173139Srwatson	    channel->reserve_length = channel->reserve_initial;
78173139Srwatson	    channel->free_arr = tmp_arr;
79173139Srwatson	    channel->reserve_top = channel->free_length;
80173139Srwatson	    channel->free_length = channel->reserve_initial;
81171095Ssam
82173139Srwatson	    channel->stats.reserve_free_swaps_cnt++;
83171095Ssam
84173139Srwatson	    xge_debug_channel(XGE_TRACE,
85173139Srwatson	           "switch on channel %d:%d:%d, reserve_length %d, "
86173139Srwatson	           "free_length %d", channel->type, channel->post_qid,
87173139Srwatson	           channel->compl_qid, channel->reserve_length,
88173139Srwatson	           channel->free_length);
89171095Ssam
90173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
91173139Srwatson	    xge_os_spin_unlock_irq(&channel->free_lock, flags);
92173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
93173139Srwatson	    xge_os_spin_unlock(&channel->free_lock);
94171095Ssam#endif
95171095Ssam
96173139Srwatson	    goto _alloc_after_swap;
97171095Ssam	}
98171095Ssam
99173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
100173139Srwatson	xge_os_spin_unlock_irq(&channel->free_lock, flags);
101173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
102171095Ssam	xge_os_spin_unlock(&channel->free_lock);
103171095Ssam#endif
104171095Ssam
105171095Ssam	xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!",
106173139Srwatson	           channel->type, channel->post_qid,
107173139Srwatson	           channel->compl_qid);
108171095Ssam
109171095Ssam	channel->stats.full_cnt++;
110171095Ssam
111173139Srwatson	*dtrh = NULL;
112171095Ssam	return XGE_HAL_INF_OUT_OF_DESCRIPTORS;
113171095Ssam}
114171095Ssam
115171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
116173139Srwatson__hal_channel_dtr_restore(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
117173139Srwatson	          int offset)
118171095Ssam{
119173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
120171095Ssam
121173139Srwatson	/* restore a previously allocated dtrh at current offset and update
122173139Srwatson	 * the available reserve length accordingly. If dtrh is null just
123171095Ssam	 * update the reserve length, only */
124171095Ssam
125171095Ssam	if (dtrh) {
126173139Srwatson	    channel->reserve_arr[channel->reserve_length + offset] = dtrh;
127173139Srwatson	    xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for "
128173139Srwatson	        "channel %d:%d:%d, offset %d at reserve index %d, ",
129173139Srwatson	        (unsigned long long)(ulong_t)dtrh, channel->type,
130173139Srwatson	        channel->post_qid, channel->compl_qid, offset,
131173139Srwatson	        channel->reserve_length + offset);
132171095Ssam	}
133171095Ssam	else {
134173139Srwatson	    channel->reserve_length += offset;
135173139Srwatson	    xge_debug_channel(XGE_TRACE, "channel %d:%d:%d, restored "
136173139Srwatson	        "for offset %d, new reserve_length %d, free length %d",
137173139Srwatson	        channel->type, channel->post_qid, channel->compl_qid,
138173139Srwatson	        offset, channel->reserve_length, channel->free_length);
139171095Ssam	}
140171095Ssam}
141171095Ssam
142171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
143171095Ssam__hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
144171095Ssam{
145173139Srwatson	xge_hal_channel_t *channel    = (xge_hal_channel_t*)channelh;
146171095Ssam
147171095Ssam	xge_assert(channel->work_arr[channel->post_index] == NULL);
148171095Ssam
149171095Ssam	channel->work_arr[channel->post_index++] = dtrh;
150171095Ssam
151173139Srwatson	    /* wrap-around */
152173139Srwatson	if (channel->post_index == channel->length)
153173139Srwatson	    channel->post_index = 0;
154171095Ssam}
155171095Ssam
156171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
157171095Ssam__hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
158171095Ssam{
159173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
160171095Ssam
161171095Ssam	xge_assert(channel->work_arr);
162173139Srwatson	xge_assert(channel->compl_index < channel->length);
163171095Ssam
164173139Srwatson	*dtrh = channel->work_arr[channel->compl_index];
165171095Ssam}
166171095Ssam
167171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
168171095Ssam__hal_channel_dtr_complete(xge_hal_channel_h channelh)
169171095Ssam{
170173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
171171095Ssam
172173139Srwatson	channel->work_arr[channel->compl_index] = NULL;
173171095Ssam
174171095Ssam	/* wrap-around */
175171095Ssam	if (++channel->compl_index == channel->length)
176173139Srwatson	    channel->compl_index = 0;
177171095Ssam
178171095Ssam	channel->stats.total_compl_cnt++;
179171095Ssam}
180171095Ssam
181171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
182171095Ssam__hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
183171095Ssam{
184173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
185171095Ssam
186173139Srwatson	channel->free_arr[--channel->free_length] = dtrh;
187171095Ssam
188173139Srwatson	xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed, "
189173139Srwatson	           "channel %d:%d:%d, new free_length %d",
190173139Srwatson	           (unsigned long long)(ulong_t)dtrh,
191173139Srwatson	           channel->type, channel->post_qid,
192173139Srwatson	           channel->compl_qid, channel->free_length);
193171095Ssam}
194171095Ssam
195171095Ssam/**
196171095Ssam * xge_hal_channel_dtr_count
197171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open().
198171095Ssam *
199171095Ssam * Retreive number of DTRs available. This function can not be called
200171095Ssam * from data path.
201171095Ssam */
202171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
203171095Ssamxge_hal_channel_dtr_count(xge_hal_channel_h channelh)
204171095Ssam{
205171095Ssam	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
206171095Ssam
207171095Ssam	return ((channel->reserve_length - channel->reserve_top) +
208173139Srwatson	    (channel->reserve_initial - channel->free_length) -
209173139Srwatson	                    channel->reserve_threshold);
210171095Ssam}
211171095Ssam
212171095Ssam/**
213173139Srwatson * xge_hal_channel_userdata - Get user-specified channel context.
214171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open().
215171095Ssam *
216173139Srwatson * Returns: per-channel "user data", which can be any ULD-defined context.
217173139Srwatson * The %userdata "gets" into the channel at open time
218173139Srwatson * (see xge_hal_channel_open()).
219171095Ssam *
220171095Ssam * See also: xge_hal_channel_open().
221171095Ssam */
222171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void*
223171095Ssamxge_hal_channel_userdata(xge_hal_channel_h channelh)
224171095Ssam{
225173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
226171095Ssam
227171095Ssam	return channel->userdata;
228171095Ssam}
229171095Ssam
230171095Ssam/**
231173139Srwatson * xge_hal_channel_id - Get channel ID.
232171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open().
233171095Ssam *
234173139Srwatson * Returns: channel ID. For link layer channel id is the number
235173139Srwatson * in the range from 0 to 7 that identifies hardware ring or fifo,
236173139Srwatson * depending on the channel type.
237171095Ssam */
238171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
239171095Ssamxge_hal_channel_id(xge_hal_channel_h channelh)
240171095Ssam{
241173139Srwatson	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
242171095Ssam
243171095Ssam	return channel->post_qid;
244171095Ssam}
245171095Ssam
246171095Ssam/**
247173139Srwatson * xge_hal_check_alignment - Check buffer alignment and calculate the
248173139Srwatson * "misaligned" portion.
249173139Srwatson * @dma_pointer: DMA address of the buffer.
250171095Ssam * @size: Buffer size, in bytes.
251173139Srwatson * @alignment: Alignment "granularity" (see below), in bytes.
252173139Srwatson * @copy_size: Maximum number of bytes to "extract" from the buffer
253173139Srwatson * (in order to spost it as a separate scatter-gather entry). See below.
254171095Ssam *
255173139Srwatson * Check buffer alignment and calculate "misaligned" portion, if exists.
256173139Srwatson * The buffer is considered aligned if its address is multiple of
257173139Srwatson * the specified @alignment. If this is the case,
258171095Ssam * xge_hal_check_alignment() returns zero.
259173139Srwatson * Otherwise, xge_hal_check_alignment() uses the last argument,
260171095Ssam * @copy_size,
261173139Srwatson * to calculate the size to "extract" from the buffer. The @copy_size
262173139Srwatson * may or may not be equal @alignment. The difference between these two
263173139Srwatson * arguments is that the @alignment is used to make the decision: aligned
264173139Srwatson * or not aligned. While the @copy_size is used to calculate the portion
265173139Srwatson * of the buffer to "extract", i.e. to post as a separate entry in the
266173139Srwatson * transmit descriptor. For example, the combination
267173139Srwatson * @alignment=8 and @copy_size=64 will work okay on AMD Opteron boxes.
268171095Ssam *
269173139Srwatson * Note: @copy_size should be a multiple of @alignment. In many practical
270173139Srwatson * cases @copy_size and @alignment will probably be equal.
271171095Ssam *
272171095Ssam * See also: xge_hal_fifo_dtr_buffer_set_aligned().
273171095Ssam */
274171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
275173139Srwatsonxge_hal_check_alignment(dma_addr_t dma_pointer, int size, int alignment,
276173139Srwatson	    int copy_size)
277171095Ssam{
278173139Srwatson	int misaligned_size;
279171095Ssam
280173139Srwatson	misaligned_size = (int)(dma_pointer & (alignment - 1));
281171095Ssam	if (!misaligned_size) {
282173139Srwatson	    return 0;
283171095Ssam	}
284171095Ssam
285171095Ssam	if (size > copy_size) {
286173139Srwatson	    misaligned_size = (int)(dma_pointer & (copy_size - 1));
287173139Srwatson	    misaligned_size = copy_size - misaligned_size;
288171095Ssam	} else {
289173139Srwatson	    misaligned_size = size;
290171095Ssam	}
291171095Ssam
292171095Ssam	return misaligned_size;
293171095Ssam}
294171095Ssam
295