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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * hci1394_ixl_misc.c
31 * Isochronous IXL miscellaneous routines.
32 * Contains common routines used by the ixl compiler, interrupt handler and
33 * dynamic update.
34 */
35
36 #include <sys/kmem.h>
37 #include <sys/types.h>
38 #include <sys/conf.h>
39
40 #include <sys/tnf_probe.h>
41
42 #include <sys/1394/h1394.h>
43 #include <sys/1394/ixl1394.h>
44 #include <sys/1394/adapters/hci1394.h>
45
46
47 /* local routines */
48 static void hci1394_delete_dma_desc_mem(hci1394_state_t *soft_statep,
49 hci1394_idma_desc_mem_t *);
50 static void hci1394_delete_xfer_ctl(hci1394_xfer_ctl_t *);
51
52
53 /*
54 * hci1394_ixl_set_start()
55 * Set up the context structure with the first ixl command to process
56 * and the first hci descriptor to execute.
57 *
58 * This function assumes the current context is stopped!
59 *
60 * If ixlstp IS NOT null AND is not the first compiled ixl command and
61 * is not an ixl label command, returns an error.
62 * If ixlstp IS null, uses the first compiled ixl command (ixl_firstp)
63 * in place of ixlstp.
64 *
65 * If no executeable xfer found along exec path from ixlstp, returns error.
66 */
67 int
hci1394_ixl_set_start(hci1394_iso_ctxt_t * ctxtp,ixl1394_command_t * ixlstp)68 hci1394_ixl_set_start(hci1394_iso_ctxt_t *ctxtp, ixl1394_command_t *ixlstp)
69 {
70
71 ixl1394_command_t *ixl_exec_startp;
72
73 TNF_PROBE_0_DEBUG(hci1394_ixl_set_start_enter,
74 HCI1394_TNF_HAL_STACK_ISOCH, "");
75
76 /* if ixl start command is null, use first compiled ixl command */
77 if (ixlstp == NULL) {
78 ixlstp = ctxtp->ixl_firstp;
79 }
80
81 /*
82 * if ixl start command is not first ixl compiled and is not a label,
83 * error
84 */
85 if ((ixlstp != ctxtp->ixl_firstp) && (ixlstp->ixl_opcode !=
86 IXL1394_OP_LABEL)) {
87 TNF_PROBE_0_DEBUG(hci1394_ixl_set_start_exit,
88 HCI1394_TNF_HAL_STACK_ISOCH, "");
89 return (-1);
90 }
91
92 /* follow exec path to find first ixl command that's an xfer command */
93 (void) hci1394_ixl_find_next_exec_xfer(ixlstp, NULL, &ixl_exec_startp);
94
95 /*
96 * if there was one, then in it's compiler private, its
97 * hci1394_xfer_ctl structure has the appropriate bound address
98 */
99 if (ixl_exec_startp != NULL) {
100
101 /* set up for start of context and return done */
102 ctxtp->dma_mem_execp = (uint32_t)((hci1394_xfer_ctl_t *)
103 ixl_exec_startp->compiler_privatep)->dma[0].dma_bound;
104
105 ctxtp->dma_last_time = 0;
106 ctxtp->ixl_exec_depth = 0;
107 ctxtp->ixl_execp = ixlstp;
108 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs;
109
110 TNF_PROBE_0_DEBUG(hci1394_ixl_set_start_exit,
111 HCI1394_TNF_HAL_STACK_ISOCH, "");
112 return (0);
113 }
114
115 /* else no executeable xfer command found, return error */
116 TNF_PROBE_0_DEBUG(hci1394_ixl_set_start_exit,
117 HCI1394_TNF_HAL_STACK_ISOCH, "");
118 return (1);
119 }
120 #ifdef _KERNEL
121 /*
122 * hci1394_ixl_reset_status()
123 * Reset all statuses in all hci descriptor blocks associated with the
124 * current linked list of compiled ixl commands.
125 *
126 * This function assumes the current context is stopped!
127 */
128 void
hci1394_ixl_reset_status(hci1394_iso_ctxt_t * ctxtp)129 hci1394_ixl_reset_status(hci1394_iso_ctxt_t *ctxtp)
130 {
131 ixl1394_command_t *ixlcur;
132 ixl1394_command_t *ixlnext;
133 hci1394_xfer_ctl_t *xferctlp;
134 uint_t ixldepth;
135 uint16_t timestamp;
136
137 TNF_PROBE_0_DEBUG(hci1394_ixl_reset_status_enter,
138 HCI1394_TNF_HAL_STACK_ISOCH, "");
139
140 ixlnext = ctxtp->ixl_firstp;
141
142 /*
143 * Scan for next ixl xfer start command along ixl link path.
144 * Once xfer command found, clear its hci descriptor block's
145 * status. If is composite ixl xfer command, clear statuses
146 * in each of its hci descriptor blocks.
147 */
148 while (ixlnext != NULL) {
149
150 /* set current and next ixl command */
151 ixlcur = ixlnext;
152 ixlnext = ixlcur->next_ixlp;
153
154 /* skip to examine next if this is not xfer start ixl command */
155 if (((ixlcur->ixl_opcode & IXL1394_OPF_ISXFER) == 0) ||
156 ((ixlcur->ixl_opcode & IXL1394_OPTY_MASK) == 0)) {
157 continue;
158 }
159
160 /* get control struct for this xfer start ixl command */
161 xferctlp = (hci1394_xfer_ctl_t *)ixlcur->compiler_privatep;
162
163 /* clear status in each hci descriptor block for this ixl cmd */
164 ixldepth = 0;
165 while (ixldepth < xferctlp->cnt) {
166 (void) hci1394_ixl_check_status(
167 &xferctlp->dma[ixldepth], ixlcur->ixl_opcode,
168 ×tamp, B_TRUE);
169 ixldepth++;
170 }
171 }
172
173 TNF_PROBE_0_DEBUG(hci1394_ixl_reset_status_exit,
174 HCI1394_TNF_HAL_STACK_ISOCH, "");
175 }
176 #endif
177 /*
178 * hci1394_ixl_find_next_exec_xfer()
179 * Follows execution path of ixl linked list until finds next xfer start IXL
180 * command, including the current IXL command or finds end of IXL linked
181 * list. Counts callback commands found along the way. (Previously, counted
182 * store timestamp commands, as well.)
183 *
184 * To detect an infinite loop of label<->jump without an intervening xfer,
185 * a tolerance level of HCI1394_IXL_MAX_SEQ_JUMPS is used. Once this
186 * number of jumps is traversed, the IXL prog is assumed to have a loop.
187 *
188 * Returns DDI_SUCCESS or DDI_FAILURE. DDI_FAILURE, indicates an infinite
189 * loop of labels & jumps was detected without any intervening xfers.
190 * DDI_SUCCESS indicates the next_exec_ixlpp contains the next xfer ixlp
191 * address, or NULL indicating the end of the list was reached. Note that
192 * DDI_FAILURE can only be returned during the IXL compilation phase, and
193 * not during ixl_update processing.
194 */
195 int
hci1394_ixl_find_next_exec_xfer(ixl1394_command_t * ixl_start,uint_t * callback_cnt,ixl1394_command_t ** next_exec_ixlpp)196 hci1394_ixl_find_next_exec_xfer(ixl1394_command_t *ixl_start,
197 uint_t *callback_cnt, ixl1394_command_t **next_exec_ixlpp)
198 {
199 uint16_t ixlopcode;
200 boolean_t xferfound;
201 ixl1394_command_t *ixlp;
202 int ii;
203
204 TNF_PROBE_0_DEBUG(hci1394_ixl_find_next_exec_xfer_enter,
205 HCI1394_TNF_HAL_STACK_ISOCH, "");
206
207 ixlp = ixl_start;
208 xferfound = B_FALSE;
209 ii = HCI1394_IXL_MAX_SEQ_JUMPS;
210 if (callback_cnt != NULL) {
211 *callback_cnt = 0;
212 }
213
214 /* continue until xfer start ixl cmd or end of ixl list found */
215 while ((xferfound == B_FALSE) && (ixlp != NULL) && (ii > 0)) {
216
217 /* get current ixl cmd opcode without update flag */
218 ixlopcode = ixlp->ixl_opcode & ~IXL1394_OPF_UPDATE;
219
220 /* if found an xfer start ixl command, are done */
221 if (((ixlopcode & IXL1394_OPF_ISXFER) != 0) &&
222 ((ixlopcode & IXL1394_OPTY_MASK) != 0)) {
223 xferfound = B_TRUE;
224 continue;
225 }
226
227 /* if found jump command, adjust to follow its path */
228 if (ixlopcode == IXL1394_OP_JUMP) {
229 ixlp = (ixl1394_command_t *)
230 ((ixl1394_jump_t *)ixlp)->label;
231 ii--;
232
233 /* if exceeded tolerance, give up */
234 if (ii == 0) {
235 TNF_PROBE_1(
236 hci1394_ixl_find_next_exec_xfer_error,
237 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string,
238 errmsg, "Infinite loop w/no xfers");
239 TNF_PROBE_0_DEBUG(
240 hci1394_ixl_find_next_exec_xfer_exit,
241 HCI1394_TNF_HAL_STACK_ISOCH, "");
242 return (DDI_FAILURE);
243 }
244 continue;
245 }
246
247 /* if current ixl command is a callback, count it */
248 if ((ixlopcode == IXL1394_OP_CALLBACK) &&
249 (callback_cnt != NULL)) {
250 (*callback_cnt)++;
251 }
252
253 /* advance to next linked ixl command */
254 ixlp = ixlp->next_ixlp;
255 }
256
257 /* return ixl xfer start command found, if any */
258 *next_exec_ixlpp = ixlp;
259
260 TNF_PROBE_0_DEBUG(hci1394_ixl_find_next_exec_xfer_exit,
261 HCI1394_TNF_HAL_STACK_ISOCH, "");
262 return (DDI_SUCCESS);
263 }
264 #ifdef _KERNEL
265 /*
266 * hci1394_ixl_check_status()
267 * Read the descriptor status and hdrs, clear as appropriate.
268 */
269 int32_t
hci1394_ixl_check_status(hci1394_xfer_ctl_dma_t * dma,uint16_t ixlopcode,uint16_t * timestamp,boolean_t do_status_reset)270 hci1394_ixl_check_status(hci1394_xfer_ctl_dma_t *dma, uint16_t ixlopcode,
271 uint16_t *timestamp, boolean_t do_status_reset)
272 {
273 uint16_t bufsiz;
274 uint16_t hcicnt;
275 uint16_t hcirecvcnt;
276 hci1394_desc_t *hcidescp;
277 off_t hcidesc_off;
278 ddi_acc_handle_t acc_hdl;
279 ddi_dma_handle_t dma_hdl;
280 uint32_t desc_status;
281 uint32_t desc_hdr;
282 int err;
283
284 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_enter,
285 HCI1394_TNF_HAL_STACK_ISOCH, "");
286
287 /* last dma descriptor in descriptor block from dma structure */
288 hcidescp = (hci1394_desc_t *)(dma->dma_descp);
289 hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr;
290 acc_hdl = dma->dma_buf->bi_handle;
291 dma_hdl = dma->dma_buf->bi_dma_handle;
292
293 /* if current ixl command opcode is xmit */
294 if ((ixlopcode & IXL1394_OPF_ONXMIT) != 0) {
295
296 /* Sync the descriptor before we get the status */
297 err = ddi_dma_sync(dma_hdl, hcidesc_off,
298 sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORCPU);
299 if (err != DDI_SUCCESS) {
300 TNF_PROBE_1(hci1394_ixl_check_status_error,
301 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
302 "dma_sync() failed");
303 }
304 desc_status = ddi_get32(acc_hdl, &hcidescp->status);
305
306 /* check if status is set in last dma descriptor in block */
307 if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) {
308 /*
309 * dma descriptor status set - I/O done.
310 * if not to reset status, just return; else extract
311 * timestamp, reset desc status and return dma
312 * descriptor block status set
313 */
314 if (do_status_reset == B_FALSE) {
315 return (1);
316 }
317 *timestamp = (uint16_t)
318 ((desc_status & DESC_ST_TIMESTAMP_MASK) >>
319 DESC_ST_TIMESTAMP_SHIFT);
320 ddi_put32(acc_hdl, &hcidescp->status, 0);
321
322 /* Sync descriptor for device (status was cleared) */
323 err = ddi_dma_sync(dma_hdl, hcidesc_off,
324 sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORDEV);
325 if (err != DDI_SUCCESS) {
326 TNF_PROBE_1(hci1394_ixl_check_status_error,
327 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string,
328 errmsg, "dma_sync() failed");
329 }
330
331 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_exit,
332 HCI1394_TNF_HAL_STACK_ISOCH, "");
333 return (1);
334 }
335 /* else, return dma descriptor block status not set */
336 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_exit,
337 HCI1394_TNF_HAL_STACK_ISOCH, "");
338 return (0);
339 }
340
341 /* else current ixl opcode is recv */
342 hcirecvcnt = 0;
343
344 /* get count of descriptors in current dma descriptor block */
345 hcicnt = dma->dma_bound & DESC_Z_MASK;
346 hcidescp -= (hcicnt - 1);
347 hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr;
348
349 /* iterate fwd through hci descriptors until end or find status set */
350 while (hcicnt-- != 0) {
351
352 /* Sync the descriptor before we get the status */
353 err = ddi_dma_sync(dma_hdl, hcidesc_off,
354 hcicnt * sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORCPU);
355 if (err != DDI_SUCCESS) {
356 TNF_PROBE_1(hci1394_ixl_check_status_error,
357 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
358 "dma_sync() failed");
359 }
360
361 desc_hdr = ddi_get32(acc_hdl, &hcidescp->hdr);
362
363 /* get cur buffer size & accumulate potential buffr usage */
364 bufsiz = (desc_hdr & DESC_HDR_REQCOUNT_MASK) >>
365 DESC_HDR_REQCOUNT_SHIFT;
366 hcirecvcnt += bufsiz;
367
368 desc_status = ddi_get32(acc_hdl, &hcidescp->status);
369
370 /* check if status set on this descriptor block descriptor */
371 if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) {
372 /*
373 * dma descriptor status set - I/O done.
374 * if not to reset status, just return; else extract
375 * buffer space used, reset desc status and return dma
376 * descriptor block status set
377 */
378 if (do_status_reset == B_FALSE) {
379 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_exit,
380 HCI1394_TNF_HAL_STACK_ISOCH, "");
381 return (1);
382 }
383
384 hcirecvcnt -= (desc_status & DESC_ST_RESCOUNT_MASK) >>
385 DESC_ST_RESCOUNT_SHIFT;
386 *timestamp = hcirecvcnt;
387 desc_status = (bufsiz << DESC_ST_RESCOUNT_SHIFT) &
388 DESC_ST_RESCOUNT_MASK;
389 ddi_put32(acc_hdl, &hcidescp->status, desc_status);
390
391 /* Sync descriptor for device (status was cleared) */
392 err = ddi_dma_sync(dma_hdl, hcidesc_off,
393 sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORDEV);
394 if (err != DDI_SUCCESS) {
395 TNF_PROBE_1(hci1394_ixl_check_status_error,
396 HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string,
397 errmsg, "dma_sync() failed");
398 }
399
400 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_exit,
401 HCI1394_TNF_HAL_STACK_ISOCH, "");
402 return (1);
403 } else {
404 /* else, set to evaluate next descriptor. */
405 hcidescp++;
406 hcidesc_off = (off_t)hcidescp -
407 (off_t)dma->dma_buf->bi_kaddr;
408 }
409 }
410
411 /* return input not complete status */
412 TNF_PROBE_0_DEBUG(hci1394_ixl_check_status_exit,
413 HCI1394_TNF_HAL_STACK_ISOCH, "");
414 return (0);
415 }
416 #endif
417 /*
418 * hci1394_ixl_cleanup()
419 * Delete all memory that has earlier been allocated for a context's IXL prog
420 */
421 void
hci1394_ixl_cleanup(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp)422 hci1394_ixl_cleanup(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp)
423 {
424 TNF_PROBE_0_DEBUG(hci1394_ixl_cleanup_enter,
425 HCI1394_TNF_HAL_STACK_ISOCH, "");
426
427 hci1394_delete_xfer_ctl((hci1394_xfer_ctl_t *)ctxtp->xcs_firstp);
428 hci1394_delete_dma_desc_mem(soft_statep, ctxtp->dma_firstp);
429
430 TNF_PROBE_0_DEBUG(hci1394_ixl_cleanup_exit,
431 HCI1394_TNF_HAL_STACK_ISOCH, "");
432 }
433
434 /*
435 * hci1394_delete_dma_desc_mem()
436 * Iterate through linked list of dma memory descriptors, deleting
437 * allocated dma memory blocks, then deleting the dma memory
438 * descriptor after advancing to next one
439 */
440 static void
441 /* ARGSUSED */
hci1394_delete_dma_desc_mem(hci1394_state_t * soft_statep,hci1394_idma_desc_mem_t * dma_firstp)442 hci1394_delete_dma_desc_mem(hci1394_state_t *soft_statep,
443 hci1394_idma_desc_mem_t *dma_firstp)
444 {
445 hci1394_idma_desc_mem_t *dma_next;
446
447 TNF_PROBE_0_DEBUG(hci1394_delete_dma_desc_mem_enter,
448 HCI1394_TNF_HAL_STACK_ISOCH, "");
449
450 while (dma_firstp != NULL) {
451 dma_next = dma_firstp->dma_nextp;
452 #ifdef _KERNEL
453 /*
454 * if this dma descriptor memory block has the handles, then
455 * free the memory. (Note that valid handles are kept only with
456 * the most recently acquired cookie, and that each cookie is in
457 * it's own idma_desc_mem_t struct.)
458 */
459 if (dma_firstp->mem_handle != NULL) {
460 hci1394_buf_free(&dma_firstp->mem_handle);
461 }
462
463 /* free current dma memory descriptor */
464 kmem_free(dma_firstp, sizeof (hci1394_idma_desc_mem_t));
465 #else
466 /* user mode free */
467 /* free dma memory block and current dma mem descriptor */
468 free(dma_firstp->mem.bi_kaddr);
469 free(dma_firstp);
470 #endif
471 /* advance to next dma memory descriptor */
472 dma_firstp = dma_next;
473 }
474 TNF_PROBE_0_DEBUG(hci1394_delete_dma_desc_mem_exit,
475 HCI1394_TNF_HAL_STACK_ISOCH, "");
476 }
477
478 /*
479 * hci1394_delete_xfer_ctl()
480 * Iterate thru linked list of xfer_ctl structs, deleting allocated memory.
481 */
482 void
hci1394_delete_xfer_ctl(hci1394_xfer_ctl_t * xcsp)483 hci1394_delete_xfer_ctl(hci1394_xfer_ctl_t *xcsp)
484 {
485 hci1394_xfer_ctl_t *delp;
486
487 TNF_PROBE_0_DEBUG(hci1394_delete_xfer_ctl_enter,
488 HCI1394_TNF_HAL_STACK_ISOCH, "");
489
490 while ((delp = xcsp) != NULL) {
491 /* advance ptr to next xfer_ctl struct */
492 xcsp = xcsp->ctl_nextp;
493
494 /*
495 * delete current xfer_ctl struct and included
496 * xfer_ctl_dma structs
497 */
498 #ifdef _KERNEL
499 kmem_free(delp,
500 sizeof (hci1394_xfer_ctl_t) +
501 sizeof (hci1394_xfer_ctl_dma_t) * (delp->cnt - 1));
502 #else
503 free(delp);
504 #endif
505 }
506 TNF_PROBE_0_DEBUG(hci1394_delete_xfer_ctl_exit,
507 HCI1394_TNF_HAL_STACK_ISOCH, "");
508 }
509