Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / huron / src / ssi.s
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: ssi.s
5*
6* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
7*
8* - Do no alter or remove copyright notices
9*
10* - Redistribution and use of this software in source and binary forms, with
11* or without modification, are permitted provided that the following
12* conditions are met:
13*
14* - Redistribution of source code must retain the above copyright notice,
15* this list of conditions and the following disclaimer.
16*
17* - Redistribution in binary form must reproduce the above copyright notice,
18* this list of conditions and the following disclaimer in the
19* documentation and/or other materials provided with the distribution.
20*
21* Neither the name of Sun Microsystems, Inc. or the names of contributors
22* may be used to endorse or promote products derived from this software
23* without specific prior written permission.
24*
25* This software is provided "AS IS," without a warranty of any kind.
26* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
27* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
28* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
29* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
30* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
31* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
32* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
33* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
34* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
35* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
36* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*
38* You acknowledge that this software is not designed, licensed or
39* intended for use in the design, construction, operation or maintenance of
40* any nuclear facility.
41*
42* ========== Copyright Header End ============================================
43*/
44/*
45 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
46 * Use is subject to license terms.
47 */
48
49 .ident "@(#)ssi.s 1.4 07/06/20 SMI"
50
51 .file "ssi.s"
52
53#ifdef CONFIG_FPGA
54
55#include <sys/asm_linkage.h>
56#include <sys/htypes.h>
57#include <asi.h>
58#include <offsets.h>
59#include <util.h>
60#include <fpga.h>
61#include <ldc.h>
62#include <intr.h>
63#include <vdev_ops.h>
64
65 /*
66 * fpga_intr
67 *
68 * %g1 - cpup
69 */
70 ENTRY(fpga_intr)
71
72 FPGA_MBOX_INT_DISABLE(IRQ_QUEUE_IN|IRQ_QUEUE_OUT|IRQ_LDC_OUT, %g2, %g3)
73
74#ifdef CONFIG_FPGA_UART
75 mov DEVOPS_FPGA, %g1
76 GUEST_STRUCT(%g4)
77 DEVINST2COOKIE(%g4, %g1, %g1, %g5, badtrap)
78
79
80 HVCALL(fpga_uart_mondo_receive)
81
82 VCPU_STRUCT(%g1)
83#endif /* CONFIG_FPGA_UART */
84
85#ifdef CONFIG_SVC
86 ba,pt %xcc, svc_isr
87 nop
88#else
89 retry
90#endif
91 SET_SIZE(fpga_intr)
92
93 /*
94 * Move SSI interrupts from CPU %g1 onto CPU %g2
95 */
96 ENTRY(ssi_redistribute_interrupts)
97
98 setx NCU_BASE, %g3, %g4
99 ldx [%g4 + INT_MAN + INT_MAN_DEV_OFF(NCUDEV_SSIERR)], %g5
100 srl %g5, INTRTGT_DEVSHIFT, %g5
101 and %g5, INTRTGT_CPUMASK, %g5
102 ! %g5 current interrupt target
103 ! %g1 CPU in error
104 cmp %g1, %g5
105 be,pt %xcc, 1f
106 nop
107
108 /*
109 * The CPU in error does not have any interrupts targetted at
110 * it so just exit
111 */
112 HVRET
1131:
114
115 mov %g2, %g1 ! %g1 new interrupt target
116 sllx %g1, 1 * INTRTGT_DEVSHIFT, %g2
117 sllx %g1, 2 * INTRTGT_DEVSHIFT, %g3
118 or %g3, %g2, %g3
119 ROOT_STRUCT(%g2)
120 stx %g3, [%g2 + CONFIG_INTRTGT]
121
122 /*
123 * setup the map registers for the SSI
124 * %g1 intrtgt CPUID array (8-bits per INT_MAN target)
125 * %g4 NCU Base address
126 */
127
128 /*
129 * SSI Error interrupt
130 */
131 srl %g1, INTRTGT_DEVSHIFT, %g1 ! get dev1 bits in bottom
132 and %g1, INTRTGT_CPUMASK, %g3
133 sllx %g3, INT_MAN_CPU_SHIFT, %g3 ! int_man.cpu
134 or %g3, VECINTR_SSIERR, %g3 ! int_man.vecnum
135 stx %g3, [%g4 + INT_MAN + INT_MAN_DEV_OFF(NCUDEV_SSIERR)]
136
137 /*
138 * SSI Interrupt
139 */
140 srl %g1, INTRTGT_DEVSHIFT, %g1 ! get dev2 bits in bottom
141 and %g1, INTRTGT_CPUMASK, %g3
142 sllx %g3, INT_MAN_CPU_SHIFT, %g3 ! int_man.cpu
143 or %g3, VECINTR_FPGA, %g3 ! int_man.vecnum
144 stx %g3, [%g4 + INT_MAN + INT_MAN_DEV_OFF(NCUDEV_SSI)]
145
146 HVRET
147 SET_SIZE(ssi_redistribute_interrupts)
148
149#define INT_ENABLE(x) \
150 ba isr_common ;\
151 mov x, %g1
152
153/*
154 * Handles the LDC interrupt from the SP.
155 */
156 ENTRY_NP(svc_ldc_tx_intr)
157
158#ifdef INTR_DEBUG
159 PRINT("got LDX TX\r\n")
160#endif
161
162 setx FPGA_LDCIN_BASE, %g3, %g5
163 ld [%g5 + FPGA_LDC_RECV_REG], %g3 ! read recv
164
165 ! %g3 RECV register
166.ldc_recv_intrs:
167
168 ! If no more interrupts are pending, exit
169 brz,pn %g3, .svc_ldc_tx_intr_exit
170 .empty
171
172 /*
173 * The RECV register bits [30:16] are for data notifications
174 * for the corresponding channel.
175 *
176 * The RECV register bits [14:0] are for space available
177 * notifications for the corresponding channel.
178 *
179 * RECV register bit[31] is for STATE_CHG notification.
180 */
181
182 ! Find the first bit set in the RECV register
183 neg %g3, %g4
184 xnor %g3, %g4, %g6
185 popc %g6, %g4
186 dec %g4
187
188 ! %g3 RECV register contents
189 ! %g4 first bit set
190 ! %g5 FPGA_LDCIN_BASE
191
192 /*
193 * Clear bit %g4 in RECV register (%g3)
194 */
195 mov 1, %g6
196 sllx %g6, %g4, %g6
197 st %g6, [%g5 + FPGA_LDC_RECV_REG] ! RW1C
198
199 cmp %g4, FPGA_LDC_RECV_TX_CHANNELS ! space notification
200 bl %xcc, .ldc_tx_intr
201 cmp %g4, FPGA_LDC_RECV_RX_CHANNELS ! data notification
202 bl %xcc, .ldc_rx_intr
203 sub %g4, FPGA_LDC_RECV_TX_CHANNELS + 1, %g4 ! bit 16 -> channel 0 ...
204
205 /* FALLTHRU */
206
207.ldc_reset_intr:
208
209#ifdef INTR_DEBUG
210 PRINT("LDX Reset\r\n")
211#endif
212
213 HVCALL(svc_ldc_reset_intr)
214
215 setx FPGA_LDCIN_BASE, %g3, %g5
216 ba,pt %xcc, .ldc_recv_intrs
217 ld [%g5 + FPGA_LDC_RECV_REG], %g3 ! read recv
218
219.ldc_rx_intr:
220
221#ifdef INTR_DEBUG
222 PRINT("LDX TX data available\r\n")
223#endif
224
225 ! %g4 channel number
226 HVCALL(svc_ldc_data_available)
227
228 ! next notification
229 setx FPGA_LDCIN_BASE, %g3, %g5
230 ba,pt %xcc, .ldc_recv_intrs
231 ld [%g5 + FPGA_LDC_RECV_REG], %g3 ! read recv
232
233.ldc_tx_intr:
234
235#ifdef INTR_DEBUG
236 PRINT("LDX TX space available\r\n")
237#endif
238
239 ! %g4 channel number
240 HVCALL(svc_ldc_space_available)
241
242 ! next notification
243 setx FPGA_LDCIN_BASE, %g3, %g5
244 ba,pt %xcc, .ldc_recv_intrs
245 ld [%g5 + FPGA_LDC_RECV_REG], %g3 ! read recv
246
247.svc_ldc_tx_intr_exit:
248
249 ! back to ISR handling
250 INT_ENABLE(IRQ_LDC_OUT)
251 /* NOTREACHED */
252
253 SET_SIZE(svc_ldc_tx_intr)
254
255
256/*
257 * Handles the LDC BUSY interrupt from the SP which indicates that the
258 * SP has just sent us one or more LDC packets across the SRAM.
259 *
260 * For guest<->SP connections, we simply check to see if there is
261 * any data available on any of the incoming SRAM queues. If so,
262 * we send notification to the appropriate guest (if the guest's queue
263 * is currently empty).
264 *
265 * %g4 - channel
266 * %g7 - holds calling pc value.
267 */
268 ENTRY_NP(svc_ldc_data_available)
269
270 ROOT_STRUCT(%g1)
271 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
272 mulx %g4, SP_LDC_ENDPOINT_SIZE, %g2
273 add %g1, %g2, %g1 ! pointer to SP endpoint
274
275 ! %g1 = SP endpoint which received the notification
276 ! %g7 = return %pc
277
278
279
280 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
281 brz %g2, .exit_ldc_rx_channel
282 nop
283
284.one_more_ldc_rx_channel:
285
286 ! check to see whether there are any packets
287 ! available on this channel.
288
289 ldx [ %g1 + SP_LDC_RX_QD_PA ], %g2
290 ldub [ %g2 + SRAM_LDC_HEAD ], %g3
291 ldub [ %g2 + SRAM_LDC_TAIL ], %g4
292
293 cmp %g3, %g4
294 be %xcc, .exit_ldc_rx_channel ! nothing to pick up
295 nop
296
297 ldub [ %g1 + SP_LDC_TARGET_TYPE ], %g3
298 cmp %g3, LDC_GUEST_ENDPOINT
299 be .svc_ldc_guest_target
300 nop
301
302 ! This is a SP<->HV channel so we must read out each packet
303 ! and call the appropriate callback routine for each one.
304
305 ! NOTE: There is no need to grab the RX_LOCK in this situation
306 ! because we are executing with FPGA interrupts off and this
307 ! is the only routine used for receiving data from the SRAM
308 ! since it is a SP<->HV channel.
309
310 ! %g1 = sp endpoint
311 ! %g7 = return %pc
312
313 ! snapshot queue state into our scratch register area
314 ! since we will be copying the data in possibly several
315 ! passes.
316
317 ldx [ %g1 + SP_LDC_RX_QD_PA ], %g5
318 ldub [ %g5 + SRAM_LDC_HEAD ], %g3
319 LDC_SRAM_IDX_TO_OFFSET(%g3)
320 stw %g3, [ %g1 + SP_LDC_RX_SCR_TXHEAD ] ! TX head
321 ldub [ %g5 + SRAM_LDC_TAIL ], %g3
322 LDC_SRAM_IDX_TO_OFFSET(%g3)
323 stw %g3, [ %g1 + SP_LDC_RX_SCR_TXTAIL ] ! TX tail
324 set (SRAM_LDC_QENTRY_SIZE * SRAM_LDC_ENTRIES_PER_QUEUE), %g3
325 stx %g3, [ %g1 + SP_LDC_RX_SCR_TXSIZE ] ! TX size
326
327 ! %g1 = sp endpoint
328 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
329 ! %g7 = return %pc
330
331.read_more_sram_pkts:
332
333 ! %g1 = sp endpoint
334 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
335 ! %g7 = return %pc
336
337 lduw [ %g1 + SP_LDC_RX_SCR_TXHEAD ], %g2
338 lduw [ %g1 + SP_LDC_RX_SCR_TXTAIL ], %g3
339 ldx [ %g1 + SP_LDC_RX_SCR_TXSIZE ], %g4
340
341 LDC_QUEUE_DATA_AVAILABLE(%g2, %g3, %g4)
342 LDC_SRAM_OFFSET_TO_IDX(%g3)
343
344 ! %g1 = sp endpoint
345 ! %g2 = TX head offset
346 ! %g3 = packets of data to copy
347 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
348 ! %g7 = return %pc
349
350 brlez %g3, .done_read_sram_pkts
351 nop
352
353#ifdef CONFIG_SPLIT_SRAM
354 ldx [ %g1 + SP_LDC_RX_Q_DATA_PA ], %g5 ! queue data PA
355#endif
356
357 add %g2, %g5, %g2 ! PA of TX queue data
358 add %g1, SP_LDC_RX_SCR_PKT, %g4 ! PA of RX scratch buffer
359
360 ! %g1 = sp endpoint
361 ! %g2 = TX head PA
362 ! %g4 = payload buffer
363 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
364 ! - or -
365 ! %g5 = SRAM Queue Data PA (CONFIG_SPLIT_SRAM)
366 ! %g7 = return %pc
367
368 LDC_COPY_PKT_FROM_SRAM(%g2, %g4, %g3, %g6)
369
370 ! %g1 = sp endpoint
371 ! %g2 = new TX head PA
372 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
373 ! %g7 = return %pc
374
375 ! Now we need to update our scratchpad head pointer
376 sub %g2, %g5, %g2 ! New TX head offset
377 ldx [ %g1 + SP_LDC_RX_SCR_TXSIZE ], %g6
378 cmp %g2, %g6
379 move %xcc, 0, %g2 ! check for wrap around
380 stw %g2, [ %g1 + SP_LDC_RX_SCR_TXHEAD ]
381
382 ! %g1 = sp endpoint
383 ! %g7 = return %pc
384
385 VCPU_STRUCT(%g3)
386 ldx [%g3 + CPU_ROOT], %g3
387 ldx [%g3 + CONFIG_HV_LDCS], %g3 ! get HV endpoint array
388 ldx [%g1 + SP_LDC_TARGET_CHANNEL], %g6 ! and target endpoint
389 mulx %g6, LDC_ENDPOINT_SIZE, %g4
390 add %g3, %g4, %g4 ! and its struct
391
392 ldx [%g4 + LDC_RX_CB], %g6 ! get the callback
393 brz,pn %g6, .done_read_sram_pkts ! if none, drop pkt
394 nop
395
396 STRAND_PUSH(%g1, %g2, %g3)
397 STRAND_PUSH(%g7, %g2, %g3)
398
399 add %g1, SP_LDC_RX_SCR_PKT, %g2 ! payload
400 ldx [%g4 + LDC_RX_CBARG], %g1 ! load the argument
401
402 ! %g1 = call back arg
403 ! %g2 = payload PA
404 ! %g6 = callback
405
406 jmp %g6 ! invoke callback
407 rd %pc, %g7
408
409 ! Assume all %g registers clobbered
410
411 STRAND_POP(%g7, %g2)
412 STRAND_POP(%g1, %g2)
413
414#ifndef CONFIG_SPLIT_SRAM
415 ldx [%g1 + SP_LDC_RX_QD_PA], %g5
416#endif
417
418 ! %g1 = sp endpoint
419 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
420 ! %g7 = return %pc
421
422 ba .read_more_sram_pkts
423 nop
424
425.done_read_sram_pkts:
426
427 ! %g1 = sp endpoint
428 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor !CONFIG_SPLIT_SRAM)
429 ! %g7 = return %pc
430
431 lduw [ %g1 + SP_LDC_RX_SCR_TXHEAD ], %g3
432 LDC_SRAM_OFFSET_TO_IDX(%g3)
433#ifdef CONFIG_SPLIT_SRAM
434 ldx [%g1 + SP_LDC_RX_QD_PA], %g5 ! queue data PA
435#endif
436 stb %g3, [ %g5 + SRAM_LDC_HEAD ] ! commit the new TX head
437
438 STRAND_PUSH(%g1, %g2, %g3)
439 ! %g1 target endpoint (clobbered)
440 LDC_SEND_SP_INTR(%g1, %g3, %g4, SP_LDC_SPACE)
441 STRAND_POP(%g1, %g2)
442
443 ! %g1 = SP endpoint
444 ! %g7 = return %pc
445
446 ! At this point, since we just updated the SRAM head index, we
447 ! need re-read the head/tail value from SRAM and make sure no new
448 ! packets were added while we were processing the last one.
449 ba,a .one_more_ldc_rx_channel
450 nop
451
452.svc_ldc_guest_target:
453
454 ! %g1 = SP endpoint
455 ! %g7 = return %pc
456
457 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
458 brz %g3, .exit_ldc_rx_channel
459 nop
460
461 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g6
462 mulx %g6, LDC_ENDPOINT_SIZE, %g4
463 set GUEST_LDC_ENDPOINT, %g5
464 add %g5, %g3, %g5
465 add %g4, %g5, %g3
466
467 ! %g1 = SP endpoint
468 ! %g3 = guest endpoint
469 ! %g7 = return %pc
470
471 ! See if we need to send an interrupt to the recipient
472 ldx [ %g3 + LDC_RX_MAPREG + LDC_MAPREG_CPUP ], %g6
473 brnz,pt %g6, 1f
474 nop
475
476 ! if no target CPU specified, is there a vdev interrupt we
477 ! need to generate?
478 ldx [ %g3 + LDC_RX_VINTR_COOKIE ], %g6
479 brz,pn %g6, .exit_ldc_rx_channel ! if not, we are done.
480 nop
481
482 STRAND_PUSH(%g7, %g2, %g4)
483
484 mov %g6, %g1
485 HVCALL(vdev_intr_generate)
486
487 STRAND_POP(%g7, %g2)
488
489 ! %g1 = SP endpoint
490 ! %g3 = guest endpoint
491 ! %g7 = return %pc
492
493 ba .exit_ldc_rx_channel
494 nop
4951:
496 ! %g1 = SP endpoint
497 ! %g3 = guest endpoint
498 ! %g6 = target cpu struct
499 ! %g7 = return %pc
500
501 ! Only need to send notification if guest RX queue is empty.
502 ! No synchronization issues with respect to lost notification here
503 ! because the guest's rx_set_qhead routine pulls data from the SRAM
504 ! after updating the head pointer with the guest specified value.
505 lduw [ %g3 + LDC_RX_QHEAD ], %g4
506 lduw [ %g3 + LDC_RX_QTAIL ], %g5
507 cmp %g4, %g5
508 bne %xcc, .exit_ldc_rx_channel
509 nop
510
511 ! %g1 = SP endpoint
512 ! %g3 = guest endpoint
513 ! %g6 = target cpu struct
514 ! %g7 = return %pc
515 STRAND_PUSH(%g7, %g2, %g4)
516 HVCALL(hv_ldc_cpu_notify)
517 STRAND_POP(%g7, %g2)
518
519 ! %g7 = return %pc
520
521.exit_ldc_rx_channel:
522
523 HVRET
524 SET_SIZE(svc_ldc_data_available)
525
526
527/*
528 * Handles the LDC ACK interrupt from the SP which indicates that the
529 * SP has freed up some room in the SRAM LDC queues for us so that we
530 * may once again send more packets if needed.
531 *
532 * %g4 - channel which received the notification
533 * %g7 - holds calling pc value.
534 */
535 ENTRY_NP(svc_ldc_space_available)
536
537 STRAND_PUSH(%g7, %g1, %g2)
538
539 ROOT_STRUCT(%g1)
540 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
541 mulx %g4, SP_LDC_ENDPOINT_SIZE, %g2
542 add %g1, %g2, %g1 ! pointer to SP endpoint
543 clr %g6 ! SP notification flag
544
545 ! %g1 = SP endpoint which received t henotication
546 ! %g6 = 0 (notification flag)
547 ! %g7 = return PC
548
549 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
550 brz %g2, .exit_ldc_tx_channel
551 nop
552
553 ! If this is a SP <-> HV connection (guest ptr==NULL) then
554 ! there is nothing really to do.
555 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
556 brz %g3, .exit_ldc_tx_channel
557 nop
558
559 ! SP <-> Guest channel
560
561 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g4
562 mulx %g4, LDC_ENDPOINT_SIZE, %g4
563 set GUEST_LDC_ENDPOINT, %g5
564 add %g5, %g3, %g5
565 add %g4, %g5, %g3
566
567 ! %g1 = SP endpoint
568 ! %g3 = guest endpoint
569 ! %g6 = (notification flag)
570 ! %g7 = return PC
571
572 ! Nothing to send if guest TX queue is empty
573 lduw [ %g3 + LDC_TX_QHEAD ], %g4
574 lduw [ %g3 + LDC_TX_QTAIL ], %g5
575 cmp %g4, %g5
576 be %xcc, .exit_ldc_tx_channel
577 nop
578
579 ! %g1 = SP endpoint
580 ! %g3 = guest endpoint
581
582 mov %g3, %g2
583 mov %g1, %g3
584
585 ! %g2 = guest endpoint
586 ! %g3 = sp endpoint
587
588 STRAND_PUSH(%g2, %g1, %g4) ! save guest endpoint
589
590 add %g3, SP_LDC_TX_LOCK, %g5
591 SPINLOCK_ENTER(%g5, %g1, %g4)
592
593 HVCALL(sram_ldc_push_data) ! %g3 (sp endpoint) preserved
594
595 add %g3, SP_LDC_TX_LOCK, %g5
596 SPINLOCK_EXIT(%g5)
597
598 mov %g3, %g1
599
600 clr %g3
601 movrnz %g2, 1, %g3 ! %g2 = send interrupt flag
602 or %g6, %g3, %g6
603
604 ! %g1 = sp endpoint
605 ! %g6 = (notification flag)
606
607 STRAND_POP(%g2, %g3) ! restore guest endpoint
608
609 ! %g2 = sender's (guest) endpoint
610
611 ! We might need to send a 'queue no longer full' interrupt
612 ! in certain situations.
613 ldub [ %g2 + LDC_TXQ_FULL ], %g3
614 brz,pt %g3, .exit_ldc_tx_channel
615 nop
616 stb %g0, [ %g2 + LDC_TXQ_FULL ]
617
618 ldx [%g2 + LDC_RX_VINTR_COOKIE], %g2
619 brz %g2, .exit_ldc_tx_channel
620 nop
621
622 ! save off registers
623 STRAND_PUSH(%g1, %g3, %g4)
624 STRAND_PUSH(%g6, %g3, %g4)
625
626 mov %g2, %g1
627 HVCALL(vdev_intr_generate)
628
629 ! restore registers
630 STRAND_POP(%g6, %g3)
631 STRAND_POP(%g1, %g3)
632
633.exit_ldc_tx_channel:
634
635 ! Done checking all SRAM queues
636 btst 1, %g6
637 bz %xcc, 1f ! skip TX notification if flag is clear
638 nop
639
640 ! %g1 target endpoint (clobbered)
641 LDC_SEND_SP_INTR(%g1, %g6, %g4, SP_LDC_DATA)
6421:
643 STRAND_POP(%g7, %g5)
644 HVRET
645 SET_SIZE(svc_ldc_space_available)
646
647
648/*
649 * Called when the SP sends us notification for a channel reset so that
650 * we can forward the notification interrupt to a guest if necessary.
651 *
652 * %g7 - holds calling pc value.
653 */
654 ENTRY_NP(svc_ldc_reset_intr)
655 ROOT_STRUCT(%g1)
656 ldx [%g1 + CONFIG_SP_LDC_MAX_CID], %g2
657 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
658
659 mulx %g2, SP_LDC_ENDPOINT_SIZE, %g2
660 add %g1, %g2, %g1 ! pointer to last SP endpoint
661
662.one_more_sram_channel:
663
664 ! %g1 = SP endpoint
665
666 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
667 brz %g2, .next_ldc_sram_channel
668 nop
669
670 ! check to see whether there is a reset notification pending
671 ! for this channel.
672 ldx [ %g1 + SP_LDC_TX_QD_PA ], %g2
673 ldub [ %g2 + SRAM_LDC_STATE_NOTIFY ], %g3
674 brz,pt %g3, .next_ldc_sram_channel
675 nop
676
677 ! reset notification is pending for this channel
678 stb %g0, [ %g2 + SRAM_LDC_STATE_NOTIFY ] ! clear the flag
679
680 ! For SP<->HV connections (guest ptr==NULL), there is nothing to
681 ! do at this point.
682 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
683 brz %g3, .next_ldc_sram_channel
684 nop
685
686 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g4
687 mulx %g4, LDC_ENDPOINT_SIZE, %g4
688 set GUEST_LDC_ENDPOINT, %g5
689 add %g5, %g3, %g5
690 add %g4, %g5, %g3
691
692 ! %g1 = SP endpoint
693 ! %g3 = guest endpoint
694
695 ! skip notification if no CPU is specified to handle interrupts
696 ldx [ %g3 + LDC_RX_MAPREG + LDC_MAPREG_CPUP ], %g6
697 brz,pn %g6, .next_ldc_sram_channel
698 nop
699
700 ! %g1 = SP endpoint
701 ! %g3 = guest endpoint
702 ! %g6 = target cpu struct
703 STRAND_PUSH(%g1, %g2, %g4)
704 STRAND_PUSH(%g7, %g2, %g4)
705 STRAND_PUSH(%g6, %g2, %g4)
706 HVCALL(hv_ldc_cpu_notify)
707 STRAND_POP(%g6, %g2)
708 STRAND_POP(%g7, %g2)
709 STRAND_POP(%g1, %g2)
710 ! %g1 = SP endpoint
711
712.next_ldc_sram_channel:
713
714 ROOT_STRUCT(%g2)
715 ldx [%g2 + CONFIG_SP_LDCS], %g2 ! first SP endpoint
716 cmp %g1, %g2 ! did we just process it?
717 bgu,pt %xcc, .one_more_sram_channel
718 sub %g1, SP_LDC_ENDPOINT_SIZE, %g1
719
720 HVRET
721 SET_SIZE(svc_ldc_reset_intr)
722
723#endif /* CONFIG_FPGA */