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 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/asi.h>
27 #include <sys/asm_linkage.h>
28 #include <sys/machthread.h>
29 #include <sys/privregs.h>
30 #include <sys/ontrap.h>
31 #include <sys/dditypes.h>
32
33 #include "assym.h"
34
35 /*
36 * This file implements the following ddi common access
37 * functions:
38 *
39 * ddi_get{8,16,32,64}
40 * ddi_put{8,16,32,64}
41 *
42 * and the underlying "trivial" implementations
43 *
44 * i_ddi_{get,put}{8,16,32,64}
45 *
46 * which assume that there is no need to check the access handle -
47 * byte swapping will be done by the mmu and the address is always
48 * accessible via ld/st instructions.
49 */
50
51 /*
52 * The functionality of each of the ddi_get/put routines is performed by
53 * the respective indirect function defined in the access handle. Use of
54 * the access handle functions provides compatibility across platforms for
55 * drivers.
56 *
57 * By default, the indirect access handle functions are initialized to the
58 * i_ddi_get/put routines to perform memory mapped IO. If memory mapped IO
59 * is not possible or desired, the access handle must be intialized to another
60 * valid routine to perform the sepcified IO operation.
61 *
62 * The alignment and placement of the following functions have been optimized
63 * such that the implementation specific versions, i_ddi*, fall within the
64 * same cache-line of the generic versions, ddi_*. This insures that an
65 * I-cache hit will occur thus minimizing the performance impact of using the
66 * access handle.
67 */
68
69 .align 32
70 ENTRY(ddi_get8)
71 ALTENTRY(ddi_getb)
72 ALTENTRY(ddi_io_get8)
73 ALTENTRY(ddi_io_getb)
74 ALTENTRY(ddi_mem_get8)
75 ALTENTRY(ddi_mem_getb)
76 ldn [%o0 + AHI_GET8], %g1 /* hdl->ahi_get8 access hndl */
77 jmpl %g1, %g0 /* jump to access handle routine */
78 nop
79 SET_SIZE(ddi_get8)
80 SET_SIZE(ddi_getb)
81 SET_SIZE(ddi_io_get8)
82 SET_SIZE(ddi_io_getb)
83 SET_SIZE(ddi_mem_get8)
84 SET_SIZE(ddi_mem_getb)
85
86 .align 16
87 ENTRY(i_ddi_get8)
88 retl
89 ldub [%o1], %o0
90 SET_SIZE(i_ddi_get8)
91
92 .align 32
93 ENTRY(ddi_get16)
94 ALTENTRY(ddi_getw)
95 ALTENTRY(ddi_io_get16)
96 ALTENTRY(ddi_io_getw)
97 ALTENTRY(ddi_mem_get16)
98 ALTENTRY(ddi_mem_getw)
99 ldn [%o0 + AHI_GET16], %g1 /* hdl->ahi_get16 access hndl */
100 jmpl %g1, %g0 /* jump to access handle routine */
101 nop
102 SET_SIZE(ddi_get16)
103 SET_SIZE(ddi_getw)
104 SET_SIZE(ddi_io_get16)
105 SET_SIZE(ddi_io_getw)
106 SET_SIZE(ddi_mem_get16)
107 SET_SIZE(ddi_mem_getw)
108
109 .align 16
110 ENTRY(i_ddi_get16)
111 ALTENTRY(i_ddi_swap_get16)
112 retl
113 lduh [%o1], %o0
114 SET_SIZE(i_ddi_get16)
115 SET_SIZE(i_ddi_swap_get16)
116
117 .align 32
118 ENTRY(ddi_get32)
119 ALTENTRY(ddi_getl)
120 ALTENTRY(ddi_io_get32)
121 ALTENTRY(ddi_io_getl)
122 ALTENTRY(ddi_mem_get32)
123 ALTENTRY(ddi_mem_getl)
124 ldn [%o0 + AHI_GET32], %g1 /* hdl->ahi_get32 access handle */
125 jmpl %g1, %g0 /* jump to access handle routine */
126 nop
127 SET_SIZE(ddi_get32)
128 SET_SIZE(ddi_getl)
129 SET_SIZE(ddi_io_get32)
130 SET_SIZE(ddi_io_getl)
131 SET_SIZE(ddi_mem_get32)
132 SET_SIZE(ddi_mem_getl)
133
134 .align 16
135 ENTRY(i_ddi_get32)
136 ALTENTRY(i_ddi_swap_get32)
137 retl
138 ld [%o1], %o0
139 SET_SIZE(i_ddi_get32)
140 SET_SIZE(i_ddi_swap_get32)
141
142 .align 32
143 ENTRY(ddi_get64)
144 ALTENTRY(ddi_getll)
145 ALTENTRY(ddi_io_get64)
146 ALTENTRY(ddi_io_getll)
147 ALTENTRY(ddi_mem_get64)
148 ALTENTRY(ddi_mem_getll)
149 ldn [%o0 + AHI_GET64], %g1 /* hdl->ahi_get64 access handle */
150 jmpl %g1, %g0 /* jump to access handle routine */
151 nop
152 SET_SIZE(ddi_get64)
153 SET_SIZE(ddi_getll)
154 SET_SIZE(ddi_io_get64)
155 SET_SIZE(ddi_io_getll)
156 SET_SIZE(ddi_mem_get64)
157 SET_SIZE(ddi_mem_getll)
158
159 .align 16
160 ENTRY(i_ddi_get64)
161 ALTENTRY(i_ddi_swap_get64)
162 retl
163 ldx [%o1], %o0
164 SET_SIZE(i_ddi_get64)
165 SET_SIZE(i_ddi_swap_get64)
166
167 .align 32
168 ENTRY(ddi_put8)
169 ALTENTRY(ddi_putb)
170 ALTENTRY(ddi_io_put8)
171 ALTENTRY(ddi_io_putb)
172 ALTENTRY(ddi_mem_put8)
173 ALTENTRY(ddi_mem_putb)
174 ldn [%o0 + AHI_PUT8], %g1 /* hdl->ahi_put8 access handle */
175 jmpl %g1, %g0 /* jump to access handle routine */
176 nop
177 SET_SIZE(ddi_put8)
178 SET_SIZE(ddi_putb)
179 SET_SIZE(ddi_io_put8)
180 SET_SIZE(ddi_io_putb)
181 SET_SIZE(ddi_mem_put8)
182 SET_SIZE(ddi_mem_putb)
183
184 .align 16
185 ENTRY(i_ddi_put8)
186 retl
187 stub %o2, [%o1]
188 SET_SIZE(i_ddi_put8)
189
190 .align 32
191 ENTRY(ddi_put16)
192 ALTENTRY(ddi_putw)
193 ALTENTRY(ddi_io_put16)
194 ALTENTRY(ddi_io_putw)
195 ALTENTRY(ddi_mem_put16)
196 ALTENTRY(ddi_mem_putw)
197 ldn [%o0 + AHI_PUT16], %g1 /* hdl->ahi_put16 access handle */
198 jmpl %g1, %g0 /* jump to access handle routine */
199 nop
200 SET_SIZE(ddi_put16)
201 SET_SIZE(ddi_putw)
202 SET_SIZE(ddi_io_put16)
203 SET_SIZE(ddi_io_putw)
204 SET_SIZE(ddi_mem_put16)
205 SET_SIZE(ddi_mem_putw)
206
207 .align 16
208 ENTRY(i_ddi_put16)
209 ALTENTRY(i_ddi_swap_put16)
210 retl
211 stuh %o2, [%o1]
212 SET_SIZE(i_ddi_put16)
213 SET_SIZE(i_ddi_swap_put16)
214
215 .align 32
216 ENTRY(ddi_put32)
217 ALTENTRY(ddi_putl)
218 ALTENTRY(ddi_io_put32)
219 ALTENTRY(ddi_io_putl)
220 ALTENTRY(ddi_mem_put32)
221 ALTENTRY(ddi_mem_putl)
222 ldn [%o0 + AHI_PUT32], %g1 /* hdl->ahi_put16 access handle */
223 jmpl %g1, %g0 /* jump to access handle routine */
224 nop
225 SET_SIZE(ddi_put32)
226 SET_SIZE(ddi_putl)
227 SET_SIZE(ddi_io_put32)
228 SET_SIZE(ddi_io_putl)
229 SET_SIZE(ddi_mem_put32)
230 SET_SIZE(ddi_mem_putl)
231
232 .align 16
233 ENTRY(i_ddi_put32)
234 ALTENTRY(i_ddi_swap_put32)
235 retl
236 st %o2, [%o1]
237 SET_SIZE(i_ddi_put32)
238 SET_SIZE(i_ddi_swap_put32)
239
240 .align 32
241 ENTRY(ddi_put64)
242 ALTENTRY(ddi_putll)
243 ALTENTRY(ddi_io_put64)
244 ALTENTRY(ddi_io_putll)
245 ALTENTRY(ddi_mem_put64)
246 ALTENTRY(ddi_mem_putll)
247 ldn [%o0 + AHI_PUT64], %g1 /* hdl->ahi_put64 access handle */
248 jmpl %g1, %g0 /* jump to access handle routine */
249 nop
250 SET_SIZE(ddi_put64)
251 SET_SIZE(ddi_putll)
252 SET_SIZE(ddi_io_put64)
253 SET_SIZE(ddi_io_putll)
254 SET_SIZE(ddi_mem_put64)
255 SET_SIZE(ddi_mem_putll)
256
257 .align 16
258 ENTRY(i_ddi_put64)
259 ALTENTRY(i_ddi_swap_put64)
260 retl
261 stx %o2, [%o1]
262 SET_SIZE(i_ddi_put64)
263 SET_SIZE(i_ddi_swap_put64)
264
265 /*
266 * The ddi_io_rep_get/put routines don't take a flag argument like the "plain"
267 * and mem versions do. This flag is used to determine whether or not the
268 * device address or port should be automatically incremented. For IO space,
269 * the device port is never incremented and as such, the flag is always set
270 * to DDI_DEV_NO_AUTOINCR.
271 *
272 * This define processes the repetitive get functionality. Automatic
273 * incrementing of the device address is determined by the flag field
274 * %o4. If this is set for AUTOINCR, %o4 is updated with 1 for the
275 * subsequent increment in 2:.
276 *
277 * If this flag is not set for AUTOINCR, %o4 is update with a value of 0 thus
278 * making the increment operation a non-operation.
279 */
280
281 #define DDI_REP_GET(n,s) \
282 cmp DDI_DEV_NO_AUTOINCR, %o4; \
283 mov %g0, %o4; \
284 brz,pn %o3, 1f; \
285 movnz %xcc, n, %o4; \
286 2: \
287 dec %o3; \
288 ld/**/s [%o2], %g4; \
289 add %o2, %o4, %o2; \
290 st/**/s %g4, [%o1]; \
291 brnz,pt %o3, 2b; \
292 add %o1, n, %o1; \
293 1:
294
295 .align 32
296 ENTRY(ddi_rep_get8)
297 ALTENTRY(ddi_rep_getb)
298 ALTENTRY(ddi_mem_rep_get8)
299 ALTENTRY(ddi_mem_rep_getb)
300 ldn [%o0 + AHI_REP_GET8], %g1
301 jmpl %g1, %g0
302 nop
303 SET_SIZE(ddi_rep_get8)
304 SET_SIZE(ddi_rep_getb)
305 SET_SIZE(ddi_mem_rep_get8)
306 SET_SIZE(ddi_mem_rep_getb)
307
308 .align 16
309 ENTRY(i_ddi_rep_get8)
310 DDI_REP_GET(1,ub)
311 retl
312 nop
313 SET_SIZE(i_ddi_rep_get8)
314
315 .align 32
316 ENTRY(ddi_rep_get16)
317 ALTENTRY(ddi_rep_getw)
318 ALTENTRY(ddi_mem_rep_get16)
319 ALTENTRY(ddi_mem_rep_getw)
320 ldn [%o0 + AHI_REP_GET16], %g1
321 jmpl %g1, %g0
322 nop
323 SET_SIZE(ddi_rep_get16)
324 SET_SIZE(ddi_rep_getw)
325 SET_SIZE(ddi_mem_rep_get16)
326 SET_SIZE(ddi_mem_rep_getw)
327
328 .align 16
329 ENTRY(i_ddi_rep_get16)
330 ALTENTRY(i_ddi_swap_rep_get16)
331 DDI_REP_GET(2,uh)
332 retl
333 nop
334 SET_SIZE(i_ddi_rep_get16)
335 SET_SIZE(i_ddi_swap_rep_get16)
336
337 .align 32
338 ENTRY(ddi_rep_get32)
339 ALTENTRY(ddi_rep_getl)
340 ALTENTRY(ddi_mem_rep_get32)
341 ALTENTRY(ddi_mem_rep_getl)
342 ldn [%o0 + AHI_REP_GET32], %g1
343 jmpl %g1, %g0
344 nop
345 SET_SIZE(ddi_rep_get32)
346 SET_SIZE(ddi_rep_getl)
347 SET_SIZE(ddi_mem_rep_get32)
348 SET_SIZE(ddi_mem_rep_getl)
349
350 .align 16
351 ENTRY(i_ddi_rep_get32)
352 ALTENTRY(i_ddi_swap_rep_get32)
353 DDI_REP_GET(4,/**/)
354 retl
355 nop
356 SET_SIZE(i_ddi_rep_get32)
357 SET_SIZE(i_ddi_swap_rep_get32)
358
359 .align 32
360 ENTRY(ddi_rep_get64)
361 ALTENTRY(ddi_rep_getll)
362 ALTENTRY(ddi_mem_rep_get64)
363 ALTENTRY(ddi_mem_rep_getll)
364 ldn [%o0 + AHI_REP_GET64], %g1
365 jmpl %g1, %g0
366 nop
367 SET_SIZE(ddi_rep_get64)
368 SET_SIZE(ddi_rep_getll)
369 SET_SIZE(ddi_mem_rep_get64)
370 SET_SIZE(ddi_mem_rep_getll)
371
372 .align 16
373 ENTRY(i_ddi_rep_get64)
374 ALTENTRY(i_ddi_swap_rep_get64)
375 DDI_REP_GET(8,x)
376 retl
377 nop
378 SET_SIZE(i_ddi_rep_get64)
379 SET_SIZE(i_ddi_swap_rep_get64)
380
381 /*
382 * This define processes the repetitive put functionality. Automatic
383 * incrementing of the device address is determined by the flag field
384 * %o4. If this is set for AUTOINCR, %o4 is updated with 1 for the
385 * subsequent increment in 2:.
386 *
387 * If this flag is not set for AUTOINCR, %o4 is update with a value of 0 thus
388 * making the increment operation a non-operation.
389 */
390 #define DDI_REP_PUT(n,s) \
391 cmp DDI_DEV_NO_AUTOINCR, %o4; \
392 mov %g0, %o4; \
393 brz,pn %o3, 1f; \
394 movnz %xcc, n, %o4; \
395 2: \
396 dec %o3; \
397 ld/**/s [%o1], %g4; \
398 add %o1, n, %o1; \
399 st/**/s %g4, [%o2]; \
400 brnz,pt %o3, 2b; \
401 add %o2, %o4, %o2; \
402 1:
403
404 .align 32
405 ENTRY(ddi_rep_put8)
406 ALTENTRY(ddi_rep_putb)
407 ALTENTRY(ddi_mem_rep_put8)
408 ALTENTRY(ddi_mem_rep_putb)
409 ldn [%o0 + AHI_REP_PUT8], %g1
410 jmpl %g1, %g0
411 nop
412 SET_SIZE(ddi_rep_put8)
413 SET_SIZE(ddi_rep_putb)
414 SET_SIZE(ddi_mem_rep_put8)
415 SET_SIZE(ddi_mem_rep_putb)
416
417 .align 16
418 ENTRY(i_ddi_rep_put8)
419 DDI_REP_PUT(1,ub)
420 retl
421 nop
422 SET_SIZE(i_ddi_rep_put8)
423
424 .align 32
425 ENTRY(ddi_rep_put16)
426 ALTENTRY(ddi_rep_putw)
427 ALTENTRY(ddi_mem_rep_put16)
428 ALTENTRY(ddi_mem_rep_putw)
429 ldn [%o0 + AHI_REP_PUT16], %g1
430 jmpl %g1, %g0
431 nop
432 SET_SIZE(ddi_rep_put16)
433 SET_SIZE(ddi_rep_putw)
434 SET_SIZE(ddi_mem_rep_put16)
435 SET_SIZE(ddi_mem_rep_putw)
436
437 .align 16
438 ENTRY(i_ddi_rep_put16)
439 ALTENTRY(i_ddi_swap_rep_put16)
440 DDI_REP_PUT(2,uh)
441 retl
442 nop
443 SET_SIZE(i_ddi_rep_put16)
444 SET_SIZE(i_ddi_swap_rep_put16)
445
446 .align 32
447 ENTRY(ddi_rep_put32)
448 ALTENTRY(ddi_rep_putl)
449 ALTENTRY(ddi_mem_rep_put32)
450 ALTENTRY(ddi_mem_rep_putl)
451 ldn [%o0 + AHI_REP_PUT32], %g1
452 jmpl %g1, %g0
453 nop
454 SET_SIZE(ddi_rep_put32)
455 SET_SIZE(ddi_rep_putl)
456 SET_SIZE(ddi_mem_rep_put32)
457 SET_SIZE(ddi_mem_rep_putl)
458
459 .align 16
460 ENTRY(i_ddi_rep_put32)
461 ALTENTRY(i_ddi_swap_rep_put32)
462 DDI_REP_PUT(4,/**/)
463 retl
464 nop
465 SET_SIZE(i_ddi_rep_put32)
466 SET_SIZE(i_ddi_swap_rep_put32)
467
468 .align 32
469 ENTRY(ddi_rep_put64)
470 ALTENTRY(ddi_rep_putll)
471 ALTENTRY(ddi_mem_rep_put64)
472 ALTENTRY(ddi_mem_rep_putll)
473 ldn [%o0 + AHI_REP_PUT64], %g1
474 jmpl %g1, %g0
475 nop
476 SET_SIZE(ddi_rep_put64)
477 SET_SIZE(ddi_rep_putll)
478 SET_SIZE(ddi_mem_rep_put64)
479 SET_SIZE(ddi_mem_rep_putll)
480
481 .align 16
482 ENTRY(i_ddi_rep_put64)
483 ALTENTRY(i_ddi_swap_rep_put64)
484 DDI_REP_PUT(8,x)
485 retl
486 nop
487 SET_SIZE(i_ddi_rep_put64)
488 SET_SIZE(i_ddi_swap_rep_put64)
489
490 .align 16
491 ENTRY(ddi_io_rep_get8)
492 ALTENTRY(ddi_io_rep_getb)
493 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
494 ldn [%o0 + AHI_REP_GET8], %g1
495 jmpl %g1, %g0
496 nop
497 SET_SIZE(ddi_io_rep_get8)
498 SET_SIZE(ddi_io_rep_getb)
499
500 .align 16
501 ENTRY(ddi_io_rep_get16)
502 ALTENTRY(ddi_io_rep_getw)
503 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
504 ldn [%o0 + AHI_REP_GET16], %g1
505 jmpl %g1, %g0
506 nop
507 SET_SIZE(ddi_io_rep_get16)
508 SET_SIZE(ddi_io_rep_getw)
509
510 .align 16
511 ENTRY(ddi_io_rep_get32)
512 ALTENTRY(ddi_io_rep_getl)
513 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
514 ldn [%o0 + AHI_REP_GET32], %g1
515 jmpl %g1, %g0
516 nop
517 SET_SIZE(ddi_io_rep_get32)
518 SET_SIZE(ddi_io_rep_getl)
519
520 .align 16
521 ENTRY(ddi_io_rep_get64)
522 ALTENTRY(ddi_io_rep_getll)
523 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
524 ldn [%o0 + AHI_REP_GET64], %g1
525 jmpl %g1, %g0
526 nop
527 SET_SIZE(ddi_io_rep_get64)
528 SET_SIZE(ddi_io_rep_getll)
529
530 .align 64
531 ENTRY(ddi_check_acc_handle)
532 save %sp, -SA(WINDOWSIZE), %sp ! get a new window
533 ldn [%i0 + AHI_FAULT_CHECK], %g1
534 jmpl %g1, %o7
535 mov %i0, %o0
536 brnz,a,pn %o0, 0f ! if (return_value != 0)
537 mov -1, %o0 ! return (DDI_FAILURE)
538 0: ! else return (DDI_SUCCESS)
539 sra %o0, 0, %i0
540 ret
541 restore
542 SET_SIZE(ddi_check_acc_handle)
543
544 .align 16
545 ENTRY(i_ddi_acc_fault_check)
546 retl
547 ld [%o0 + AHI_FAULT], %o0
548 SET_SIZE(i_ddi_acc_fault_check)
549
550 .align 16
551 ENTRY(ddi_io_rep_put8)
552 ALTENTRY(ddi_io_rep_putb)
553 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
554 ldn [%o0 + AHI_REP_PUT8], %g1
555 jmpl %g1, %g0
556 nop
557 SET_SIZE(ddi_io_rep_put8)
558 SET_SIZE(ddi_io_rep_putb)
559
560 .align 16
561 ENTRY(ddi_io_rep_put16)
562 ALTENTRY(ddi_io_rep_putw)
563 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
564 ldn [%o0 + AHI_REP_PUT16], %g1
565 jmpl %g1, %g0
566 nop
567 SET_SIZE(ddi_io_rep_put16)
568 SET_SIZE(ddi_io_rep_putw)
569
570 .align 16
571 ENTRY(ddi_io_rep_put32)
572 ALTENTRY(ddi_io_rep_putl)
573 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
574 ldn [%o0 + AHI_REP_PUT32], %g1
575 jmpl %g1, %g0
576 nop
577 SET_SIZE(ddi_io_rep_put32)
578 SET_SIZE(ddi_io_rep_putl)
579
580 .align 16
581 ENTRY(ddi_io_rep_put64)
582 ALTENTRY(ddi_io_rep_putll)
583 set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */
584 ldn [%o0 + AHI_REP_PUT64], %g1
585 jmpl %g1, %g0
586 nop
587 SET_SIZE(ddi_io_rep_put64)
588 SET_SIZE(ddi_io_rep_putll)
589
590 ENTRY(do_peek)
591 rdpr %pstate, %o3 ! check ints
592 andcc %o3, PSTATE_IE, %g0
593 bz,a done
594 or %g0, 1, %o0 ! Return failure if ints are disabled
595 wrpr %o3, PSTATE_IE, %pstate
596 cmp %o0, 8 ! 64-bit?
597 bne,a .peek_int
598 cmp %o0, 4 ! 32-bit?
599 ldx [%o1], %g1
600 ba .peekdone
601 stx %g1, [%o2]
602 .peek_int:
603 bne,a .peek_half
604 cmp %o0, 2 ! 16-bit?
605 lduw [%o1], %g1
606 ba .peekdone
607 stuw %g1, [%o2]
608 .peek_half:
609 bne,a .peek_byte
610 ldub [%o1], %g1 ! 8-bit!
611 lduh [%o1], %g1
612 ba .peekdone
613 stuh %g1, [%o2]
614 .peek_byte:
615 stub %g1, [%o2]
616 .peekdone:
617 membar #Sync ! Make sure the loads take
618 rdpr %pstate, %o3 ! check&enable ints
619 andcc %o3, PSTATE_IE, %g0
620 bnz 1f
621 nop
622 wrpr %o3, PSTATE_IE, %pstate
623 1:
624 mov %g0, %o0
625 done:
626 retl
627 nop
628 SET_SIZE(do_peek)
629
630 ENTRY(do_poke)
631 cmp %o0, 8 ! 64 bit?
632 bne,a .poke_int
633 cmp %o0, 4 ! 32-bit?
634 ldx [%o2], %g1
635 ba .pokedone
636 stx %g1, [%o1]
637 .poke_int:
638 bne,a .poke_half
639 cmp %o0, 2 ! 16-bit?
640 lduw [%o2], %g1
641 ba .pokedone
642 stuw %g1, [%o1]
643 .poke_half:
644 bne,a .poke_byte
645 ldub [%o2], %g1 ! 8-bit!
646 lduh [%o2], %g1
647 ba .pokedone
648 stuh %g1, [%o1]
649 .poke_byte:
650 stub %g1, [%o1]
651 .pokedone:
652 membar #Sync
653 retl
654 mov %g0, %o0
655 SET_SIZE(do_poke)
656
657
658 /*
659 * The peek_fault() and poke_fault() routines below are used as on_trap()
660 * trampoline routines. i_ddi_peek and i_ddi_poke execute do_peek and do_poke
661 * under on_trap protection (see <sys/ontrap.h>), but modify ot_trampoline to
662 * refer to the corresponding routine below. If a trap occurs, the trap code
663 * will bounce back to the trampoline code, which will effectively cause
664 * do_peek or do_poke to return DDI_FAILURE, instead of longjmp'ing back to
665 * on_trap. In the case of a peek, we may also need to re-enable interrupts.
666 */
667 .seg ".data"
668 .peek_panic:
669 .asciz "peek_fault: missing or invalid on_trap_data"
670 .poke_panic:
671 .asciz "poke_fault: missing or invalid on_trap_data"
672
673 ENTRY(peek_fault)
674 ldn [THREAD_REG + T_ONTRAP], %o0 ! %o0 = on_trap_data pointer
675 brz,pn %o0, .peekfail ! if (%o0 == NULL) panic
676 nop
677 lduh [%o0 + OT_PROT], %o1 ! %o1 = %o0->ot_prot
678 andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS))
679 bz,pn %icc, .peekfail ! panic
680 rdpr %pstate, %o3
681
682 andcc %o3, PSTATE_IE, %g0 ! enable interrupts
683 bnz 1f
684 nop
685 wrpr %o3, PSTATE_IE, %pstate
686 1:
687 retl
688 sub %g0, 1, %o0 ! return (DDI_FAILURE);
689 .peekfail:
690 set .peek_panic, %o0 ! Load panic message
691 call panic ! Panic if bad t_ontrap data
692 nop
693 SET_SIZE(peek_fault)
694
695
696 ENTRY(poke_fault)
697 ldn [THREAD_REG + T_ONTRAP], %o0 ! %o0 = on_trap_data pointer
698 brz,pn %o0, .pokefail ! if (%o0 == NULL) panic
699 nop
700 lduh [%o0 + OT_PROT], %o1 ! %o1 = %o0->ot_prot
701 andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS))
702 bz,pn %icc, .pokefail ! panic
703 nop
704 retl
705 sub %g0, 1, %o0 ! return (DDI_FAILURE);
706 .pokefail:
707 set .poke_panic, %o0 ! Load panic message
708 call panic ! Panic if bad t_ontrap data
709 nop
710 SET_SIZE(poke_fault)
711
712
713 /*
714 * IO Fault Services
715 *
716 * Support for protected IO accesses is implemented in the following
717 * functions. A driver may request one of three protection mechanisms
718 * that enable the system to survive an access errors. The protection
719 * mechansim is set-up during ddi_regs_map_setup time and may be one of:
720 *
721 * DDI_DEFAULT_ACC - no error protection requested. We will
722 * use the standard ddi_get/ddi_put operations
723 * defined above.
724 *
725 * DDI_FLAGERR - Driver requests that errors encountered will
726 * be flagged by the system. The driver is
727 * responsible for checking the error status
728 * of the access with a call to ddi_acc_err_get()
729 * upon return of ddi_get or ddi_put. To prevent
730 * an access from causing a system we use internal
731 * on_trap semantics.
732 *
733 * The system, depending upon the error,
734 * may or may not panic.
735 *
736 * DDI_CAUTIOUS_ACC - Driver expects that the access may cause
737 * an error to occur. The system will return
738 * an error status but will not generate an ereport.
739 * The system will also ensure synchronous and
740 * exclusive access to the IO space accessed by
741 * the caller.
742 *
743 * To prevent an access from causing a system panic,
744 * we use on_trap semantics to catch the error and
745 * set error status.
746 *
747 * If a read access error is detected and DDI_CAUTIOUS_ACC or
748 * DDI_FLAGERR_ACC protection was requested, we will trampoline to the
749 * error handler, i_ddi_trampoline. i_ddi_trampoline will:
750 * - check for proper protection semantics
751 * - set the error status of the access handle to DDI_FM_NONFATAL
752 * - re-enable interrupts if neccessary
753 * - longjmp back to the initiating access function.
754
755 * If a write access error is detected, an interrupt is typically
756 * generated and claimed by a bus nexus responsible for the write
757 * transaction. The nexus error handler is expected to set the
758 * error status and the IO initiating driver is expected to check
759 * for a failed transaction via ddi_fm_acc_err_get().
760 *
761 */
762
763 .seg ".data"
764 .acc_panic:
765 .asciz "DDI access: missing or invalid on_trap_data"
766
767 ENTRY(i_ddi_caut_trampoline)
768 ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap
769 lduh [%o5 + OT_PROT], %o1 ! %o1 = %o0->ot_prot
770 andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS))
771 bz,pn %icc, .cautaccfail ! panic
772 rdpr %pstate, %o3
773 andcc %o3, PSTATE_IE, %g0 ! enable interrupts
774 bnz 1f
775 nop
776 wrpr %o3, PSTATE_IE, %pstate
777 1:
778 ldn [%o5 + OT_HANDLE], %o0 ! %o0 = ot_handle
779 brz,pn %o0, .cautaccfail ! if (ot_handle == NULL) panic
780 nop
781 ldn [%o0 + AHI_ERR], %o4 ! %o4 = hp->ahi_err
782 membar #Sync
783 stx %g0, [%o4 + ERR_ENA] ! ahi_err->err_ena = 0
784 mov -2, %o0
785 st %o0, [%o4 + ERR_STATUS] ! ahi_err->err_status = NONFATAL
786 b longjmp ! longjmp back
787 add %o5, OT_JMPBUF, %o0 ! %o0 = &ot_jmpbuf
788 .cautaccfail:
789 set .acc_panic, %o0 ! Load panic message
790 call panic ! Panic if bad t_ontrap data
791 nop
792 SET_SIZE(i_ddi_caut_trampoline)
793
794 /*
795 * DDI on_trap set-up functions, i_ddi_ontrap() and i_ddinotrap() are used
796 * to protect * ddi_get accesses for DDI_CAUT_ACC. i_ddi_ontrap() sets
797 * the jumpbuf (setjmp) that will return back to the access routine from
798 * i_ddi_trampoline(). DDI_NOPROTECT() clears the ontrap set-up.
799 */
800 ENTRY(i_ddi_ontrap)
801 ldn [%o0 + AHI_ERR], %o4
802 ldn [%o4 + ERR_ONTRAP], %o4 ! %o4 = hp->ahi_err->err_ontrap
803 ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap
804 stn %o5, [%o4 + OT_PREV] ! ot_prev = t_ontrap
805 membar #Sync ! force error barrier
806 stn %o4, [THREAD_REG + T_ONTRAP] ! t_ontrap = err_ontrap
807 b setjmp
808 add %o4, OT_JMPBUF, %o0
809 SET_SIZE(i_ddi_ontrap)
810
811 ENTRY(i_ddi_notrap)
812 membar #Sync ! force error barrier
813 ldn [%o0 + AHI_ERR], %o4
814 ldn [%o4 + ERR_ONTRAP], %o4 ! %o4 = hp->ahi_err->err_ontrap
815 ldn [%o4 + OT_PREV], %o4
816 retl
817 stn %o4, [THREAD_REG + T_ONTRAP] ! restore curthread->t_ontrap
818 SET_SIZE(i_ddi_notrap)
819
820 /*
821 * Internal on_trap set-up macros. DDI_PROTECT() and DDI_NOPROTECT() are used
822 * to protect * ddi_get accesses for DDI_FLAGERR_ACC. DDI_NOPROTECT() sets
823 * the jumpbuf that will return back to the access routine from
824 * i_ddi_protect_trampoline(). DDI_NOPROTECT() clears the ontrap set-up.
825 */
826 ENTRY(i_ddi_prot_trampoline)
827 ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap
828 lduh [%o5 + OT_PROT], %o1 ! %o1 = %o0->ot_prot
829 andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS))
830 bz,pn %icc, .protaccfail ! panic
831 rdpr %pstate, %o3
832 andcc %o3, PSTATE_IE, %g0 ! enable interrupts
833 bnz 1f
834 nop
835 wrpr %o3, PSTATE_IE, %pstate
836 1:
837 ldn [%o5 + OT_HANDLE], %o0 ! %o0 = ot_handle
838 brz,pn %o0, .protaccfail ! if (ot_handle == NULL) panic
839 nop
840 ldn [%o0 + AHI_ERR], %o4 ! %o4 = hp->ahi_err
841 stn %g0, [%o4 + ERR_ENA] ! ahi_err->err_ena = 0
842 mov -2, %o0
843 st %o0, [%o4 + ERR_STATUS] ! ahi_err->err_status = NONFATAL
844 ldn [%o5 + OT_PREV], %o0 ! restore ontrap
845 membar #Sync ! force error barrier
846 stn %o0, [THREAD_REG + T_ONTRAP];
847 b longjmp ! longjmp back
848 add %o5, OT_JMPBUF, %o0 ! %o0 = &ot_jmpbuf
849 .protaccfail:
850 set .acc_panic, %o0 ! Load panic message
851 call panic ! Panic if bad t_ontrap data
852 nop
853 SET_SIZE(i_ddi_prot_trampoline)
854
855 #define DDI_PROTECT() \
856 ldn [%o0 + AHI_ERR], %o4; \
857 ldn [%o4 + ERR_ONTRAP], %o4; \
858 ldn [THREAD_REG + T_ONTRAP], %o5; \
859 stn %o5, [%o4 + OT_PREV]; \
860 membar #Sync; \
861 stn %o4, [THREAD_REG + T_ONTRAP]; \
862 add %o4, OT_JMPBUF, %o0; \
863 stn %o7, [%o0 + L_PC]; \
864 stn %sp, [%o0 + L_SP]; \
865 clr %o0;
866
867 #define DDI_NOPROTECT() \
868 ldn [THREAD_REG + T_ONTRAP], %o4; \
869 ldn [%o4 + OT_PREV], %o5; \
870 membar #Sync; \
871 stn %o5, [THREAD_REG + T_ONTRAP];
872
873 /*
874 * DDI_FLAGERR_ACC specific get/put routines.
875 */
876 .align 16
877 ENTRY(i_ddi_prot_get8)
878 DDI_PROTECT() ! set ontrap protection
879 ldub [%o1], %o2 ! do the io access
880 DDI_NOPROTECT() ! remove protection & ret
881 retl
882 mov %o2, %o0 ! set return value
883 SET_SIZE(i_ddi_prot_get8)
884
885 .align 16
886 ENTRY(i_ddi_prot_get16)
887 DDI_PROTECT() ! set ontrap protection
888 lduh [%o1], %o2 ! do the io access
889 DDI_NOPROTECT() ! remove protection & ret
890 retl
891 mov %o2, %o0 ! set return value
892 SET_SIZE(i_ddi_prot_get16)
893
894 .align 16
895 ENTRY(i_ddi_prot_get32)
896 DDI_PROTECT() ! set ontrap protection
897 ld [%o1], %o2 ! do the io access
898 DDI_NOPROTECT() ! remove protection & ret
899 retl
900 mov %o2, %o0 ! set return value
901 SET_SIZE(i_ddi_prot_get32)
902
903 .align 16
904 ENTRY(i_ddi_prot_get64)
905 DDI_PROTECT() ! set ontrap protection
906 ldx [%o1], %o2 ! do the io access
907 DDI_NOPROTECT() ! remove protection & ret
908 retl
909 mov %o2, %o0 ! set return value
910 SET_SIZE(i_ddi_prot_get64)
911
912 .align 16
913 ENTRY(i_ddi_prot_put8)
914 stub %o2, [%o1] ! do the io access
915 retl
916 membar #Sync;
917 SET_SIZE(i_ddi_prot_put8)
918
919 .align 16
920 ENTRY(i_ddi_prot_put16)
921 stuh %o2, [%o1] ! do the io access
922 retl
923 membar #Sync;
924 SET_SIZE(i_ddi_prot_put16)
925
926 .align 16
927 ENTRY(i_ddi_prot_put32)
928 st %o2, [%o1] ! do the io access
929 retl
930 membar #Sync;
931 SET_SIZE(i_ddi_prot_put32)
932
933 .align 16
934 ENTRY(i_ddi_prot_put64)
935 stx %o2, [%o1] ! do the io access
936 retl
937 membar #Sync;
938 SET_SIZE(i_ddi_prot_put64)
939
940 .align 16
941 ENTRY(i_ddi_prot_rep_get8)
942 DDI_PROTECT() ! set ontrap protection
943 tst %o0 ! check access error
944 bnz,a 1f
945 nop
946 DDI_REP_GET(1,ub)
947 1:
948 DDI_NOPROTECT() ! remove protection & ret
949 retl
950 nop
951 SET_SIZE(i_ddi_prot_rep_get8)
952
953 .align 16
954 ENTRY(i_ddi_prot_rep_get16)
955 DDI_PROTECT() ! set ontrap protection
956 tst %o0 ! check access error
957 bnz,a 1f
958 nop
959 DDI_REP_GET(2,uh)
960 1:
961 DDI_NOPROTECT() ! remove protection & ret
962 retl
963 nop
964 SET_SIZE(i_ddi_prot_rep_get16)
965
966 .align 16
967 ENTRY(i_ddi_prot_rep_get32)
968 DDI_PROTECT() ! set ontrap protection
969 tst %o0 ! check access error
970 bnz,a 1f
971 nop
972 DDI_REP_GET(4,/**/)
973 1:
974 DDI_NOPROTECT() ! remove protection & ret
975 retl
976 nop
977 SET_SIZE(i_ddi_prot_rep_get32)
978
979 .align 16
980 ENTRY(i_ddi_prot_rep_get64)
981 DDI_PROTECT() ! set ontrap protection
982 tst %o0 ! check access error
983 bnz,a 1f
984 nop
985 DDI_REP_GET(8,x)
986 1:
987 DDI_NOPROTECT() ! remove protection & ret
988 retl
989 nop
990 SET_SIZE(i_ddi_prot_rep_get64)
991
992 .align 16
993 ENTRY(i_ddi_prot_rep_put8)
994 DDI_REP_PUT(1,ub)
995 retl
996 membar #Sync;
997 SET_SIZE(i_ddi_prot_rep_put8)
998
999 .align 16
1000 ENTRY(i_ddi_prot_rep_put16)
1001 DDI_REP_PUT(2,uh)
1002 retl
1003 membar #Sync;
1004 SET_SIZE(i_ddi_prot_rep_put16)
1005
1006 .align 16
1007 ENTRY(i_ddi_prot_rep_put32)
1008 DDI_REP_PUT(4,/**/)
1009 retl
1010 membar #Sync;
1011 SET_SIZE(i_ddi_prot_rep_put32)
1012
1013 .align 16
1014 ENTRY(i_ddi_prot_rep_put64)
1015 DDI_REP_PUT(8,x)
1016 retl
1017 membar #Sync;
1018 SET_SIZE(i_ddi_prot_rep_put64)
1019
1020 /*
1021 * Common DDI_CAUTIOUS_ACC routine called from cautious access routines
1022 * in ddi_impl.c
1023 */
1024 ENTRY(i_ddi_caut_get)
1025 rdpr %pstate, %o3 ! check ints
1026 andcc %o3, PSTATE_IE, %g0
1027 bz,a cautdone
1028 nop
1029 wrpr %o3, PSTATE_IE, %pstate
1030 cmp %o0, 8 ! 64-bit?
1031 bne,a .get_int
1032 cmp %o0, 4 ! 32-bit?
1033 ldx [%o1], %g1
1034 ba .getdone
1035 stx %g1, [%o2]
1036 .get_int:
1037 bne,a .get_half
1038 cmp %o0, 2 ! 16-bit?
1039 lduw [%o1], %g1
1040 ba .getdone
1041 stuw %g1, [%o2]
1042 .get_half:
1043 bne,a .get_byte
1044 ldub [%o1], %g1 ! 8-bit!
1045 lduh [%o1], %g1
1046 ba .getdone
1047 stuh %g1, [%o2]
1048 .get_byte:
1049 stub %g1, [%o2]
1050 .getdone:
1051 rdpr %pstate, %o3 ! check&enable ints
1052 andcc %o3, PSTATE_IE, %g0
1053 bnz,a cautdone
1054 nop
1055 wrpr %o3, PSTATE_IE, %pstate
1056 cautdone:
1057 retl
1058 nop
1059 SET_SIZE(i_ddi_caut_get)
1060