1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright (c) 2002-2006 Neterion, Inc.
22 */
23
24 #include "xgehal-channel.h"
25 #include "xgehal-fifo.h"
26 #include "xgehal-ring.h"
27 #include "xgehal-device.h"
28 #include "xgehal-regs.h"
29
30 /*
31 * __hal_channel_dtr_next_reservelist
32 *
33 * Walking through the all available DTRs.
34 */
35 static xge_hal_status_e
__hal_channel_dtr_next_reservelist(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)36 __hal_channel_dtr_next_reservelist(xge_hal_channel_h channelh,
37 xge_hal_dtr_h *dtrh)
38 {
39 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
40
41 if (channel->reserve_top >= channel->reserve_length) {
42 return XGE_HAL_INF_NO_MORE_FREED_DESCRIPTORS;
43 }
44
45 *dtrh = channel->reserve_arr[channel->reserve_top++];
46
47 return XGE_HAL_OK;
48 }
49
50 /*
51 * __hal_channel_dtr_next_freelist
52 *
53 * Walking through the "freed" DTRs.
54 */
55 static xge_hal_status_e
__hal_channel_dtr_next_freelist(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)56 __hal_channel_dtr_next_freelist(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
57 {
58 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
59
60 if (channel->reserve_initial == channel->free_length) {
61 return XGE_HAL_INF_NO_MORE_FREED_DESCRIPTORS;
62 }
63
64 *dtrh = channel->free_arr[channel->free_length++];
65
66 return XGE_HAL_OK;
67 }
68
69 /*
70 * __hal_channel_dtr_next_not_completed - Get the _next_ posted but
71 * not completed descriptor.
72 *
73 * Walking through the "not completed" DTRs.
74 */
75 static xge_hal_status_e
__hal_channel_dtr_next_not_completed(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)76 __hal_channel_dtr_next_not_completed(xge_hal_channel_h channelh,
77 xge_hal_dtr_h *dtrh)
78 {
79 /* LINTED E_FUNC_SET_NOT_USED */
80 xge_hal_ring_rxd_1_t *rxdp; /* doesn't matter 1, 3 or 5... */
81
82 __hal_channel_dtr_try_complete(channelh, dtrh);
83 if (*dtrh == NULL) {
84 return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
85 }
86
87 rxdp = (xge_hal_ring_rxd_1_t *)*dtrh;
88 xge_assert(rxdp->host_control!=0);
89
90 __hal_channel_dtr_complete(channelh);
91
92 return XGE_HAL_OK;
93 }
94
95 xge_hal_channel_t*
__hal_channel_allocate(xge_hal_device_h devh,int post_qid,xge_hal_channel_type_e type)96 __hal_channel_allocate(xge_hal_device_h devh, int post_qid,
97 xge_hal_channel_type_e type)
98 {
99 xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
100 xge_hal_channel_t *channel;
101 int size = 0;
102
103 switch(type) {
104 case XGE_HAL_CHANNEL_TYPE_FIFO:
105 xge_assert(post_qid + 1 >= XGE_HAL_MIN_FIFO_NUM &&
106 post_qid + 1 <= XGE_HAL_MAX_FIFO_NUM);
107 size = sizeof(xge_hal_fifo_t);
108 break;
109 case XGE_HAL_CHANNEL_TYPE_RING:
110 xge_assert(post_qid + 1 >= XGE_HAL_MIN_RING_NUM &&
111 post_qid + 1 <= XGE_HAL_MAX_RING_NUM);
112 size = sizeof(xge_hal_ring_t);
113 break;
114 default :
115 xge_assert(size);
116 break;
117
118 }
119
120
121 /* allocate FIFO channel */
122 channel = (xge_hal_channel_t *) xge_os_malloc(hldev->pdev, size);
123 if (channel == NULL) {
124 return NULL;
125 }
126 xge_os_memzero(channel, size);
127
128 channel->pdev = hldev->pdev;
129 channel->regh0 = hldev->regh0;
130 channel->regh1 = hldev->regh1;
131 channel->type = type;
132 channel->devh = devh;
133 channel->post_qid = post_qid;
134 channel->compl_qid = 0;
135
136 return channel;
137 }
138
__hal_channel_free(xge_hal_channel_t * channel)139 void __hal_channel_free(xge_hal_channel_t *channel)
140 {
141 int size = 0;
142
143 xge_assert(channel->pdev);
144
145 switch(channel->type) {
146 case XGE_HAL_CHANNEL_TYPE_FIFO:
147 size = sizeof(xge_hal_fifo_t);
148 break;
149 case XGE_HAL_CHANNEL_TYPE_RING:
150 size = sizeof(xge_hal_ring_t);
151 break;
152 case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
153 case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
154 case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
155 case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
156 case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
157 xge_assert(size);
158 break;
159 default:
160 break;
161 }
162
163 xge_os_free(channel->pdev, channel, size);
164 }
165
166 xge_hal_status_e
__hal_channel_initialize(xge_hal_channel_h channelh,xge_hal_channel_attr_t * attr,void ** reserve_arr,int reserve_initial,int reserve_max,int reserve_threshold)167 __hal_channel_initialize (xge_hal_channel_h channelh,
168 xge_hal_channel_attr_t *attr, void **reserve_arr,
169 int reserve_initial, int reserve_max, int reserve_threshold)
170 {
171 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
172 xge_hal_device_t *hldev;
173
174 hldev = (xge_hal_device_t *)channel->devh;
175
176 channel->dtr_term = attr->dtr_term;
177 channel->dtr_init = attr->dtr_init;
178 channel->callback = attr->callback;
179 channel->userdata = attr->userdata;
180 channel->flags = attr->flags;
181 channel->per_dtr_space = attr->per_dtr_space;
182
183 channel->reserve_arr = reserve_arr;
184 channel->reserve_initial = reserve_initial;
185 channel->reserve_max = reserve_max;
186 channel->reserve_length = channel->reserve_initial;
187 channel->reserve_threshold = reserve_threshold;
188 channel->reserve_top = 0;
189 channel->saved_arr = (void **) xge_os_malloc(hldev->pdev,
190 sizeof(void*)*channel->reserve_max);
191 if (channel->saved_arr == NULL) {
192 return XGE_HAL_ERR_OUT_OF_MEMORY;
193 }
194 xge_os_memzero(channel->saved_arr, sizeof(void*)*channel->reserve_max);
195 channel->free_arr = channel->saved_arr;
196 channel->free_length = channel->reserve_initial;
197 channel->work_arr = (void **) xge_os_malloc(hldev->pdev,
198 sizeof(void*)*channel->reserve_max);
199 if (channel->work_arr == NULL) {
200 return XGE_HAL_ERR_OUT_OF_MEMORY;
201 }
202 xge_os_memzero(channel->work_arr,
203 sizeof(void*)*channel->reserve_max);
204 channel->post_index = 0;
205 channel->compl_index = 0;
206 channel->length = channel->reserve_initial;
207
208 channel->orig_arr = (void **) xge_os_malloc(hldev->pdev,
209 sizeof(void*)*channel->reserve_max);
210 if (channel->orig_arr == NULL)
211 return XGE_HAL_ERR_OUT_OF_MEMORY;
212
213 xge_os_memzero(channel->orig_arr, sizeof(void*)*channel->reserve_max);
214
215 #if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
216 xge_os_spin_lock_init_irq(&channel->free_lock, hldev->irqh);
217 #elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
218 xge_os_spin_lock_init(&channel->free_lock, hldev->pdev);
219 #endif
220
221 return XGE_HAL_OK;
222 }
223
__hal_channel_terminate(xge_hal_channel_h channelh)224 void __hal_channel_terminate(xge_hal_channel_h channelh)
225 {
226 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
227 xge_hal_device_t *hldev;
228
229 hldev = (xge_hal_device_t *)channel->devh;
230
231 xge_assert(channel->pdev);
232 /* undo changes made at channel_initialize() */
233 if (channel->work_arr) {
234 xge_os_free(channel->pdev, channel->work_arr,
235 sizeof(void*)*channel->reserve_max);
236 channel->work_arr = NULL;
237 }
238
239 if (channel->saved_arr) {
240 xge_os_free(channel->pdev, channel->saved_arr,
241 sizeof(void*)*channel->reserve_max);
242 channel->saved_arr = NULL;
243 }
244
245 if (channel->orig_arr) {
246 xge_os_free(channel->pdev, channel->orig_arr,
247 sizeof(void*)*channel->reserve_max);
248 channel->orig_arr = NULL;
249 }
250
251 #if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
252 xge_os_spin_lock_destroy_irq(&channel->free_lock, hldev->irqh);
253 #elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
254 xge_os_spin_lock_destroy(&channel->free_lock, hldev->pdev);
255 #endif
256 }
257
258 /**
259 * xge_hal_channel_open - Open communication channel.
260 * @devh: HAL device, pointer to xge_hal_device_t structure.
261 * @attr: Contains attributes required to open
262 * the channel.
263 * @channelh: The channel handle. On success (XGE_HAL_OK) HAL fills
264 * this "out" parameter with a valid channel handle.
265 * @reopen: See xge_hal_channel_reopen_e{}.
266 *
267 * Open communication channel with the device.
268 *
269 * HAL uses (persistent) channel configuration to allocate both channel
270 * and Xframe Tx and Rx descriptors.
271 * Notes:
272 * 1) The channel config data is fed into HAL prior to
273 * xge_hal_channel_open().
274 *
275 * 2) The corresponding hardware queues must be already configured and
276 * enabled.
277 *
278 * 3) Either down or up queue may be omitted, in which case the channel
279 * is treated as _unidirectional_.
280 *
281 * 4) Post and completion queue may be the same, in which case the channel
282 * is said to have "in-band completions".
283 *
284 * Note that free_channels list is not protected. i.e. caller must provide
285 * safe context.
286 *
287 * Returns: XGE_HAL_OK - success.
288 * XGE_HAL_ERR_CHANNEL_NOT_FOUND - Unable to locate the channel.
289 * XGE_HAL_ERR_OUT_OF_MEMORY - Memory allocation failed.
290 *
291 * See also: xge_hal_channel_attr_t{}.
292 * Usage: See ex_open{}.
293 */
294 xge_hal_status_e
xge_hal_channel_open(xge_hal_device_h devh,xge_hal_channel_attr_t * attr,xge_hal_channel_h * channelh,xge_hal_channel_reopen_e reopen)295 xge_hal_channel_open(xge_hal_device_h devh,
296 xge_hal_channel_attr_t *attr,
297 xge_hal_channel_h *channelh,
298 xge_hal_channel_reopen_e reopen)
299 {
300 xge_list_t *item;
301 int i;
302 xge_hal_status_e status = XGE_HAL_OK;
303 xge_hal_channel_t *channel = NULL;
304 xge_hal_device_t *device = (xge_hal_device_t *)devh;
305
306 xge_assert(device);
307 xge_assert(attr);
308
309 *channelh = NULL;
310
311 /* find channel */
312 xge_list_for_each(item, &device->free_channels) {
313 xge_hal_channel_t *tmp;
314
315 tmp = xge_container_of(item, xge_hal_channel_t, item);
316 if (tmp->type == attr->type &&
317 tmp->post_qid == attr->post_qid &&
318 tmp->compl_qid == attr->compl_qid) {
319 channel = tmp;
320 break;
321 }
322 }
323
324 if (channel == NULL) {
325 return XGE_HAL_ERR_CHANNEL_NOT_FOUND;
326 }
327
328 xge_assert((channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) ||
329 (channel->type == XGE_HAL_CHANNEL_TYPE_RING));
330
331 if (reopen == XGE_HAL_CHANNEL_OC_NORMAL) {
332 /* allocate memory, initialize pointers, etc */
333 switch(channel->type) {
334 case XGE_HAL_CHANNEL_TYPE_FIFO:
335 status = __hal_fifo_open(channel, attr);
336 break;
337 case XGE_HAL_CHANNEL_TYPE_RING:
338 status = __hal_ring_open(channel, attr);
339 break;
340 case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
341 case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
342 case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
343 case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
344 case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
345 status = XGE_HAL_FAIL;
346 break;
347 default:
348 break;
349 }
350
351 if (status == XGE_HAL_OK) {
352 for (i = 0; i < channel->reserve_initial; i++) {
353 channel->orig_arr[i] =
354 channel->reserve_arr[i];
355 }
356 }
357 else
358 return status;
359 } else {
360 xge_assert(reopen == XGE_HAL_CHANNEL_RESET_ONLY);
361
362 for (i = 0; i < channel->reserve_initial; i++) {
363 channel->reserve_arr[i] = channel->orig_arr[i];
364 channel->free_arr[i] = NULL;
365 }
366 channel->free_length = channel->reserve_initial;
367 channel->reserve_length = channel->reserve_initial;
368 channel->reserve_top = 0;
369 channel->post_index = 0;
370 channel->compl_index = 0;
371 if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
372 status = __hal_ring_initial_replenish(channel,
373 reopen);
374 if (status != XGE_HAL_OK)
375 return status;
376 }
377 }
378
379 /* move channel to the open state list */
380
381 switch(channel->type) {
382 case XGE_HAL_CHANNEL_TYPE_FIFO:
383 xge_list_remove(&channel->item);
384 xge_list_insert(&channel->item, &device->fifo_channels);
385 break;
386 case XGE_HAL_CHANNEL_TYPE_RING:
387 xge_list_remove(&channel->item);
388 xge_list_insert(&channel->item, &device->ring_channels);
389 break;
390 case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
391 case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
392 case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
393 case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
394 case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
395 xge_assert(channel->type == XGE_HAL_CHANNEL_TYPE_FIFO ||
396 channel->type == XGE_HAL_CHANNEL_TYPE_RING);
397 break;
398 default:
399 break;
400 }
401 channel->is_open = 1;
402 channel->terminating = 0;
403 /*
404 * The magic check the argument validity, has to be
405 * removed before 03/01/2005.
406 */
407 channel->magic = XGE_HAL_MAGIC;
408
409 *channelh = channel;
410
411 return XGE_HAL_OK;
412 }
413
414 /**
415 * xge_hal_channel_abort - Abort the channel.
416 * @channelh: Channel handle.
417 * @reopen: See xge_hal_channel_reopen_e{}.
418 *
419 * Terminate (via xge_hal_channel_dtr_term_f{}) all channel descriptors.
420 * Currently used internally only by HAL, as part of its
421 * xge_hal_channel_close() and xge_hal_channel_open() in case
422 * of fatal error.
423 *
424 * See also: xge_hal_channel_dtr_term_f{}.
425 */
xge_hal_channel_abort(xge_hal_channel_h channelh,xge_hal_channel_reopen_e reopen)426 void xge_hal_channel_abort(xge_hal_channel_h channelh,
427 xge_hal_channel_reopen_e reopen)
428 {
429 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
430 xge_hal_dtr_h dtr;
431 #ifdef XGE_OS_MEMORY_CHECK
432 int check_cnt = 0;
433 #endif
434 int free_length_sav;
435 int reserve_top_sav;
436
437 if (channel->dtr_term == NULL) {
438 return;
439 }
440
441 free_length_sav = channel->free_length;
442 while (__hal_channel_dtr_next_freelist(channelh, &dtr) == XGE_HAL_OK) {
443 #ifdef XGE_OS_MEMORY_CHECK
444 #ifdef XGE_DEBUG_ASSERT
445 if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
446 xge_assert(!__hal_fifo_txdl_priv(dtr)->allocated);
447 } else {
448 if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
449 xge_assert(!__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)->allocated);
450 }
451 }
452 #endif
453 check_cnt++;
454 #endif
455 channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_FREED,
456 channel->userdata, reopen);
457 }
458 channel->free_length = free_length_sav;
459
460 while (__hal_channel_dtr_next_not_completed(channelh, &dtr) ==
461 XGE_HAL_OK) {
462 #ifdef XGE_OS_MEMORY_CHECK
463 #ifdef XGE_DEBUG_ASSERT
464 if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
465 xge_assert(__hal_fifo_txdl_priv(dtr)->allocated);
466 } else {
467 if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
468 xge_assert(__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)
469 ->allocated);
470 }
471 }
472 #endif
473 check_cnt++;
474 #endif
475 channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_POSTED,
476 channel->userdata, reopen);
477
478 }
479
480 reserve_top_sav = channel->reserve_top;
481 while (__hal_channel_dtr_next_reservelist(channelh, &dtr) ==
482 XGE_HAL_OK) {
483 #ifdef XGE_OS_MEMORY_CHECK
484 #ifdef XGE_DEBUG_ASSERT
485 if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
486 xge_assert(!__hal_fifo_txdl_priv(dtr)->allocated);
487 } else {
488 if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
489 xge_assert(!__hal_ring_rxd_priv((xge_hal_ring_t * ) channelh, dtr)->allocated);
490 }
491 }
492 #endif
493 check_cnt++;
494 #endif
495 channel->dtr_term(channel, dtr, XGE_HAL_DTR_STATE_AVAIL,
496 channel->userdata, reopen);
497 }
498 channel->reserve_top = reserve_top_sav;
499
500 xge_assert(channel->reserve_length ==
501 (channel->free_length + channel->reserve_top));
502
503 #ifdef XGE_OS_MEMORY_CHECK
504 xge_assert(check_cnt == channel->reserve_initial);
505 #endif
506
507 }
508
509 /**
510 * xge_hal_channel_close - Close communication channel.
511 * @channelh: The channel handle.
512 * @reopen: See xge_hal_channel_reopen_e{}.
513 *
514 * Will close previously opened channel and deallocate associated resources.
515 * Channel must be opened otherwise assert will be generated.
516 * Note that free_channels list is not protected. i.e. caller must provide
517 * safe context.
518 */
xge_hal_channel_close(xge_hal_channel_h channelh,xge_hal_channel_reopen_e reopen)519 void xge_hal_channel_close(xge_hal_channel_h channelh,
520 xge_hal_channel_reopen_e reopen)
521 {
522 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
523 xge_hal_device_t *hldev;
524 xge_list_t *item;
525 xge_assert(channel);
526 xge_assert(channel->type < XGE_HAL_CHANNEL_TYPE_MAX);
527
528 hldev = (xge_hal_device_t *)channel->devh;
529 channel->is_open = 0;
530 channel->magic = XGE_HAL_DEAD;
531
532 /* sanity check: make sure channel is not in free list */
533 xge_list_for_each(item, &hldev->free_channels) {
534 xge_hal_channel_t *tmp;
535
536 tmp = xge_container_of(item, xge_hal_channel_t, item);
537 xge_assert(!tmp->is_open);
538 if (channel == tmp) {
539 return;
540 }
541 }
542
543 xge_hal_channel_abort(channel, reopen);
544
545 xge_assert((channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) ||
546 (channel->type == XGE_HAL_CHANNEL_TYPE_RING));
547
548 if (reopen == XGE_HAL_CHANNEL_OC_NORMAL) {
549 /* de-allocate */
550 switch(channel->type) {
551 case XGE_HAL_CHANNEL_TYPE_FIFO:
552 __hal_fifo_close(channelh);
553 break;
554 case XGE_HAL_CHANNEL_TYPE_RING:
555 __hal_ring_close(channelh);
556 break;
557 case XGE_HAL_CHANNEL_TYPE_SEND_QUEUE:
558 case XGE_HAL_CHANNEL_TYPE_RECEIVE_QUEUE:
559 case XGE_HAL_CHANNEL_TYPE_COMPLETION_QUEUE:
560 case XGE_HAL_CHANNEL_TYPE_UP_MESSAGE_QUEUE:
561 case XGE_HAL_CHANNEL_TYPE_DOWN_MESSAGE_QUEUE:
562 xge_assert(channel->type == XGE_HAL_CHANNEL_TYPE_FIFO ||
563 channel->type == XGE_HAL_CHANNEL_TYPE_RING);
564 break;
565 default:
566 break;
567 }
568 }
569
570 /* move channel back to free state list */
571 xge_list_remove(&channel->item);
572 xge_list_insert(&channel->item, &hldev->free_channels);
573
574 if (xge_list_is_empty(&hldev->fifo_channels) &&
575 xge_list_is_empty(&hldev->ring_channels)) {
576 /* clear msix_idx in case of following HW reset */
577 hldev->reset_needed_after_close = 1;
578 }
579 }
580