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