xref: /freebsd-11-stable/sys/dev/vxge/vxgehal/vxgehal-fifo.c (revision 4ab2e064d7950be84256d671a7ae93f87cc6aa36)
1 /*-
2  * Copyright(c) 2002-2011 Exar Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification are permitted provided the following conditions are met:
7  *
8  *    1. Redistributions of source code must retain the above copyright notice,
9  *       this list of conditions and the following disclaimer.
10  *
11  *    2. Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in the
13  *       documentation and/or other materials provided with the distribution.
14  *
15  *    3. Neither the name of the Exar Corporation nor the names of its
16  *       contributors may be used to endorse or promote products derived from
17  *       this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*$FreeBSD$*/
32 
33 #include <dev/vxge/vxgehal/vxgehal.h>
34 
35 /*
36  * __hal_fifo_mempool_item_alloc - Allocate List blocks for TxD list callback
37  * @mempoolh: Handle to memory pool
38  * @memblock: Address of this memory block
39  * @memblock_index: Index of this memory block
40  * @dma_object: dma object for this block
41  * @item: Pointer to this item
42  * @index: Index of this item in memory block
43  * @is_last: If this is last item in the block
44  * @userdata: Specific data of user
45  *
46  * This function is callback passed to __hal_mempool_create to create memory
47  * pool for TxD list
48  */
49 static vxge_hal_status_e
__hal_fifo_mempool_item_alloc(vxge_hal_mempool_h mempoolh,void * memblock,u32 memblock_index,vxge_hal_mempool_dma_t * dma_object,void * item,u32 item_index,u32 is_last,void * userdata)50 __hal_fifo_mempool_item_alloc(
51     vxge_hal_mempool_h mempoolh,
52     void *memblock,
53     u32 memblock_index,
54     vxge_hal_mempool_dma_t *dma_object,
55     void *item,
56     u32 item_index,
57     u32 is_last,
58     void *userdata)
59 {
60 	u32 i;
61 	void *block_priv;
62 	u32 memblock_item_idx;
63 
64 	__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
65 
66 	vxge_assert(fifo != NULL);
67 	vxge_assert(item);
68 
69 #if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
70 	{
71 		__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
72 
73 		vxge_hal_trace_log_pool("==> %s:%s:%d",
74 		    __FILE__, __func__, __LINE__);
75 
76 		vxge_hal_trace_log_pool(
77 		    "mempoolh = 0x"VXGE_OS_STXFMT", "
78 		    "memblock = 0x"VXGE_OS_STXFMT", memblock_index = %d, "
79 		    "dma_object = 0x"VXGE_OS_STXFMT", \
80 		    item = 0x"VXGE_OS_STXFMT", "
81 		    "item_index = %d, is_last = %d, userdata = 0x"VXGE_OS_STXFMT,
82 		    (ptr_t) mempoolh, (ptr_t) memblock, memblock_index,
83 		    (ptr_t) dma_object, (ptr_t) item, item_index, is_last,
84 		    (ptr_t) userdata);
85 	}
86 #endif
87 
88 	block_priv = __hal_mempool_item_priv((vxge_hal_mempool_t *) mempoolh,
89 	    memblock_index, item, &memblock_item_idx);
90 
91 	vxge_assert(block_priv != NULL);
92 
93 	for (i = 0; i < fifo->txdl_per_memblock; i++) {
94 
95 		__hal_fifo_txdl_priv_t *txdl_priv;
96 		vxge_hal_fifo_txd_t *txdp;
97 
98 		int dtr_index = item_index * fifo->txdl_per_memblock + i;
99 
100 		txdp = (vxge_hal_fifo_txd_t *) ((void *)
101 		    ((char *) item + i * fifo->txdl_size));
102 
103 		txdp->host_control = dtr_index;
104 
105 		fifo->channel.dtr_arr[dtr_index].dtr = txdp;
106 
107 		fifo->channel.dtr_arr[dtr_index].uld_priv = (void *)
108 		    ((char *) block_priv + fifo->txdl_priv_size * i);
109 
110 		fifo->channel.dtr_arr[dtr_index].hal_priv = (void *)
111 		    (((char *) fifo->channel.dtr_arr[dtr_index].uld_priv) +
112 		    fifo->per_txdl_space);
113 
114 		txdl_priv = (__hal_fifo_txdl_priv_t *)
115 		    fifo->channel.dtr_arr[dtr_index].hal_priv;
116 
117 		vxge_assert(txdl_priv);
118 
119 		/* pre-format HAL's TxDL's private */
120 		/* LINTED */
121 		txdl_priv->dma_offset = (char *) txdp - (char *) memblock;
122 		txdl_priv->dma_addr = dma_object->addr + txdl_priv->dma_offset;
123 		txdl_priv->dma_handle = dma_object->handle;
124 		txdl_priv->memblock = memblock;
125 		txdl_priv->first_txdp = (vxge_hal_fifo_txd_t *) txdp;
126 		txdl_priv->next_txdl_priv = NULL;
127 		txdl_priv->dang_txdl = NULL;
128 		txdl_priv->dang_frags = 0;
129 		txdl_priv->alloc_frags = 0;
130 
131 #if defined(VXGE_DEBUG_ASSERT)
132 		txdl_priv->dma_object = dma_object;
133 #endif
134 
135 #if defined(VXGE_HAL_ALIGN_XMIT)
136 		txdl_priv->align_vaddr = NULL;
137 		txdl_priv->align_dma_addr = (dma_addr_t) 0;
138 
139 #ifndef	VXGE_HAL_ALIGN_XMIT_ALLOC_RT
140 		/* CONSTCOND */
141 		if (TRUE) {
142 			vxge_hal_status_e status;
143 
144 			if (fifo->config->alignment_size) {
145 				status = __hal_fifo_txdl_align_alloc_map(fifo,
146 				    txdp);
147 				if (status != VXGE_HAL_OK) {
148 
149 #if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
150 					__hal_device_t *hldev;
151 					hldev = (__hal_device_t *)
152 					    fifo->channel.devh;
153 
154 					vxge_hal_err_log_pool(
155 					    "align buffer[%d] %d bytes, \
156 					    status %d",
157 					    (item_index * fifo->txdl_per_memblock + i),
158 					    fifo->align_size, status);
159 
160 					vxge_hal_trace_log_pool(
161 					    "<== %s:%s:%d  Result: 0",
162 					    __FILE__, __func__, __LINE__);
163 #endif
164 					return (status);
165 				}
166 			}
167 		}
168 #endif
169 #endif
170 		if (fifo->txdl_init) {
171 			fifo->txdl_init(fifo->channel.vph,
172 			    (vxge_hal_txdl_h) txdp,
173 			    VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp),
174 			    VXGE_HAL_FIFO_TXDL_INDEX(txdp),
175 			    fifo->channel.userdata, VXGE_HAL_OPEN_NORMAL);
176 		}
177 	}
178 
179 #if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
180 	{
181 		__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
182 
183 		vxge_hal_trace_log_pool("<== %s:%s:%d  Result: 0",
184 		    __FILE__, __func__, __LINE__);
185 	}
186 #endif
187 
188 	return (VXGE_HAL_OK);
189 }
190 
191 
192 /*
193  * __hal_fifo_mempool_item_free - Free List blocks for TxD list callback
194  * @mempoolh: Handle to memory pool
195  * @memblock: Address of this memory block
196  * @memblock_index: Index of this memory block
197  * @dma_object: dma object for this block
198  * @item: Pointer to this item
199  * @index: Index of this item in memory block
200  * @is_last: If this is last item in the block
201  * @userdata: Specific data of user
202  *
203  * This function is callback passed to __hal_mempool_free to destroy memory
204  * pool for TxD list
205  */
206 static vxge_hal_status_e
__hal_fifo_mempool_item_free(vxge_hal_mempool_h mempoolh,void * memblock,u32 memblock_index,vxge_hal_mempool_dma_t * dma_object,void * item,u32 item_index,u32 is_last,void * userdata)207 __hal_fifo_mempool_item_free(
208     vxge_hal_mempool_h mempoolh,
209     void *memblock,
210     u32 memblock_index,
211     vxge_hal_mempool_dma_t *dma_object,
212     void *item,
213     u32 item_index,
214     u32 is_last,
215     void *userdata)
216 {
217 	vxge_assert(item);
218 
219 #if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
220 	{
221 		__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
222 
223 		vxge_assert(fifo != NULL);
224 
225 		__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
226 
227 		vxge_hal_trace_log_pool("==> %s:%s:%d",
228 		    __FILE__, __func__, __LINE__);
229 
230 		vxge_hal_trace_log_pool("mempoolh = 0x"VXGE_OS_STXFMT", "
231 		    "memblock = 0x"VXGE_OS_STXFMT", memblock_index = %d, "
232 		    "dma_object = 0x"VXGE_OS_STXFMT", \
233 		    item = 0x"VXGE_OS_STXFMT", "
234 		    "item_index = %d, is_last = %d, userdata = 0x"VXGE_OS_STXFMT,
235 		    (ptr_t) mempoolh, (ptr_t) memblock, memblock_index,
236 		    (ptr_t) dma_object, (ptr_t) item, item_index, is_last,
237 		    (ptr_t) userdata);
238 	}
239 #endif
240 
241 #if defined(VXGE_HAL_ALIGN_XMIT)
242 	{
243 		__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
244 
245 		vxge_assert(fifo != NULL);
246 		if (fifo->config->alignment_size) {
247 
248 			int i;
249 			vxge_hal_fifo_txd_t *txdp;
250 
251 			for (i = 0; i < fifo->txdl_per_memblock; i++) {
252 				txdp = (void *)
253 				    ((char *) item + i * fifo->txdl_size);
254 				__hal_fifo_txdl_align_free_unmap(fifo, txdp);
255 			}
256 		}
257 	}
258 #endif
259 
260 #if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
261 	{
262 		__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
263 
264 		vxge_assert(fifo != NULL);
265 
266 		__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
267 
268 		vxge_hal_trace_log_pool("<== %s:%s:%d  Result: 0",
269 		    __FILE__, __func__, __LINE__);
270 	}
271 #endif
272 
273 	return (VXGE_HAL_OK);
274 }
275 
276 /*
277  * __hal_fifo_create - Create a FIFO
278  * @vpath_handle: Handle returned by virtual path open
279  * @attr: FIFO configuration parameters structure
280  *
281  * This function creates FIFO and initializes it.
282  *
283  */
284 vxge_hal_status_e
__hal_fifo_create(vxge_hal_vpath_h vpath_handle,vxge_hal_fifo_attr_t * attr)285 __hal_fifo_create(
286     vxge_hal_vpath_h vpath_handle,
287     vxge_hal_fifo_attr_t *attr)
288 {
289 	vxge_hal_status_e status;
290 	__hal_fifo_t *fifo;
291 	vxge_hal_fifo_config_t *config;
292 	u32 txdl_size, memblock_size, txdl_per_memblock;
293 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
294 	__hal_device_t *hldev;
295 
296 	vxge_assert((vpath_handle != NULL) && (attr != NULL));
297 
298 	hldev = (__hal_device_t *) vp->vpath->hldev;
299 
300 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
301 	    __FILE__, __func__, __LINE__);
302 
303 	vxge_hal_trace_log_fifo(
304 	    "vpath_handle = 0x"VXGE_OS_STXFMT", attr = 0x"VXGE_OS_STXFMT,
305 	    (ptr_t) vpath_handle, (ptr_t) attr);
306 
307 	if ((vpath_handle == NULL) || (attr == NULL)) {
308 		vxge_hal_err_log_fifo("null pointer passed == > %s : %d",
309 		    __func__, __LINE__);
310 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
311 		    __FILE__, __func__, __LINE__,
312 		    VXGE_HAL_ERR_INVALID_HANDLE);
313 		return (VXGE_HAL_ERR_INVALID_HANDLE);
314 	}
315 
316 	config =
317 	    &vp->vpath->hldev->header.config.vp_config[vp->vpath->vp_id].fifo;
318 
319 	txdl_size = config->max_frags * sizeof(vxge_hal_fifo_txd_t);
320 
321 	if (txdl_size <= VXGE_OS_HOST_PAGE_SIZE)
322 		memblock_size = VXGE_OS_HOST_PAGE_SIZE;
323 	else
324 		memblock_size = txdl_size;
325 
326 	txdl_per_memblock = memblock_size / txdl_size;
327 
328 	config->fifo_length = ((config->fifo_length + txdl_per_memblock - 1) /
329 	    txdl_per_memblock) * txdl_per_memblock;
330 
331 	fifo = (__hal_fifo_t *) vxge_hal_channel_allocate(
332 	    (vxge_hal_device_h) vp->vpath->hldev,
333 	    vpath_handle,
334 	    VXGE_HAL_CHANNEL_TYPE_FIFO,
335 	    config->fifo_length,
336 	    attr->per_txdl_space,
337 	    attr->userdata);
338 
339 	if (fifo == NULL) {
340 		vxge_hal_err_log_fifo("Memory allocation failed == > %s : %d",
341 		    __func__, __LINE__);
342 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
343 		    __FILE__, __func__, __LINE__,
344 		    VXGE_HAL_ERR_OUT_OF_MEMORY);
345 		return (VXGE_HAL_ERR_OUT_OF_MEMORY);
346 	}
347 
348 	vp->vpath->fifoh = fifo;
349 
350 	fifo->stats = &vp->vpath->sw_stats->fifo_stats;
351 
352 	fifo->config = config;
353 
354 	fifo->memblock_size = memblock_size;
355 
356 #if defined(VXGE_HAL_TX_MULTI_POST)
357 	vxge_os_spin_lock_init(&fifo->channel.post_lock,
358 	    vp->vpath->hldev->header.pdev);
359 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
360 	vxge_os_spin_lock_init_irq(&fifo->channel.post_lock,
361 	    vp->vpath->hldev->header.irqh);
362 #endif
363 
364 	fifo->align_size =
365 	    fifo->config->alignment_size * fifo->config->max_aligned_frags;
366 
367 	/* apply "interrupts per txdl" attribute */
368 	fifo->interrupt_type = VXGE_HAL_FIFO_TXD_INT_TYPE_UTILZ;
369 	if (fifo->config->intr) {
370 		fifo->interrupt_type = VXGE_HAL_FIFO_TXD_INT_TYPE_PER_LIST;
371 	}
372 
373 	fifo->no_snoop_bits = config->no_snoop_bits;
374 
375 	/*
376 	 * FIFO memory management strategy:
377 	 *
378 	 * TxDL splitted into three independent parts:
379 	 *	- set of TxD's
380 	 *	- TxD HAL private part
381 	 *	- upper layer private part
382 	 *
383 	 * Adaptative memory allocation used. i.e. Memory allocated on
384 	 * demand with the size which will fit into one memory block.
385 	 * One memory block may contain more than one TxDL. In simple case
386 	 * memory block size can be equal to CPU page size. On more
387 	 * sophisticated OS's memory block can be contiguous across
388 	 * several pages.
389 	 *
390 	 * During "reserve" operations more memory can be allocated on demand
391 	 * for example due to FIFO full condition.
392 	 *
393 	 * Pool of memory memblocks never shrinks except __hal_fifo_close
394 	 * routine which will essentially stop channel and free the resources.
395 	 */
396 
397 	/* TxDL common private size == TxDL private + ULD private */
398 	fifo->txdl_priv_size =
399 	    sizeof(__hal_fifo_txdl_priv_t) + attr->per_txdl_space;
400 	fifo->txdl_priv_size =
401 	    ((fifo->txdl_priv_size + __vxge_os_cacheline_size - 1) /
402 	    __vxge_os_cacheline_size) * __vxge_os_cacheline_size;
403 
404 	fifo->per_txdl_space = attr->per_txdl_space;
405 
406 	/* recompute txdl size to be cacheline aligned */
407 	fifo->txdl_size = txdl_size;
408 	fifo->txdl_per_memblock = txdl_per_memblock;
409 
410 	/*
411 	 * since txdl_init() callback will be called from item_alloc(),
412 	 * the same way channels userdata might be used prior to
413 	 * channel_initialize()
414 	 */
415 	fifo->txdl_init = attr->txdl_init;
416 	fifo->txdl_term = attr->txdl_term;
417 	fifo->callback = attr->callback;
418 
419 	if (fifo->txdl_per_memblock == 0) {
420 		__hal_fifo_delete(vpath_handle);
421 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
422 		    __FILE__, __func__, __LINE__,
423 		    VXGE_HAL_ERR_INVALID_BLOCK_SIZE);
424 		return (VXGE_HAL_ERR_INVALID_BLOCK_SIZE);
425 	}
426 
427 	/* calculate actual TxDL block private size */
428 	fifo->txdlblock_priv_size =
429 	    fifo->txdl_priv_size * fifo->txdl_per_memblock;
430 
431 	fifo->mempool =
432 	    vxge_hal_mempool_create((vxge_hal_device_h) vp->vpath->hldev,
433 	    fifo->memblock_size,
434 	    fifo->memblock_size,
435 	    fifo->txdlblock_priv_size,
436 	    fifo->config->fifo_length /
437 	    fifo->txdl_per_memblock,
438 	    fifo->config->fifo_length /
439 	    fifo->txdl_per_memblock,
440 	    __hal_fifo_mempool_item_alloc,
441 	    __hal_fifo_mempool_item_free,
442 	    fifo);
443 
444 	if (fifo->mempool == NULL) {
445 		__hal_fifo_delete(vpath_handle);
446 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
447 		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
448 		return (VXGE_HAL_ERR_OUT_OF_MEMORY);
449 	}
450 
451 	status = vxge_hal_channel_initialize(&fifo->channel);
452 	if (status != VXGE_HAL_OK) {
453 		__hal_fifo_delete(vpath_handle);
454 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
455 		    __FILE__, __func__, __LINE__, status);
456 		return (status);
457 	}
458 
459 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
460 	    __FILE__, __func__, __LINE__);
461 	return (VXGE_HAL_OK);
462 }
463 
464 /*
465  * __hal_fifo_abort - Returns the TxD
466  * @fifoh: Fifo to be reset
467  * @reopen: See  vxge_hal_reopen_e {}.
468  *
469  * This function terminates the TxDs of fifo
470  */
471 void
__hal_fifo_abort(vxge_hal_fifo_h fifoh,vxge_hal_reopen_e reopen)472 __hal_fifo_abort(
473     vxge_hal_fifo_h fifoh,
474     vxge_hal_reopen_e reopen)
475 {
476 	u32 i = 0;
477 	__hal_fifo_t *fifo = (__hal_fifo_t *) fifoh;
478 	__hal_device_t *hldev;
479 	vxge_hal_txdl_h txdlh;
480 
481 	vxge_assert(fifoh != NULL);
482 
483 	hldev = (__hal_device_t *) fifo->channel.devh;
484 
485 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
486 	    __FILE__, __func__, __LINE__);
487 
488 	vxge_hal_trace_log_fifo("fifo = 0x"VXGE_OS_STXFMT", reopen = %d",
489 	    (ptr_t) fifoh, reopen);
490 
491 	if (fifo->txdl_term) {
492 		__hal_channel_for_each_dtr(&fifo->channel, txdlh, i) {
493 			if (!__hal_channel_is_posted_dtr(&fifo->channel,
494 			    i)) {
495 				fifo->txdl_term(fifo->channel.vph, txdlh,
496 				    VXGE_HAL_FIFO_ULD_PRIV(fifo, txdlh),
497 				    VXGE_HAL_TXDL_STATE_FREED,
498 				    fifo->channel.userdata,
499 				    reopen);
500 			}
501 		}
502 	}
503 
504 	for (;;) {
505 		__hal_channel_dtr_try_complete(&fifo->channel, &txdlh);
506 
507 		if (txdlh == NULL)
508 			break;
509 
510 		__hal_channel_dtr_complete(&fifo->channel);
511 
512 		if (fifo->txdl_term) {
513 			fifo->txdl_term(fifo->channel.vph, txdlh,
514 			    VXGE_HAL_FIFO_ULD_PRIV(fifo, txdlh),
515 			    VXGE_HAL_TXDL_STATE_POSTED,
516 			    fifo->channel.userdata,
517 			    reopen);
518 		}
519 
520 		__hal_channel_dtr_free(&fifo->channel,
521 		    VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
522 	}
523 
524 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
525 	    __FILE__, __func__, __LINE__);
526 }
527 
528 /*
529  * __hal_fifo_reset - Resets the fifo
530  * @fifoh: Fifo to be reset
531  *
532  * This function resets the fifo during vpath reset operation
533  */
534 vxge_hal_status_e
__hal_fifo_reset(vxge_hal_fifo_h fifoh)535 __hal_fifo_reset(
536     vxge_hal_fifo_h fifoh)
537 {
538 	vxge_hal_status_e status;
539 	__hal_device_t *hldev;
540 	__hal_fifo_t *fifo = (__hal_fifo_t *) fifoh;
541 
542 	vxge_assert(fifoh != NULL);
543 
544 	hldev = (__hal_device_t *) fifo->channel.devh;
545 
546 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
547 	    __FILE__, __func__, __LINE__);
548 
549 	vxge_hal_trace_log_fifo("fifo = 0x"VXGE_OS_STXFMT,
550 	    (ptr_t) fifoh);
551 
552 	__hal_fifo_abort(fifoh, VXGE_HAL_RESET_ONLY);
553 
554 	status = __hal_channel_reset(&fifo->channel);
555 
556 	if (status != VXGE_HAL_OK) {
557 
558 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
559 		    __FILE__, __func__, __LINE__, status);
560 		return (status);
561 
562 	}
563 
564 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
565 	    __FILE__, __func__, __LINE__);
566 
567 	return (VXGE_HAL_OK);
568 }
569 
570 /*
571  * vxge_hal_fifo_doorbell_reset - Resets the doorbell fifo
572  * @vapth_handle: Vpath Handle
573  *
574  * This function resets the doorbell fifo during if fifo error occurs
575  */
576 vxge_hal_status_e
vxge_hal_fifo_doorbell_reset(vxge_hal_vpath_h vpath_handle)577 vxge_hal_fifo_doorbell_reset(
578     vxge_hal_vpath_h vpath_handle)
579 {
580 	u32 i;
581 	vxge_hal_txdl_h txdlh;
582 	__hal_fifo_t *fifo;
583 	__hal_virtualpath_t *vpath;
584 	__hal_fifo_txdl_priv_t *txdl_priv;
585 	__hal_device_t *hldev;
586 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
587 	vxge_hal_status_e status = VXGE_HAL_OK;
588 
589 	vxge_assert(vpath_handle != NULL);
590 
591 	hldev = vp->vpath->hldev;
592 
593 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
594 	    __FILE__, __func__, __LINE__);
595 
596 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
597 	    (ptr_t) vpath_handle);
598 
599 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
600 
601 	vpath = ((__hal_vpath_handle_t *) fifo->channel.vph)->vpath;
602 
603 	status = __hal_non_offload_db_reset(fifo->channel.vph);
604 
605 	if (status != VXGE_HAL_OK) {
606 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
607 		    __FILE__, __func__, __LINE__);
608 		return (status);
609 	}
610 
611 	__hal_channel_for_each_posted_dtr(&fifo->channel, txdlh, i) {
612 
613 		txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
614 
615 		__hal_non_offload_db_post(fifo->channel.vph,
616 		    ((VXGE_HAL_FIFO_TXD_NO_BW_LIMIT_GET(
617 		    ((vxge_hal_fifo_txd_t *) txdlh)->control_1)) ?
618 		    (((u64) txdl_priv->dma_addr) | 0x1) :
619 		    (u64) txdl_priv->dma_addr),
620 		    txdl_priv->frags - 1,
621 		    vpath->vp_config->fifo.no_snoop_bits);
622 	}
623 
624 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
625 	    __FILE__, __func__, __LINE__);
626 
627 	return (status);
628 }
629 
630 /*
631  * __hal_fifo_delete - Removes the FIFO
632  * @vpath_handle: Virtual path handle to which this queue belongs
633  *
634  * This function freeup the memory pool and removes the FIFO
635  */
636 void
__hal_fifo_delete(vxge_hal_vpath_h vpath_handle)637 __hal_fifo_delete(
638     vxge_hal_vpath_h vpath_handle)
639 {
640 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
641 	__hal_fifo_t *fifo;
642 	__hal_device_t *hldev;
643 
644 	vxge_assert(vpath_handle != NULL);
645 
646 	hldev = vp->vpath->hldev;
647 
648 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
649 	    __FILE__, __func__, __LINE__);
650 
651 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
652 	    (ptr_t) vpath_handle);
653 
654 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
655 
656 	vxge_assert(fifo != NULL);
657 
658 	if (fifo->mempool) {
659 		__hal_fifo_abort(vp->vpath->fifoh, VXGE_HAL_OPEN_NORMAL);
660 		vxge_hal_mempool_destroy(fifo->mempool);
661 	}
662 
663 	vxge_hal_channel_terminate(&fifo->channel);
664 
665 #if defined(VXGE_HAL_TX_MULTI_POST)
666 	vxge_os_spin_lock_destroy(&fifo->channel.post_lock,
667 	    vp->vpath->hldev->header.pdev);
668 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
669 	vxge_os_spin_lock_destroy_irq(&fifo->channel.post_lock,
670 	    vp->vpath->hldev->header.pdev);
671 #endif
672 
673 	vxge_hal_channel_free(&fifo->channel);
674 
675 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
676 	    __FILE__, __func__, __LINE__);
677 }
678 
679 #if defined(VXGE_HAL_ALIGN_XMIT)
680 /*
681  * __hal_fifo_txdl_align_free_unmap - Unmap the alignement buffers
682  * @fifo: Fifo
683  * @txdp: txdl
684  *
685  * This function unmaps dma memory for the alignment buffers
686  */
687 void
__hal_fifo_txdl_align_free_unmap(__hal_fifo_t * fifo,vxge_hal_fifo_txd_t * txdp)688 __hal_fifo_txdl_align_free_unmap(
689     __hal_fifo_t *fifo,
690     vxge_hal_fifo_txd_t *txdp)
691 {
692 	__hal_device_t *hldev;
693 	__hal_fifo_txdl_priv_t *txdl_priv;
694 
695 	vxge_assert((fifo != NULL) && (txdp != NULL));
696 
697 	hldev = (__hal_device_t *) fifo->channel.devh;
698 
699 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
700 	    __FILE__, __func__, __LINE__);
701 
702 	vxge_hal_trace_log_fifo(
703 	    "fifo = 0x"VXGE_OS_STXFMT",  txdp = 0x"VXGE_OS_STXFMT,
704 	    (ptr_t) fifo, (ptr_t) txdp);
705 
706 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
707 
708 	if (txdl_priv->align_vaddr != NULL) {
709 		__hal_blockpool_free(fifo->channel.devh,
710 		    txdl_priv->align_vaddr,
711 		    fifo->align_size,
712 		    &txdl_priv->align_dma_addr,
713 		    &txdl_priv->align_dma_handle,
714 		    &txdl_priv->align_dma_acch);
715 
716 		txdl_priv->align_vaddr = NULL;
717 		txdl_priv->align_dma_addr = 0;
718 	}
719 
720 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
721 	    __FILE__, __func__, __LINE__);
722 }
723 
724 /*
725  * __hal_fifo_txdl_align_alloc_map - Maps the alignement buffers
726  * @fifo: Fifo
727  * @txdp: txdl
728  *
729  * This function maps dma memory for the alignment buffers
730  */
731 vxge_hal_status_e
__hal_fifo_txdl_align_alloc_map(__hal_fifo_t * fifo,vxge_hal_fifo_txd_t * txdp)732 __hal_fifo_txdl_align_alloc_map(
733     __hal_fifo_t *fifo,
734     vxge_hal_fifo_txd_t *txdp)
735 {
736 	__hal_device_t *hldev;
737 	__hal_fifo_txdl_priv_t *txdl_priv;
738 
739 	vxge_assert((fifo != NULL) && (txdp != NULL));
740 
741 	hldev = (__hal_device_t *) fifo->channel.devh;
742 
743 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
744 	    __FILE__, __func__, __LINE__);
745 
746 	vxge_hal_trace_log_fifo(
747 	    "fifo = 0x"VXGE_OS_STXFMT",  txdp = 0x"VXGE_OS_STXFMT,
748 	    (ptr_t) fifo, (ptr_t) txdp);
749 
750 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
751 
752 	/* allocate alignment DMA-buffer */
753 	txdl_priv->align_vaddr =
754 	    (u8 *) __hal_blockpool_malloc(fifo->channel.devh,
755 	    fifo->align_size,
756 	    &txdl_priv->align_dma_addr,
757 	    &txdl_priv->align_dma_handle,
758 	    &txdl_priv->align_dma_acch);
759 	if (txdl_priv->align_vaddr == NULL) {
760 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
761 		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
762 		return (VXGE_HAL_ERR_OUT_OF_MEMORY);
763 	}
764 
765 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
766 	    __FILE__, __func__, __LINE__);
767 	return (VXGE_HAL_OK);
768 }
769 #endif
770 /*
771  * vxge_hal_fifo_free_txdl_count_get - returns the number of txdls
772  *                               available in the fifo
773  * @vpath_handle: Virtual path handle.
774  */
775 u32
vxge_hal_fifo_free_txdl_count_get(vxge_hal_vpath_h vpath_handle)776 vxge_hal_fifo_free_txdl_count_get(vxge_hal_vpath_h vpath_handle)
777 {
778 	return __hal_channel_free_dtr_count(&((__hal_fifo_t *)
779 	    ((__hal_vpath_handle_t *) vpath_handle)->vpath->fifoh)->channel);
780 }
781 
782 /*
783  * vxge_hal_fifo_txdl_private_get - Retrieve per-descriptor private data.
784  * @vpath_handle: Virtual path handle.
785  * @txdlh: Descriptor handle.
786  *
787  * Retrieve per-descriptor private data.
788  * Note that ULD requests per-descriptor space via
789  * vxge_hal_fifo_attr_t passed to
790  * vxge_hal_vpath_open().
791  *
792  * Returns: private ULD data associated with the descriptor.
793  */
794 void *
vxge_hal_fifo_txdl_private_get(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh)795 vxge_hal_fifo_txdl_private_get(
796     vxge_hal_vpath_h vpath_handle,
797     vxge_hal_txdl_h txdlh)
798 {
799 	return (VXGE_HAL_FIFO_ULD_PRIV(((__hal_fifo_t *)
800 	    ((__hal_vpath_handle_t *) vpath_handle)->vpath->fifoh), txdlh));
801 }
802 
803 /*
804  * vxge_hal_fifo_txdl_reserve - Reserve fifo descriptor.
805  * @vapth_handle: virtual path handle.
806  * @txdlh: Reserved descriptor. On success HAL fills this "out" parameter
807  *	with a valid handle.
808  * @txdl_priv: Buffer to return the pointer to per txdl space
809  *
810  * Reserve a single TxDL (that is, fifo descriptor)
811  * for the subsequent filling-in by upper layerdriver (ULD))
812  * and posting on the corresponding channel (@channelh)
813  * via vxge_hal_fifo_txdl_post().
814  *
815  * Note: it is the responsibility of ULD to reserve multiple descriptors
816  * for lengthy (e.g., LSO) transmit operation. A single fifo descriptor
817  * carries up to configured number (fifo.max_frags) of contiguous buffers.
818  *
819  * Returns: VXGE_HAL_OK - success;
820  * VXGE_HAL_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available
821  *
822  */
823 vxge_hal_status_e
vxge_hal_fifo_txdl_reserve(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h * txdlh,void ** txdl_priv)824 vxge_hal_fifo_txdl_reserve(
825     vxge_hal_vpath_h vpath_handle,
826     vxge_hal_txdl_h *txdlh,
827     void **txdl_priv)
828 {
829 	u32 i;
830 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
831 	__hal_device_t *hldev;
832 	__hal_fifo_t *fifo;
833 	vxge_hal_status_e status;
834 
835 #if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
836 	unsigned long flags = 0;
837 
838 #endif
839 
840 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
841 
842 	hldev = vp->vpath->hldev;
843 
844 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
845 	    __FILE__, __func__, __LINE__);
846 
847 	vxge_hal_trace_log_fifo(
848 	    "vpath_handle = 0x"VXGE_OS_STXFMT",  txdlh = 0x"VXGE_OS_STXFMT,
849 	    (ptr_t) vpath_handle, (ptr_t) txdlh);
850 
851 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
852 
853 	vxge_assert(fifo != NULL);
854 
855 #if defined(VXGE_HAL_TX_MULTI_POST)
856 	vxge_os_spin_lock(&fifo->channel.post_lock);
857 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
858 	vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
859 #endif
860 
861 	status = __hal_channel_dtr_reserve(&fifo->channel, txdlh);
862 
863 #if defined(VXGE_HAL_TX_MULTI_POST)
864 	vxge_os_spin_unlock(&fifo->channel.post_lock);
865 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
866 	vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
867 #endif
868 
869 	if (status == VXGE_HAL_OK) {
870 		vxge_hal_fifo_txd_t *txdp = (vxge_hal_fifo_txd_t *)*txdlh;
871 		__hal_fifo_txdl_priv_t *priv;
872 
873 		priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
874 
875 		/* reset the TxDL's private */
876 		priv->align_dma_offset = 0;
877 		priv->align_vaddr_start = priv->align_vaddr;
878 		priv->align_used_frags = 0;
879 		priv->frags = 0;
880 		priv->alloc_frags = fifo->config->max_frags;
881 		priv->dang_txdl = NULL;
882 		priv->dang_frags = 0;
883 		priv->next_txdl_priv = NULL;
884 		priv->bytes_sent = 0;
885 
886 		*txdl_priv = VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp);
887 
888 		for (i = 0; i < fifo->config->max_frags; i++) {
889 			txdp = ((vxge_hal_fifo_txd_t *)*txdlh) + i;
890 			txdp->control_0 = txdp->control_1 = 0;
891 		}
892 
893 #if defined(VXGE_OS_MEMORY_CHECK)
894 		priv->allocated = 1;
895 #endif
896 	}
897 
898 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
899 	    __FILE__, __func__, __LINE__);
900 	return (status);
901 }
902 
903 /*
904  * vxge_hal_fifo_txdl_buffer_set - Set transmit buffer pointer in the
905  * descriptor.
906  * @vpath_handle: virtual path handle.
907  * @txdlh: Descriptor handle.
908  * @frag_idx: Index of the data buffer in the caller's scatter-gather list
909  *	   (of buffers).
910  * @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
911  * @size: Size of the data buffer (in bytes).
912  *
913  * This API is part of the preparation of the transmit descriptor for posting
914  * (via vxge_hal_fifo_txdl_post()). The related "preparation" APIs include
915  * vxge_hal_fifo_txdl_mss_set() and vxge_hal_fifo_txdl_cksum_set_bits().
916  * All three APIs fill in the fields of the fifo descriptor,
917  * in accordance with the X3100 specification.
918  *
919  */
920 void
vxge_hal_fifo_txdl_buffer_set(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,u32 frag_idx,dma_addr_t dma_pointer,unsigned long size)921 vxge_hal_fifo_txdl_buffer_set(
922     vxge_hal_vpath_h vpath_handle,
923     vxge_hal_txdl_h txdlh,
924     u32 frag_idx,
925     dma_addr_t dma_pointer,
926     unsigned long size)
927 {
928 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
929 	__hal_fifo_t *fifo;
930 	__hal_device_t *hldev;
931 	__hal_fifo_txdl_priv_t *txdl_priv;
932 	vxge_hal_fifo_txd_t *txdp;
933 
934 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL) &&
935 	    (dma_pointer != 0) && (size != 0));
936 
937 	hldev = vp->vpath->hldev;
938 
939 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
940 	    __FILE__, __func__, __LINE__);
941 
942 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
943 	    "txdlh = 0x"VXGE_OS_STXFMT", frag_idx = %d, "
944 	    "dma_pointer = 0x"VXGE_OS_LLXFMT", size = %lu",
945 	    (ptr_t) vpath_handle, (ptr_t) txdlh,
946 	    frag_idx, (u64) dma_pointer, size);
947 
948 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
949 
950 	vxge_assert(fifo != NULL);
951 
952 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
953 
954 	txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
955 
956 	/*
957 	 * Note:
958 	 * it is the responsibility of upper layers and not HAL
959 	 * detect it and skip zero-size fragment
960 	 */
961 	vxge_assert(size > 0);
962 	vxge_assert(frag_idx < txdl_priv->alloc_frags);
963 
964 	txdp->buffer_pointer = (u64) dma_pointer;
965 	txdp->control_0 |= VXGE_HAL_FIFO_TXD_BUFFER_SIZE(size);
966 	txdl_priv->bytes_sent += size;
967 	fifo->stats->total_buffers++;
968 	txdl_priv->frags++;
969 
970 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
971 	    __FILE__, __func__, __LINE__);
972 }
973 
974 /*
975  * vxge_hal_fifo_txdl_buffer_set_aligned - Align transmit buffer and fill
976  * in fifo descriptor.
977  * @vpath_handle: Virtual path handle.
978  * @txdlh: Descriptor handle.
979  * @frag_idx: Index of the data buffer in the caller's scatter-gather list
980  *	   (of buffers).
981  * @vaddr: Virtual address of the data buffer.
982  * @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
983  * @size: Size of the data buffer (in bytes).
984  * @misaligned_size: Size (in bytes) of the misaligned portion of the
985  * data buffer. Calculated by the caller, based on the platform/OS/other
986  * specific criteria, which is outside of HAL's domain. See notes below.
987  *
988  * This API is part of the transmit descriptor preparation for posting
989  * (via vxge_hal_fifo_txdl_post()). The related "preparation" APIs include
990  * vxge_hal_fifo_txdl_mss_set() and vxge_hal_fifo_txdl_cksum_set_bits().
991  * All three APIs fill in the fields of the fifo descriptor,
992  * in accordance with the X3100 specification.
993  * On the PCI-X based systems aligning transmit data typically provides better
994  * transmit performance. The typical alignment granularity: L2 cacheline size.
995  * However, HAL does not make assumptions in terms of the alignment granularity;
996  * this is specified via additional @misaligned_size parameter described above.
997  * Prior to calling vxge_hal_fifo_txdl_buffer_set_aligned(),
998  * ULD is supposed to check alignment of a given fragment/buffer. For this HAL
999  * provides a separate vxge_hal_check_alignment() API sufficient to cover
1000  * most (but not all) possible alignment criteria.
1001  * If the buffer appears to be aligned, the ULD calls
1002  * vxge_hal_fifo_txdl_buffer_set().
1003  * Otherwise, ULD calls vxge_hal_fifo_txdl_buffer_set_aligned().
1004  *
1005  * Note; This API is a "superset" of vxge_hal_fifo_txdl_buffer_set(). In
1006  * addition to filling in the specified descriptor it aligns transmit data on
1007  * the specified boundary.
1008  * Note: Decision on whether to align or not to align a given contiguous
1009  * transmit buffer is outside of HAL's domain. To this end ULD can use any
1010  * programmable criteria, which can help to 1) boost transmit performance,
1011  * and/or 2) provide a workaround for PCI bridge bugs, if any.
1012  *
1013  */
1014 vxge_hal_status_e
vxge_hal_fifo_txdl_buffer_set_aligned(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,u32 frag_idx,void * vaddr,dma_addr_t dma_pointer,u32 size,u32 misaligned_size)1015 vxge_hal_fifo_txdl_buffer_set_aligned(
1016     vxge_hal_vpath_h vpath_handle,
1017     vxge_hal_txdl_h txdlh,
1018     u32 frag_idx,
1019     void *vaddr,
1020     dma_addr_t dma_pointer,
1021     u32 size,
1022     u32 misaligned_size)
1023 {
1024 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1025 	__hal_fifo_t *fifo;
1026 	__hal_device_t *hldev;
1027 	__hal_fifo_txdl_priv_t *txdl_priv;
1028 	vxge_hal_fifo_txd_t *txdp;
1029 	int remaining_size;
1030 	ptrdiff_t prev_boff;
1031 
1032 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL) &&
1033 	    (vaddr != NULL) && (dma_pointer != 0) &&
1034 	    (size != 0) && (misaligned_size != 0));
1035 
1036 	hldev = vp->vpath->hldev;
1037 
1038 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1039 	    __FILE__, __func__, __LINE__);
1040 
1041 	vxge_hal_trace_log_fifo(
1042 	    "vpath_handle = 0x"VXGE_OS_STXFMT", txdlh = 0x"VXGE_OS_STXFMT", "
1043 	    "frag_idx = %d, vaddr = 0x"VXGE_OS_STXFMT", "
1044 	    "dma_pointer = 0x"VXGE_OS_LLXFMT", size = %d, "
1045 	    "misaligned_size = %d", (ptr_t) vpath_handle,
1046 	    (ptr_t) txdlh, frag_idx, (ptr_t) vaddr, (u64) dma_pointer, size,
1047 	    misaligned_size);
1048 
1049 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1050 
1051 	vxge_assert(fifo != NULL);
1052 
1053 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1054 
1055 	txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
1056 
1057 	/*
1058 	 * On some systems buffer size could be zero.
1059 	 * It is the responsibility of ULD and *not HAL* to
1060 	 * detect it and skip it.
1061 	 */
1062 	vxge_assert(size > 0);
1063 	vxge_assert(frag_idx < txdl_priv->alloc_frags);
1064 	vxge_assert(misaligned_size != 0 &&
1065 	    misaligned_size <= fifo->config->alignment_size);
1066 
1067 	remaining_size = size - misaligned_size;
1068 	vxge_assert(remaining_size >= 0);
1069 
1070 	vxge_os_memcpy((char *) txdl_priv->align_vaddr_start,
1071 	    vaddr, misaligned_size);
1072 
1073 	if (txdl_priv->align_used_frags >= fifo->config->max_aligned_frags) {
1074 		return (VXGE_HAL_ERR_OUT_ALIGNED_FRAGS);
1075 	}
1076 
1077 	/* setup new buffer */
1078 	/* LINTED */
1079 	prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
1080 	txdp->buffer_pointer = (u64) txdl_priv->align_dma_addr + prev_boff;
1081 	txdp->control_0 |= VXGE_HAL_FIFO_TXD_BUFFER_SIZE(misaligned_size);
1082 	txdl_priv->bytes_sent += misaligned_size;
1083 	fifo->stats->total_buffers++;
1084 	txdl_priv->frags++;
1085 	txdl_priv->align_used_frags++;
1086 	txdl_priv->align_vaddr_start += fifo->config->alignment_size;
1087 	txdl_priv->align_dma_offset = 0;
1088 
1089 #if defined(VXGE_OS_DMA_REQUIRES_SYNC)
1090 	/* sync new buffer */
1091 	vxge_os_dma_sync(fifo->channel.pdev,
1092 	    txdl_priv->align_dma_handle,
1093 	    txdp->buffer_pointer,
1094 	    0,
1095 	    misaligned_size,
1096 	    VXGE_OS_DMA_DIR_TODEVICE);
1097 #endif
1098 
1099 	if (remaining_size) {
1100 		vxge_assert(frag_idx < txdl_priv->alloc_frags);
1101 		txdp++;
1102 		txdp->buffer_pointer = (u64) dma_pointer + misaligned_size;
1103 		txdp->control_0 |=
1104 		    VXGE_HAL_FIFO_TXD_BUFFER_SIZE(remaining_size);
1105 		txdl_priv->bytes_sent += remaining_size;
1106 		fifo->stats->total_buffers++;
1107 		txdl_priv->frags++;
1108 	}
1109 
1110 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1111 	    __FILE__, __func__, __LINE__);
1112 	return (VXGE_HAL_OK);
1113 }
1114 
1115 /*
1116  * vxge_hal_fifo_txdl_buffer_append - Append the contents of virtually
1117  *		contiguous data buffer to a single physically contiguous buffer.
1118  * @vpath_handle: Virtual path handle.
1119  * @txdlh: Descriptor handle.
1120  * @vaddr: Virtual address of the data buffer.
1121  * @size: Size of the data buffer (in bytes).
1122  *
1123  * This API is part of the transmit descriptor preparation for posting
1124  * (via vxge_hal_fifo_txdl_post()).
1125  * The main difference of this API wrt to the APIs
1126  * vxge_hal_fifo_txdl_buffer_set_aligned() is that this API appends the
1127  * contents of virtually contiguous data buffers received from
1128  * upper layer into a single physically contiguous data buffer and the
1129  * device will do a DMA from this buffer.
1130  *
1131  * See Also: vxge_hal_fifo_txdl_buffer_finalize(),
1132  * vxge_hal_fifo_txdl_buffer_set(),
1133  * vxge_hal_fifo_txdl_buffer_set_aligned().
1134  */
1135 vxge_hal_status_e
vxge_hal_fifo_txdl_buffer_append(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,void * vaddr,u32 size)1136 vxge_hal_fifo_txdl_buffer_append(
1137     vxge_hal_vpath_h vpath_handle,
1138     vxge_hal_txdl_h txdlh,
1139     void *vaddr,
1140     u32 size)
1141 {
1142 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1143 	__hal_fifo_t *fifo;
1144 	__hal_device_t *hldev;
1145 	__hal_fifo_txdl_priv_t *txdl_priv;
1146 	ptrdiff_t used;
1147 
1148 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL) &&
1149 	    (vaddr != NULL) && (size == 0));
1150 
1151 	hldev = vp->vpath->hldev;
1152 
1153 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1154 	    __FILE__, __func__, __LINE__);
1155 
1156 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1157 	    "txdlh = 0x"VXGE_OS_STXFMT", vaddr = 0x"VXGE_OS_STXFMT", "
1158 	    "size = %d", (ptr_t) vpath_handle, (ptr_t) txdlh,
1159 	    (ptr_t) vaddr, size);
1160 
1161 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1162 
1163 	vxge_assert(fifo != NULL);
1164 
1165 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1166 
1167 	/* LINTED */
1168 	used = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
1169 	used += txdl_priv->align_dma_offset;
1170 
1171 	if (used + (unsigned int)size > (unsigned int)fifo->align_size)
1172 		return (VXGE_HAL_ERR_OUT_ALIGNED_FRAGS);
1173 
1174 	vxge_os_memcpy((char *) txdl_priv->align_vaddr_start +
1175 	    txdl_priv->align_dma_offset, vaddr, size);
1176 
1177 	fifo->stats->copied_frags++;
1178 
1179 	txdl_priv->align_dma_offset += size;
1180 
1181 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1182 	    __FILE__, __func__, __LINE__);
1183 	return (VXGE_HAL_OK);
1184 }
1185 
1186 /*
1187  * vxge_hal_fifo_txdl_buffer_finalize - Prepares a descriptor that contains the
1188  * single physically contiguous buffer.
1189  *
1190  * @vpath_handle: Virtual path handle.
1191  * @txdlh: Descriptor handle.
1192  * @frag_idx: Index of the data buffer in the Txdl list.
1193  *
1194  * This API in conjunction with vxge_hal_fifo_txdl_buffer_append() prepares
1195  * a descriptor that consists of a single physically contiguous buffer
1196  * which inturn contains the contents of one or more virtually contiguous
1197  * buffers received from the upper layer.
1198  *
1199  * See Also: vxge_hal_fifo_txdl_buffer_append().
1200  */
1201 void
vxge_hal_fifo_txdl_buffer_finalize(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,u32 frag_idx)1202 vxge_hal_fifo_txdl_buffer_finalize(
1203     vxge_hal_vpath_h vpath_handle,
1204     vxge_hal_txdl_h txdlh,
1205     u32 frag_idx)
1206 {
1207 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1208 	__hal_fifo_t *fifo;
1209 	__hal_device_t *hldev;
1210 	__hal_fifo_txdl_priv_t *txdl_priv;
1211 	vxge_hal_fifo_txd_t *txdp;
1212 	ptrdiff_t prev_boff;
1213 
1214 	vxge_assert((vpath_handle != NULL) &&
1215 	    (txdlh != NULL) && (frag_idx != 0));
1216 
1217 	hldev = vp->vpath->hldev;
1218 
1219 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1220 	    __FILE__, __func__, __LINE__);
1221 
1222 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1223 	    "txdlh = 0x"VXGE_OS_STXFMT", frag_idx = %d", (ptr_t) vpath_handle,
1224 	    (ptr_t) txdlh, frag_idx);
1225 
1226 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1227 
1228 	vxge_assert(fifo != NULL);
1229 
1230 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1231 	txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
1232 
1233 	/* LINTED */
1234 	prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
1235 	txdp->buffer_pointer = (u64) txdl_priv->align_dma_addr + prev_boff;
1236 	txdp->control_0 |=
1237 	    VXGE_HAL_FIFO_TXD_BUFFER_SIZE(txdl_priv->align_dma_offset);
1238 	txdl_priv->bytes_sent += (unsigned int)txdl_priv->align_dma_offset;
1239 	fifo->stats->total_buffers++;
1240 	fifo->stats->copied_buffers++;
1241 	txdl_priv->frags++;
1242 	txdl_priv->align_used_frags++;
1243 
1244 #if defined(VXGE_OS_DMA_REQUIRES_SYNC)
1245 	/* sync pre-mapped buffer */
1246 	vxge_os_dma_sync(fifo->channel.pdev,
1247 	    txdl_priv->align_dma_handle,
1248 	    txdp->buffer_pointer,
1249 	    0,
1250 	    txdl_priv->align_dma_offset,
1251 	    VXGE_OS_DMA_DIR_TODEVICE);
1252 #endif
1253 
1254 	/* increment vaddr_start for the next buffer_append() iteration */
1255 	txdl_priv->align_vaddr_start += txdl_priv->align_dma_offset;
1256 	txdl_priv->align_dma_offset = 0;
1257 
1258 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1259 	    __FILE__, __func__, __LINE__);
1260 }
1261 
1262 /*
1263  * vxge_hal_fifo_txdl_new_frame_set - Start the new packet by setting TXDL flags
1264  * @vpath_handle: virtual path handle.
1265  * @txdlh: Descriptor handle.
1266  * @tagged: Is the frame tagged
1267  *
1268  * This API is part of the preparation of the transmit descriptor for posting
1269  * (via vxge_hal_fifo_txdl_post()). This api is used to mark the end of previous
1270  * frame and start of a new frame.
1271  *
1272  */
1273 void
vxge_hal_fifo_txdl_new_frame_set(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,u32 tagged)1274 vxge_hal_fifo_txdl_new_frame_set(
1275     vxge_hal_vpath_h vpath_handle,
1276     vxge_hal_txdl_h txdlh,
1277     u32 tagged)
1278 {
1279 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1280 	__hal_fifo_t *fifo;
1281 	__hal_device_t *hldev;
1282 	__hal_fifo_txdl_priv_t *txdl_priv;
1283 	vxge_hal_fifo_txd_t *txdp;
1284 
1285 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
1286 
1287 	hldev = vp->vpath->hldev;
1288 
1289 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1290 	    __FILE__, __func__, __LINE__);
1291 
1292 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1293 	    "txdlh = 0x"VXGE_OS_STXFMT", tagged = %d",
1294 	    (ptr_t) vpath_handle, (ptr_t) txdlh, tagged);
1295 
1296 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1297 
1298 	vxge_assert(fifo != NULL);
1299 
1300 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1301 
1302 	txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
1303 
1304 	txdp->control_0 |=
1305 	    VXGE_HAL_FIFO_TXD_HOST_STEER(vp->vpath->vp_config->wire_port);
1306 	txdp->control_0 |= VXGE_HAL_FIFO_TXD_GATHER_CODE(
1307 	    VXGE_HAL_FIFO_TXD_GATHER_CODE_FIRST);
1308 	txdp->control_1 |= fifo->interrupt_type;
1309 	txdp->control_1 |= VXGE_HAL_FIFO_TXD_INT_NUMBER(
1310 	    vp->vpath->tx_intr_num);
1311 	if (tagged)
1312 		txdp->control_1 |= VXGE_HAL_FIFO_TXD_NO_BW_LIMIT;
1313 	if (txdl_priv->frags) {
1314 
1315 		txdp = (vxge_hal_fifo_txd_t *) txdlh + (txdl_priv->frags - 1);
1316 
1317 		txdp->control_0 |= VXGE_HAL_FIFO_TXD_GATHER_CODE(
1318 		    VXGE_HAL_FIFO_TXD_GATHER_CODE_LAST);
1319 
1320 	}
1321 
1322 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1323 	    __FILE__, __func__, __LINE__);
1324 }
1325 
1326 /*
1327  * vxge_hal_fifo_txdl_post - Post descriptor on the fifo channel.
1328  * @vpath_handle: Virtual path handle.
1329  * @txdlh: Descriptor obtained via vxge_hal_fifo_txdl_reserve()
1330  * @tagged: Is the frame tagged
1331  *
1332  * Post descriptor on the 'fifo' type channel for transmission.
1333  * Prior to posting the descriptor should be filled in accordance with
1334  * Host/X3100 interface specification for a given service (LL, etc.).
1335  *
1336  */
1337 void
vxge_hal_fifo_txdl_post(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,u32 tagged)1338 vxge_hal_fifo_txdl_post(
1339     vxge_hal_vpath_h vpath_handle,
1340     vxge_hal_txdl_h txdlh,
1341     u32 tagged)
1342 {
1343 	u64 list_ptr;
1344 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1345 	__hal_fifo_t *fifo;
1346 	__hal_device_t *hldev;
1347 	__hal_fifo_txdl_priv_t *txdl_priv;
1348 	vxge_hal_fifo_txd_t *txdp_last;
1349 	vxge_hal_fifo_txd_t *txdp_first;
1350 
1351 #if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1352 	unsigned long flags = 0;
1353 
1354 #endif
1355 
1356 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
1357 
1358 	hldev = vp->vpath->hldev;
1359 
1360 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1361 	    __FILE__, __func__, __LINE__);
1362 
1363 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1364 	    "txdlh = 0x"VXGE_OS_STXFMT", tagged = %d",
1365 	    (ptr_t) vpath_handle, (ptr_t) txdlh, tagged);
1366 
1367 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1368 
1369 	vxge_assert(fifo != NULL);
1370 
1371 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1372 
1373 	txdp_first = (vxge_hal_fifo_txd_t *) txdlh;
1374 	txdp_first->control_0 |=
1375 	    VXGE_HAL_FIFO_TXD_HOST_STEER(vp->vpath->vp_config->wire_port);
1376 	txdp_first->control_0 |=
1377 	    VXGE_HAL_FIFO_TXD_GATHER_CODE(VXGE_HAL_FIFO_TXD_GATHER_CODE_FIRST);
1378 	txdp_first->control_1 |=
1379 	    VXGE_HAL_FIFO_TXD_INT_NUMBER(vp->vpath->tx_intr_num);
1380 	txdp_first->control_1 |= fifo->interrupt_type;
1381 	list_ptr = (u64) txdl_priv->dma_addr;
1382 	if (tagged) {
1383 		txdp_first->control_1 |= VXGE_HAL_FIFO_TXD_NO_BW_LIMIT;
1384 		list_ptr |= 0x1;
1385 	}
1386 
1387 	txdp_last =
1388 	    (vxge_hal_fifo_txd_t *) txdlh + (txdl_priv->frags - 1);
1389 	txdp_last->control_0 |=
1390 	    VXGE_HAL_FIFO_TXD_GATHER_CODE(VXGE_HAL_FIFO_TXD_GATHER_CODE_LAST);
1391 
1392 #if defined(VXGE_HAL_TX_MULTI_POST)
1393 	vxge_os_spin_lock(&fifo->channel.post_lock);
1394 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1395 	vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
1396 #endif
1397 
1398 	txdp_first->control_0 |= VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER;
1399 
1400 #if defined(VXGE_DEBUG_ASSERT)
1401 	/* make sure device overwrites the t_code value on completion */
1402 	txdp_first->control_0 |=
1403 	    VXGE_HAL_FIFO_TXD_T_CODE(VXGE_HAL_FIFO_TXD_T_CODE_UNUSED);
1404 #endif
1405 
1406 #if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
1407 	/* sync the TxDL to device */
1408 	vxge_os_dma_sync(fifo->channel.pdev,
1409 	    txdl_priv->dma_handle,
1410 	    txdl_priv->dma_addr,
1411 	    txdl_priv->dma_offset,
1412 	    txdl_priv->frags << 5, /* sizeof(vxge_hal_fifo_txd_t) */
1413 	    VXGE_OS_DMA_DIR_TODEVICE);
1414 #endif
1415 	/*
1416 	 * we want touch dtr_arr in order with ownership bit set to HW
1417 	 */
1418 	__hal_channel_dtr_post(&fifo->channel, VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
1419 
1420 	__hal_non_offload_db_post(vpath_handle,
1421 	    list_ptr,
1422 	    txdl_priv->frags - 1,
1423 	    vp->vpath->vp_config->fifo.no_snoop_bits);
1424 
1425 #if defined(VXGE_HAL_FIFO_DUMP_TXD)
1426 	vxge_hal_info_log_fifo(
1427 	    ""VXGE_OS_LLXFMT":"VXGE_OS_LLXFMT":"VXGE_OS_LLXFMT":"
1428 	    VXGE_OS_LLXFMT" dma "VXGE_OS_LLXFMT,
1429 	    txdp_first->control_0, txdp_first->control_1,
1430 	    txdp_first->buffer_pointer, VXGE_HAL_FIFO_TXDL_INDEX(txdp_first),
1431 	    txdl_priv->dma_addr);
1432 #endif
1433 
1434 	fifo->stats->total_posts++;
1435 	fifo->stats->common_stats.usage_cnt++;
1436 	if (fifo->stats->common_stats.usage_max <
1437 	    fifo->stats->common_stats.usage_cnt)
1438 		fifo->stats->common_stats.usage_max =
1439 		    fifo->stats->common_stats.usage_cnt;
1440 
1441 #if defined(VXGE_HAL_TX_MULTI_POST)
1442 	vxge_os_spin_unlock(&fifo->channel.post_lock);
1443 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1444 	vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
1445 #endif
1446 
1447 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1448 	    __FILE__, __func__, __LINE__);
1449 }
1450 
1451 /*
1452  * vxge_hal_fifo_is_next_txdl_completed - Checks if the next txdl is completed
1453  * @vpath_handle: Virtual path handle.
1454  */
1455 vxge_hal_status_e
vxge_hal_fifo_is_next_txdl_completed(vxge_hal_vpath_h vpath_handle)1456 vxge_hal_fifo_is_next_txdl_completed(vxge_hal_vpath_h vpath_handle)
1457 {
1458 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1459 	__hal_fifo_t *fifo;
1460 	__hal_device_t *hldev;
1461 	vxge_hal_fifo_txd_t *txdp;
1462 	vxge_hal_txdl_h txdlh;
1463 	vxge_hal_status_e status = VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
1464 
1465 #if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1466 	unsigned long flags = 0;
1467 
1468 #endif
1469 
1470 
1471 	vxge_assert(vpath_handle != NULL);
1472 
1473 	hldev = vp->vpath->hldev;
1474 
1475 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1476 	    __FILE__, __func__, __LINE__);
1477 
1478 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
1479 	    (ptr_t) vpath_handle);
1480 
1481 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1482 
1483 	vxge_assert(fifo != NULL);
1484 
1485 #if defined(VXGE_HAL_TX_MULTI_POST)
1486 	vxge_os_spin_lock(&fifo->channel.post_lock);
1487 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1488 	vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
1489 #endif
1490 
1491 	__hal_channel_dtr_try_complete(&fifo->channel, &txdlh);
1492 
1493 	txdp = (vxge_hal_fifo_txd_t *) txdlh;
1494 	if ((txdp != NULL) &&
1495 	    (!(txdp->control_0 & VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER))) {
1496 		status = VXGE_HAL_OK;
1497 	}
1498 
1499 #if defined(VXGE_HAL_TX_MULTI_POST)
1500 	vxge_os_spin_unlock(&fifo->channel.post_lock);
1501 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1502 	vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
1503 #endif
1504 
1505 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
1506 	    __FILE__, __func__, __LINE__, status);
1507 
1508 	/* no more completions */
1509 	return (status);
1510 }
1511 
1512 /*
1513  * vxge_hal_fifo_txdl_next_completed - Retrieve next completed descriptor.
1514  * @vpath_handle: Virtual path handle.
1515  * @txdlh: Descriptor handle. Returned by HAL.
1516  * @txdl_priv: Buffer to return the pointer to per txdl space
1517  * @t_code: Transfer code, as per X3100 User Guide,
1518  *	 Transmit Descriptor Format.
1519  *	 Returned by HAL.
1520  *
1521  * Retrieve the _next_ completed descriptor.
1522  * HAL uses channel callback (*vxge_hal_channel_callback_f) to notifiy
1523  * upper-layer driver (ULD) of new completed descriptors. After that
1524  * the ULD can use vxge_hal_fifo_txdl_next_completed to retrieve the rest
1525  * completions (the very first completion is passed by HAL via
1526  * vxge_hal_channel_callback_f).
1527  *
1528  * Implementation-wise, the upper-layer driver is free to call
1529  * vxge_hal_fifo_txdl_next_completed either immediately from inside the
1530  * channel callback, or in a deferred fashion and separate (from HAL)
1531  * context.
1532  *
1533  * Non-zero @t_code means failure to process the descriptor.
1534  * The failure could happen, for instance, when the link is
1535  * down, in which case X3100 completes the descriptor because it
1536  * is not able to send the data out.
1537  *
1538  * For details please refer to X3100 User Guide.
1539  *
1540  * Returns: VXGE_HAL_OK - success.
1541  * VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
1542  * are currently available for processing.
1543  *
1544  */
1545 vxge_hal_status_e
vxge_hal_fifo_txdl_next_completed(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h * txdlh,void ** txdl_priv,vxge_hal_fifo_tcode_e * t_code)1546 vxge_hal_fifo_txdl_next_completed(
1547     vxge_hal_vpath_h vpath_handle,
1548     vxge_hal_txdl_h * txdlh,
1549     void **txdl_priv,
1550     vxge_hal_fifo_tcode_e * t_code)
1551 {
1552 	__hal_fifo_t *fifo;
1553 	__hal_device_t *hldev;
1554 	vxge_hal_fifo_txd_t *txdp;
1555 
1556 #if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
1557 	__hal_fifo_txdl_priv_t *priv;
1558 
1559 #endif
1560 #if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1561 	unsigned long flags = 0;
1562 
1563 #endif
1564 
1565 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1566 	vxge_hal_status_e status = VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
1567 
1568 	vxge_assert((vpath_handle != NULL) &&
1569 	    (txdlh != NULL) && (t_code != NULL));
1570 
1571 	hldev = vp->vpath->hldev;
1572 
1573 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1574 	    __FILE__, __func__, __LINE__);
1575 
1576 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1577 	    "txdlh = 0x"VXGE_OS_STXFMT", t_code = 0x"VXGE_OS_STXFMT,
1578 	    (ptr_t) vpath_handle, (ptr_t) txdlh, (ptr_t) t_code);
1579 
1580 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1581 
1582 	vxge_assert(fifo != NULL);
1583 
1584 	*txdlh = 0;
1585 
1586 #if defined(VXGE_HAL_TX_MULTI_POST)
1587 	vxge_os_spin_lock(&fifo->channel.post_lock);
1588 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1589 	vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
1590 #endif
1591 
1592 	__hal_channel_dtr_try_complete(&fifo->channel, txdlh);
1593 
1594 	txdp = (vxge_hal_fifo_txd_t *) * txdlh;
1595 	if (txdp != NULL) {
1596 
1597 #if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
1598 		priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
1599 
1600 		/*
1601 		 * sync TxDL to read the ownership
1602 		 *
1603 		 * Note: 16bytes means Control_1 & Control_2
1604 		 */
1605 		vxge_os_dma_sync(fifo->channel.pdev,
1606 		    priv->dma_handle,
1607 		    priv->dma_addr,
1608 		    priv->dma_offset,
1609 		    16,
1610 		    VXGE_OS_DMA_DIR_FROMDEVICE);
1611 #endif
1612 
1613 		/* check whether host owns it */
1614 		if (!(txdp->control_0 & VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER)) {
1615 
1616 			__hal_channel_dtr_complete(&fifo->channel);
1617 
1618 			*txdl_priv = VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp);
1619 
1620 			*t_code = (vxge_hal_fifo_tcode_e)
1621 			    VXGE_HAL_FIFO_TXD_T_CODE_GET(txdp->control_0);
1622 
1623 			if (fifo->stats->common_stats.usage_cnt > 0)
1624 				fifo->stats->common_stats.usage_cnt--;
1625 
1626 			status = VXGE_HAL_OK;
1627 		}
1628 	}
1629 
1630 	/* no more completions */
1631 #if defined(VXGE_HAL_TX_MULTI_POST)
1632 	vxge_os_spin_unlock(&fifo->channel.post_lock);
1633 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1634 	vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
1635 #endif
1636 
1637 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
1638 	    __FILE__, __func__, __LINE__, status);
1639 
1640 	return (status);
1641 }
1642 
1643 /*
1644  * vxge_hal_fifo_handle_tcode - Handle transfer code.
1645  * @vpath_handle: Virtual Path handle.
1646  * @txdlh: Descriptor handle.
1647  * @t_code: One of the enumerated (and documented in the X3100 user guide)
1648  *	 "transfer codes".
1649  *
1650  * Handle descriptor's transfer code. The latter comes with each completed
1651  * descriptor.
1652  *
1653  * Returns: one of the vxge_hal_status_e {} enumerated types.
1654  * VXGE_HAL_OK			- for success.
1655  * VXGE_HAL_ERR_CRITICAL	- when encounters critical error.
1656  */
1657 vxge_hal_status_e
vxge_hal_fifo_handle_tcode(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh,vxge_hal_fifo_tcode_e t_code)1658 vxge_hal_fifo_handle_tcode(
1659     vxge_hal_vpath_h vpath_handle,
1660     vxge_hal_txdl_h txdlh,
1661     vxge_hal_fifo_tcode_e t_code)
1662 {
1663 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1664 	__hal_device_t *hldev;
1665 
1666 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
1667 
1668 	hldev = vp->vpath->hldev;
1669 
1670 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1671 	    __FILE__, __func__, __LINE__);
1672 
1673 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1674 	    "txdlh = 0x"VXGE_OS_STXFMT", t_code = 0x%d",
1675 	    (ptr_t) vpath_handle, (ptr_t) txdlh, t_code);
1676 
1677 	switch ((t_code & 0x7)) {
1678 	case 0:
1679 		/* 000: Transfer operation completed successfully. */
1680 		break;
1681 	case 1:
1682 		/*
1683 		 * 001: a PCI read transaction (either TxD or frame data)
1684 		 *	returned with corrupt data.
1685 		 */
1686 		break;
1687 	case 2:
1688 		/* 010: a PCI read transaction was returned with no data. */
1689 		break;
1690 	case 3:
1691 		/*
1692 		 * 011: The host attempted to send either a frame or LSO
1693 		 *	MSS that was too long (>9800B).
1694 		 */
1695 		break;
1696 	case 4:
1697 		/*
1698 		 * 100: Error detected during TCP/UDP Large Send
1699 		 *	Offload operation, due to improper header template,
1700 		 *	unsupported protocol, etc.
1701 		 */
1702 		break;
1703 	default:
1704 		vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
1705 		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_INVALID_TCODE);
1706 		return (VXGE_HAL_ERR_INVALID_TCODE);
1707 	}
1708 
1709 	vp->vpath->sw_stats->fifo_stats.txd_t_code_err_cnt[t_code]++;
1710 
1711 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: %d",
1712 	    __FILE__, __func__, __LINE__, VXGE_HAL_OK);
1713 	return (VXGE_HAL_OK);
1714 }
1715 
1716 /*
1717  * __hal_fifo_txdl_free_many - Free the fragments
1718  * @fifo: FIFO
1719  * @txdp: Poniter to a TxD
1720  * @list_size: List size
1721  * @frags: Number of fragments
1722  *
1723  * This routinf frees the fragments in a txdl
1724  */
1725 void
__hal_fifo_txdl_free_many(__hal_fifo_t * fifo,vxge_hal_fifo_txd_t * txdp,u32 list_size,u32 frags)1726 __hal_fifo_txdl_free_many(
1727     __hal_fifo_t *fifo,
1728     vxge_hal_fifo_txd_t * txdp,
1729     u32 list_size,
1730     u32 frags)
1731 {
1732 	__hal_fifo_txdl_priv_t *current_txdl_priv;
1733 	__hal_fifo_txdl_priv_t *next_txdl_priv;
1734 	u32 invalid_frags = frags % list_size;
1735 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) fifo->channel.vph;
1736 	__hal_device_t *hldev;
1737 
1738 	vxge_assert((fifo != NULL) && (txdp != NULL));
1739 
1740 	hldev = vp->vpath->hldev;
1741 
1742 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1743 	    __FILE__, __func__, __LINE__);
1744 
1745 	vxge_hal_trace_log_fifo(
1746 	    "fifo = 0x"VXGE_OS_STXFMT", txdp = 0x"VXGE_OS_STXFMT", "
1747 	    "list_size = %d, frags = %d", (ptr_t) fifo, (ptr_t) txdp,
1748 	    list_size, frags);
1749 
1750 	if (invalid_frags) {
1751 		vxge_hal_trace_log_fifo(
1752 		    "freeing corrupt txdlh 0x"VXGE_OS_STXFMT", "
1753 		    "fragments %d list size %d",
1754 		    (ptr_t) txdp, frags, list_size);
1755 		vxge_assert(invalid_frags == 0);
1756 	}
1757 	while (txdp) {
1758 		vxge_hal_trace_log_fifo("freeing linked txdlh 0x"VXGE_OS_STXFMT
1759 		    ", " "fragments %d list size %d",
1760 		    (ptr_t) txdp, frags, list_size);
1761 		current_txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
1762 #if defined(VXGE_DEBUG_ASSERT) && defined(VXGE_OS_MEMORY_CHECK)
1763 		current_txdl_priv->allocated = 0;
1764 #endif
1765 		__hal_channel_dtr_free(&fifo->channel,
1766 		    VXGE_HAL_FIFO_TXDL_INDEX(txdp));
1767 		next_txdl_priv = current_txdl_priv->next_txdl_priv;
1768 		vxge_assert(frags);
1769 		frags -= list_size;
1770 		if (next_txdl_priv) {
1771 			current_txdl_priv->next_txdl_priv = NULL;
1772 			txdp = next_txdl_priv->first_txdp;
1773 		} else {
1774 			vxge_hal_trace_log_fifo(
1775 			    "freed linked txdlh fragments %d list size %d",
1776 			    frags, list_size);
1777 			break;
1778 		}
1779 	}
1780 
1781 	vxge_assert(frags == 0);
1782 
1783 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1784 	    __FILE__, __func__, __LINE__);
1785 }
1786 
1787 /*
1788  * vxge_hal_fifo_txdl_free - Free descriptor.
1789  * @vpath_handle: Virtual path handle.
1790  * @txdlh: Descriptor handle.
1791  *
1792  * Free the reserved descriptor. This operation is "symmetrical" to
1793  * vxge_hal_fifo_txdl_reserve. The "free-ing" completes the descriptor's
1794  * lifecycle.
1795  *
1796  * After free-ing (see vxge_hal_fifo_txdl_free()) the descriptor again can
1797  * be:
1798  *
1799  * - reserved (vxge_hal_fifo_txdl_reserve);
1800  *
1801  * - posted (vxge_hal_fifo_txdl_post);
1802  *
1803  * - completed (vxge_hal_fifo_txdl_next_completed);
1804  *
1805  * - and recycled again (vxge_hal_fifo_txdl_free).
1806  *
1807  * For alternative state transitions and more details please refer to
1808  * the design doc.
1809  *
1810  */
1811 void
vxge_hal_fifo_txdl_free(vxge_hal_vpath_h vpath_handle,vxge_hal_txdl_h txdlh)1812 vxge_hal_fifo_txdl_free(
1813     vxge_hal_vpath_h vpath_handle,
1814     vxge_hal_txdl_h txdlh)
1815 {
1816 	__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
1817 	__hal_fifo_t *fifo;
1818 	__hal_device_t *hldev;
1819 	__hal_fifo_txdl_priv_t *txdl_priv;
1820 	u32 max_frags;
1821 
1822 #if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1823 	u32 flags = 0;
1824 
1825 #endif
1826 	vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
1827 
1828 	hldev = vp->vpath->hldev;
1829 
1830 	vxge_hal_trace_log_fifo("==> %s:%s:%d",
1831 	    __FILE__, __func__, __LINE__);
1832 
1833 	vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
1834 	    "txdlh = 0x"VXGE_OS_STXFMT, (ptr_t) vpath_handle, (ptr_t) txdlh);
1835 
1836 	fifo = (__hal_fifo_t *) vp->vpath->fifoh;
1837 
1838 	vxge_assert(fifo != NULL);
1839 
1840 	txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
1841 
1842 	max_frags = fifo->config->max_frags;
1843 
1844 #if defined(VXGE_HAL_TX_MULTI_POST)
1845 	vxge_os_spin_lock(&fifo->channel.post_lock);
1846 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1847 	vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
1848 #endif
1849 
1850 	if (txdl_priv->alloc_frags > max_frags) {
1851 		vxge_hal_fifo_txd_t *dang_txdp = (vxge_hal_fifo_txd_t *)
1852 		txdl_priv->dang_txdl;
1853 		u32 dang_frags = txdl_priv->dang_frags;
1854 		u32 alloc_frags = txdl_priv->alloc_frags;
1855 		txdl_priv->dang_txdl = NULL;
1856 		txdl_priv->dang_frags = 0;
1857 		txdl_priv->alloc_frags = 0;
1858 		/* txdlh must have a linked list of txdlh */
1859 		vxge_assert(txdl_priv->next_txdl_priv);
1860 
1861 		/* free any dangling txdlh first */
1862 		if (dang_txdp) {
1863 			vxge_hal_info_log_fifo(
1864 			    "freeing dangled txdlh 0x"VXGE_OS_STXFMT" for %d "
1865 			    "fragments", (ptr_t) dang_txdp, dang_frags);
1866 			__hal_fifo_txdl_free_many(fifo, dang_txdp,
1867 			    max_frags, dang_frags);
1868 		}
1869 
1870 		/* now free the reserved txdlh list */
1871 		vxge_hal_info_log_fifo(
1872 		    "freeing txdlh 0x"VXGE_OS_STXFMT" list of %d fragments",
1873 		    (ptr_t) txdlh, alloc_frags);
1874 		__hal_fifo_txdl_free_many(fifo,
1875 		    (vxge_hal_fifo_txd_t *) txdlh, max_frags,
1876 		    alloc_frags);
1877 	} else {
1878 		__hal_channel_dtr_free(&fifo->channel,
1879 		    VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
1880 	}
1881 
1882 	fifo->channel.poll_bytes += txdl_priv->bytes_sent;
1883 
1884 #if defined(VXGE_DEBUG_ASSERT) && defined(VXGE_OS_MEMORY_CHECK)
1885 	txdl_priv->allocated = 0;
1886 #endif
1887 
1888 #if defined(VXGE_HAL_TX_MULTI_POST)
1889 	vxge_os_spin_unlock(&fifo->channel.post_lock);
1890 #elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
1891 	vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
1892 #endif
1893 
1894 	vxge_hal_trace_log_fifo("<== %s:%s:%d  Result: 0",
1895 	    __FILE__, __func__, __LINE__);
1896 }
1897