Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / ontario / 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.2 07/05/04 SMI"
50
51 .file "intr.s"
52
53#include <sys/asm_linkage.h>
54#include <sys/htypes.h>
55#include <hprivregs.h>
56#include <asi.h>
57#include <fpga.h>
58#include <ldc.h>
59#include <iob.h>
60
61#include <offsets.h>
62#include <vcpu.h>
63#include <abort.h>
64#include <util.h>
65
66 /*
67 * fpga_mondo
68 *
69 * %g1 - cpup
70 */
71 ENTRY(fpga_intr)
72 FPGA_MBOX_INT_DISABLE(IRQ_QUEUE_IN|IRQ_QUEUE_OUT|IRQ_LDC_OUT, %g2, %g3)
73 CLEAR_INT_CTL_PEND(%g2, %g3)
74
75#ifdef CONFIG_SVC
76 ba,pt %xcc, svc_isr
77 nop
78#endif
79
80 retry
81 SET_SIZE(fpga_intr)
82
83
84 /*
85 * ssi_intr_redistribution
86 *
87 * If this cpu is handling ssi intrs, move them to the tgt cpu.
88 * Once the registers are reprogrammed, we send an FPGA intr
89 * to the tgt cpu. We do this to prevent any intrs from being
90 * lost
91 *
92 * %g1 - this cpu id
93 * %g2 - tgt cpu id
94 */
95 ENTRY_NP(ssi_intr_redistribution)
96 STRAND_PUSH(%g7, %g3, %g4)
97 setx IOBBASE, %g3, %g4
98 ! %g4 = IOB Base address
99
100 /* SSI Error interrupt */
101.ssi_err_change_cpu:
102 ldx [%g4 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSIERR)], %g3
103 srlx %g3, INT_MAN_CPU_SHIFT, %g5 ! int_man.cpu
104 and %g5, INT_MAN_CPU_MASK, %g5
105 cmp %g5, %g1
106 bne,pt %xcc, .ssi_intr_change_cpu
107 nop
108
109 ! clear the current cpu value
110 mov INT_MAN_CPU_MASK, %g5
111 sllx %g5, INT_MAN_CPU_SHIFT, %g5
112 andn %g3, %g5, %g3
113 sllx %g2, INT_MAN_CPU_SHIFT, %g6
114 or %g6, %g3, %g3
115
116 stx %g3, [%g4 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSIERR)]
117
118 /* SSI Interrupt */
119.ssi_intr_change_cpu:
120 ldx [%g4 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSI)], %g3
121 srlx %g3, INT_MAN_CPU_SHIFT, %g5 ! int_man.cpu
122 and %g5, INT_MAN_CPU_MASK, %g5
123 cmp %g5, %g1
124 bne,pt %xcc, .mondo_errs_intr_change_cpu
125 nop
126
127 ! clear the current cpu value
128 mov INT_MAN_CPU_MASK, %g5
129 sllx %g5, INT_MAN_CPU_SHIFT, %g5
130 andn %g3, %g5, %g3
131 sllx %g2, INT_MAN_CPU_SHIFT, %g6
132 or %g6, %g3, %g3
133
134 stx %g3, [%g4 + INT_MAN + INT_MAN_DEV_OFF(IOBDEV_SSI)]
135
136 ! send a ssi intr to other cpu so we don't miss any intrs
137 sllx %g2, INT_VEC_DIS_VCID_SHIFT, %g5
138 or %g5, VECINTR_FPGA, %g5
139 stxa %g5, [%g0]ASI_INTR_UDB_W
140.mondo_errs_intr_change_cpu:
141
142 STRAND_POP(%g7, %g3)
143 HVRET
144 SET_SIZE(ssi_intr_redistribution)
145
146#ifdef CONFIG_FPGA /* { */
147
148#define INT_ENABLE(x) \
149 ba isr_common ;\
150 mov x, %g1
151
152/*
153 * Handles the LDC interrupt from the SP.
154 */
155 ENTRY_NP(svc_ldc_tx_intr)
156#ifdef INTR_DEBUG
157 PRINT("got LDX TX\r\n")
158#endif
159
160 setx FPGA_LDCOUT_BASE, %g3, %g5
161 ldub [%g5 + FPGA_Q_STATUS], %g3 ! read status
162
163 btst SP_LDC_STATE_CHG, %g3 ! Notification for channel
164 bz %xcc, 1f ! state change on the SP side
165 nop
166 set SP_LDC_STATE_CHG, %g1
167 stub %g1, [%g5 + FPGA_Q_STATUS] ! clear this bit
168
169 HVCALL(svc_ldc_reset_intr)
1701:
171 setx FPGA_LDCOUT_BASE, %g3, %g5
172 ldub [%g5 + FPGA_Q_STATUS], %g3 ! read status
173
174 btst SP_LDC_DATA, %g3 ! Notification for data packets
175 bz %xcc, 1f ! available in SRAM
176 nop
177 set SP_LDC_DATA, %g1
178 stub %g1, [%g5 + FPGA_Q_STATUS] ! clear this bit
179
180#ifdef INTR_DEBUG
181 PRINT("LDX TX data available\r\n")
182#endif
183 HVCALL(svc_ldc_data_available)
1841:
185 setx FPGA_LDCOUT_BASE, %g3, %g5
186 ldub [%g5 + FPGA_Q_STATUS], %g3 ! read status
187
188 btst SP_LDC_SPACE, %g3 ! Notification that the SP has
189 bz %xcc, 1f ! made room for us in the SRAM
190 nop ! for us to send more data.
191 set SP_LDC_SPACE, %g1
192 stub %g1, [%g5 + FPGA_Q_STATUS] ! clear this bit
193
194 HVCALL(svc_ldc_space_available)
1951:
196 INT_ENABLE(IRQ_LDC_OUT)
197 SET_SIZE(svc_ldc_tx_intr)
198
199
200/*
201 * Handles the LDC BUSY interrupt from the SP which indicates that the
202 * SP has just sent us one or more LDC packets across the SRAM.
203 *
204 * For guest<->SP connections, we simply check to see if there is
205 * any data available on any of the incoming SRAM queues. If so,
206 * we send notification to the appropriate guest (if the guest's queue
207 * is currently empty).
208 *
209 * %g7 - holds calling pc value.
210 */
211 ENTRY_NP(svc_ldc_data_available)
212
213 ROOT_STRUCT(%g1)
214 ldx [%g1 + CONFIG_SP_LDC_MAX_CID], %g2
215 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
216 mulx %g2, SP_LDC_ENDPOINT_SIZE, %g2
217 add %g1, %g2, %g1 ! pointer to last SP endpoint
218
219 ! %g1 = last SP endpoint
220 ! %g7 = return %pc
221
222.one_more_ldc_rx_channel:
223
224 ! %g1 = SP endpoint
225 ! %g7 = return %pc
226
227 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
228 brz %g2, .next_ldc_rx_channel
229 nop
230
231 ! check to see whether there are any packets
232 ! available on this channel.
233
234 ldx [ %g1 + SP_LDC_RX_QD_PA ], %g2
235 ldub [ %g2 + SRAM_LDC_HEAD ], %g3
236 ldub [ %g2 + SRAM_LDC_TAIL ], %g4
237
238 cmp %g3, %g4
239 be %xcc, .next_ldc_rx_channel ! nothing to pick up
240 nop
241
242 ldub [ %g1 + SP_LDC_TARGET_TYPE ], %g3
243 cmp %g3, LDC_GUEST_ENDPOINT
244 be .svc_ldc_guest_target
245 nop
246
247 ! This is a SP<->HV channel so we must read out each packet
248 ! and call the appropriate callback routine for each one.
249
250 ! NOTE: There is no need to grab the RX_LOCK in this situation
251 ! because we are executing with FPGA interrupts off and this
252 ! is the only routine used for receiving data from the SRAM
253 ! since it is a SP<->HV channel.
254
255 ! %g1 = sp endpoint
256 ! %g7 = return %pc
257
258 ! snapshot queue state into our scratch register area
259 ! since we will be copying the data in possibly several
260 ! passes.
261
262 ldx [ %g1 + SP_LDC_RX_QD_PA ], %g5
263 ldub [ %g5 + SRAM_LDC_HEAD ], %g3
264 LDC_SRAM_IDX_TO_OFFSET(%g3)
265 stw %g3, [ %g1 + SP_LDC_RX_SCR_TXHEAD ] ! TX head
266 ldub [ %g5 + SRAM_LDC_TAIL ], %g3
267 LDC_SRAM_IDX_TO_OFFSET(%g3)
268 stw %g3, [ %g1 + SP_LDC_RX_SCR_TXTAIL ] ! TX tail
269 set (SRAM_LDC_QENTRY_SIZE * SRAM_LDC_ENTRIES_PER_QUEUE), %g3
270 stx %g3, [ %g1 + SP_LDC_RX_SCR_TXSIZE ] ! TX size
271
272 ! %g1 = sp endpoint
273 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
274 ! %g7 = return %pc
275
276.read_more_sram_pkts:
277
278 ! %g1 = sp endpoint
279 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
280 ! %g7 = return %pc
281
282 lduw [ %g1 + SP_LDC_RX_SCR_TXHEAD ], %g2
283 lduw [ %g1 + SP_LDC_RX_SCR_TXTAIL ], %g3
284 ldx [ %g1 + SP_LDC_RX_SCR_TXSIZE ], %g4
285
286 LDC_QUEUE_DATA_AVAILABLE(%g2, %g3, %g4)
287 LDC_SRAM_OFFSET_TO_IDX(%g3)
288
289 ! %g1 = sp endpoint
290 ! %g2 = TX head offset
291 ! %g3 = packets of data to copy
292 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
293 ! %g7 = return %pc
294
295 brlez %g3, .done_read_sram_pkts
296 nop
297 add %g2, %g5, %g2 ! PA of TX queue data
298 add %g1, SP_LDC_RX_SCR_PKT, %g4 ! PA of RX scratch buffer
299
300 ! %g1 = sp endpoint
301 ! %g2 = TX head PA
302 ! %g4 = payload buffer
303 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
304 ! %g7 = return %pc
305
306 LDC_COPY_PKT_FROM_SRAM(%g2, %g4, %g3, %g6)
307
308 ! %g1 = sp endpoint
309 ! %g2 = new TX head PA
310 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
311 ! %g7 = return %pc
312
313 ! Now we need to update our scratchpad head pointer
314 sub %g2, %g5, %g2 ! New TX head offset
315 ldx [ %g1 + SP_LDC_RX_SCR_TXSIZE ], %g6
316 cmp %g2, %g6
317 move %xcc, 0, %g2 ! check for wrap around
318 stw %g2, [ %g1 + SP_LDC_RX_SCR_TXHEAD ]
319
320 ! %g1 = sp endpoint
321 ! %g7 = return %pc
322
323 VCPU_STRUCT(%g3)
324 ldx [%g3 + CPU_ROOT], %g3
325 ldx [%g3 + CONFIG_HV_LDCS], %g3 ! get HV endpoint array
326 ldx [%g1 + SP_LDC_TARGET_CHANNEL], %g6 ! and target endpoint
327 mulx %g6, LDC_ENDPOINT_SIZE, %g4
328 add %g3, %g4, %g4 ! and its struct
329
330 ldx [%g4 + LDC_RX_CB], %g6 ! get the callback
331 brz,pn %g6, .done_read_sram_pkts ! if none, drop pkt
332 nop
333
334 STRAND_PUSH(%g1, %g2, %g3)
335 STRAND_PUSH(%g7, %g2, %g3)
336
337 add %g1, SP_LDC_RX_SCR_PKT, %g2 ! payload
338 ldx [%g4 + LDC_RX_CBARG], %g1 ! load the argument
339
340 ! %g1 = call back arg
341 ! %g2 = payload PA
342 ! %g6 = callback
343
344 jmp %g6 ! invoke callback
345 rd %pc, %g7
346
347 ! Assume all %g registers clobbered
348
349 STRAND_POP(%g7, %g2)
350 STRAND_POP(%g1, %g2)
351 ldx [%g1 + SP_LDC_RX_QD_PA], %g5
352
353 ! %g1 = sp endpoint
354 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
355 ! %g7 = return %pc
356
357 ba .read_more_sram_pkts
358 nop
359
360.done_read_sram_pkts:
361
362 ! %g1 = sp endpoint
363 ! %g5 = SRAM Queue base PA (SRAM Queue Descriptor)
364 ! %g7 = return %pc
365
366 lduw [ %g1 + SP_LDC_RX_SCR_TXHEAD ], %g3
367 LDC_SRAM_OFFSET_TO_IDX(%g3)
368 stb %g3, [ %g5 + SRAM_LDC_HEAD ] ! commit the new TX head
369
370 ! %g1 target endpoint
371 LDC_SEND_SP_INTR(%g1, %g3, %g4, SP_LDC_SPACE)
372
373 ! %g1 = SP endpoint
374 ! %g7 = return %pc
375
376 ! At this point, since we just updated the SRAM head index, we
377 ! need re-read the head/tail value from SRAM and make sure no new
378 ! packets were added while we were processing the last one.
379 ba,a .one_more_ldc_rx_channel
380
381.svc_ldc_guest_target:
382
383 ! %g1 = SP endpoint
384 ! %g7 = return %pc
385
386 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
387 brz %g3, .next_ldc_rx_channel
388 nop
389
390 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g6
391 mulx %g6, LDC_ENDPOINT_SIZE, %g4
392 set GUEST_LDC_ENDPOINT, %g5
393 add %g5, %g3, %g5
394 add %g4, %g5, %g3
395
396 ! %g1 = SP endpoint
397 ! %g3 = guest endpoint
398 ! %g7 = return %pc
399
400 ! See if we need to send an interrupt to the recipient
401 ldx [ %g3 + LDC_RX_MAPREG + LDC_MAPREG_CPUP ], %g6
402 brnz,pt %g6, 1f
403 nop
404
405 ! if no target CPU specified, is there a vdev interrupt we
406 ! need to generate?
407 ldx [ %g3 + LDC_RX_VINTR_COOKIE ], %g6
408 brz,pn %g6, .next_ldc_rx_channel ! if not, we are done.
409 nop
410
411 STRAND_PUSH(%g1, %g2, %g4)
412 STRAND_PUSH(%g3, %g2, %g4)
413 STRAND_PUSH(%g7, %g2, %g4)
414
415 mov %g6, %g1
416 HVCALL(vdev_intr_generate)
417
418 STRAND_POP(%g7, %g2)
419 STRAND_POP(%g3, %g2)
420 STRAND_POP(%g1, %g2)
421
422 ! %g1 = SP endpoint
423 ! %g3 = guest endpoint
424 ! %g7 = return %pc
425
426 ba .next_ldc_rx_channel
427 nop
4281:
429 ! %g1 = SP endpoint
430 ! %g3 = guest endpoint
431 ! %g6 = target cpu struct
432 ! %g7 = return %pc
433
434 ! Only need to send notification if guest RX queue is empty.
435 ! No synchronization issues with respect to lost notification here
436 ! because the guest's rx_set_qhead routine pulls data from the SRAM
437 ! after updating the head pointer with the guest specified value.
438 lduw [ %g3 + LDC_RX_QHEAD ], %g4
439 lduw [ %g3 + LDC_RX_QTAIL ], %g5
440 cmp %g4, %g5
441 bne %xcc, .next_ldc_rx_channel
442 nop
443
444 ! %g1 = SP endpoint
445 ! %g3 = guest endpoint
446 ! %g6 = target cpu struct
447 ! %g7 = return %pc
448 STRAND_PUSH(%g1, %g2, %g4)
449 STRAND_PUSH(%g7, %g2, %g4)
450 STRAND_PUSH(%g6, %g2, %g4)
451 HVCALL(hv_ldc_cpu_notify)
452 STRAND_POP(%g6, %g2)
453 STRAND_POP(%g7, %g2)
454 STRAND_POP(%g1, %g2)
455
456 ! %g1 = SP endpoint
457 ! %g7 = return %pc
458
459.next_ldc_rx_channel:
460
461 ! %g1 = SP endpoint
462 ! %g7 = return %pc
463
464 ROOT_STRUCT(%g2)
465 ldx [%g2 + CONFIG_SP_LDCS], %g2 ! first SP endpoint
466 cmp %g1, %g2 ! did we just process it?
467 bgu,pt %xcc, .one_more_ldc_rx_channel
468 sub %g1, SP_LDC_ENDPOINT_SIZE, %g1
469
470 HVRET
471 SET_SIZE(svc_ldc_data_available)
472
473
474/*
475 * Handles the LDC ACK interrupt from the SP which indicates that the
476 * SP has freed up some room in the SRAM LDC queues for us so that we
477 * may once again send more packets if needed.
478 *
479 * %g7 - holds calling pc value.
480 */
481 ENTRY_NP(svc_ldc_space_available)
482
483 ROOT_STRUCT(%g1)
484 ldx [%g1 + CONFIG_SP_LDC_MAX_CID], %g2
485 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
486 mulx %g2, SP_LDC_ENDPOINT_SIZE, %g2
487 add %g1, %g2, %g1 ! pointer to last SP endpoint
488 clr %g6 ! SP notification flag
489
490 ! %g1 = last SP endpoint
491 ! %g6 = 0 (notification flag)
492 ! %g7 = return PC
493
494.one_more_ldc_tx_channel:
495
496 ! %g1 = SP endpoint
497 ! %g6 = (notification flag)
498 ! %g7 = return PC
499
500 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
501 brz %g2, .next_ldc_tx_channel
502 nop
503
504 ! If this is a SP <-> HV connection (guest ptr==NULL) then
505 ! there is nothing really to do.
506 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
507 brz %g3, .next_ldc_tx_channel
508 nop
509
510 ! SP <-> Guest channel
511
512 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g4
513 mulx %g4, LDC_ENDPOINT_SIZE, %g4
514 set GUEST_LDC_ENDPOINT, %g5
515 add %g5, %g3, %g5
516 add %g4, %g5, %g3
517
518 ! %g1 = SP endpoint
519 ! %g3 = guest endpoint
520 ! %g6 = (notification flag)
521 ! %g7 = return PC
522
523 ! Nothing to send if guest TX queue is empty
524 lduw [ %g3 + LDC_TX_QHEAD ], %g4
525 lduw [ %g3 + LDC_TX_QTAIL ], %g5
526 cmp %g4, %g5
527 be %xcc, .next_ldc_tx_channel
528 nop
529
530 ! %g1 = SP endpoint
531 ! %g3 = guest endpoint
532
533 mov %g3, %g2
534 mov %g1, %g3
535
536 ! %g2 = guest endpoint
537 ! %g3 = sp endpoint
538
539 STRAND_PUSH(%g2, %g1, %g4) ! save guest endpoint
540
541 add %g3, SP_LDC_TX_LOCK, %g5
542 SPINLOCK_ENTER(%g5, %g1, %g4)
543
544 STRAND_PUSH(%g7, %g4, %g5)
545 HVCALL(sram_ldc_push_data) ! %g3 (sp endpoint) preserved
546 STRAND_POP(%g7, %g5)
547
548 add %g3, SP_LDC_TX_LOCK, %g5
549 SPINLOCK_EXIT(%g5)
550
551 mov %g3, %g1
552
553 clr %g3
554 movrnz %g2, 1, %g3 ! %g2 = send interrupt flag
555 or %g6, %g3, %g6
556
557 ! %g1 = sp endpoint
558 ! %g6 = (notification flag)
559 ! %g7 = return PC
560
561 STRAND_POP(%g2, %g3) ! restore guest endpoint
562
563 ! %g2 = sender's (guest) endpoint
564
565 ! We might need to send a 'queue no longer full' interrupt
566 ! in certain situations.
567 ldub [ %g2 + LDC_TXQ_FULL ], %g3
568 brz,pt %g3, .next_ldc_tx_channel
569 nop
570 stb %g0, [ %g2 + LDC_TXQ_FULL ]
571
572 ldx [%g2 + LDC_RX_VINTR_COOKIE], %g2
573 brz %g2, .next_ldc_tx_channel
574 nop
575
576 ! save off registers
577 STRAND_PUSH(%g1, %g3, %g4)
578 STRAND_PUSH(%g6, %g3, %g4)
579 STRAND_PUSH(%g7, %g3, %g4)
580
581 mov %g2, %g1
582 HVCALL(vdev_intr_generate)
583
584 ! restore registers
585 STRAND_POP(%g7, %g3)
586 STRAND_POP(%g6, %g3)
587 STRAND_POP(%g1, %g3)
588
589.next_ldc_tx_channel:
590
591 ! %g1 = SP endpoint
592 ! %g6 = (notification flag)
593 ! %g7 = return PC
594
595 ROOT_STRUCT(%g2)
596 ldx [%g2 + CONFIG_SP_LDCS], %g2 ! first SP endpoint
597 cmp %g1, %g2 ! did we just process it?
598 bgu,pt %xcc, .one_more_ldc_tx_channel
599 sub %g1, SP_LDC_ENDPOINT_SIZE, %g1
600
601 ! Done checking all SRAM queues
602 btst 1, %g6
603 bz %xcc, 1f ! skip TX notification if flag is clear
604 nop
605
606 ! %g1 target endpoint
607 LDC_SEND_SP_INTR(%g1, %g6, %g4, SP_LDC_DATA)
6081:
609 HVRET
610 SET_SIZE(svc_ldc_space_available)
611
612
613/*
614 * Called when the SP sends us notification for a channel reset so that
615 * we can forward the notification interrupt to a guest if necessary.
616 *
617 * %g7 - holds calling pc value.
618 */
619 ENTRY_NP(svc_ldc_reset_intr)
620 ROOT_STRUCT(%g1)
621 ldx [%g1 + CONFIG_SP_LDC_MAX_CID], %g2
622 ldx [%g1 + CONFIG_SP_LDCS], %g1 ! get SP endpoint array
623
624 mulx %g2, SP_LDC_ENDPOINT_SIZE, %g2
625 add %g1, %g2, %g1 ! pointer to last SP endpoint
626
627.one_more_sram_channel:
628
629 ! %g1 = SP endpoint
630
631 ldub [%g1 + SP_LDC_IS_LIVE], %g2 ! is channel open?
632 brz %g2, .next_ldc_sram_channel
633 nop
634
635 ! check to see whether there is a reset notification pending
636 ! for this channel.
637 ldx [ %g1 + SP_LDC_TX_QD_PA ], %g2
638 ldub [ %g2 + SRAM_LDC_STATE_NOTIFY ], %g3
639 brz,pt %g3, .next_ldc_sram_channel
640 nop
641
642 ! reset notification is pending for this channel
643 stb %g0, [ %g2 + SRAM_LDC_STATE_NOTIFY ] ! clear the flag
644
645 ! For SP<->HV connections (guest ptr==NULL), there is nothing to
646 ! do at this point.
647 ldx [ %g1 + SP_LDC_TARGET_GUEST ], %g3
648 brz %g3, .next_ldc_sram_channel
649 nop
650
651 ldx [ %g1 + SP_LDC_TARGET_CHANNEL ], %g4
652 mulx %g4, LDC_ENDPOINT_SIZE, %g4
653 set GUEST_LDC_ENDPOINT, %g5
654 add %g5, %g3, %g5
655 add %g4, %g5, %g3
656
657 ! %g1 = SP endpoint
658 ! %g3 = guest endpoint
659
660 ! skip notification if no CPU is specified to handle interrupts
661 ldx [ %g3 + LDC_RX_MAPREG + LDC_MAPREG_CPUP ], %g6
662 brz,pn %g6, .next_ldc_sram_channel
663 nop
664
665 ! %g1 = SP endpoint
666 ! %g3 = guest endpoint
667 ! %g6 = target cpu struct
668 STRAND_PUSH(%g1, %g2, %g4)
669 STRAND_PUSH(%g7, %g2, %g4)
670 STRAND_PUSH(%g6, %g2, %g4)
671 HVCALL(hv_ldc_cpu_notify)
672 STRAND_POP(%g6, %g2)
673 STRAND_POP(%g7, %g2)
674 STRAND_POP(%g1, %g2)
675 ! %g1 = SP endpoint
676
677.next_ldc_sram_channel:
678
679 ROOT_STRUCT(%g2)
680 ldx [%g2 + CONFIG_SP_LDCS], %g2 ! first SP endpoint
681 cmp %g1, %g2 ! did we just process it?
682 bgu,pt %xcc, .one_more_sram_channel
683 sub %g1, SP_LDC_ENDPOINT_SIZE, %g1
684
685 HVRET
686 SET_SIZE(svc_ldc_reset_intr)
687
688#endif /* CONFIG_FPGA } */
689