@@ -254,6 +254,9 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
254
254
if (cs -> gicr_typer & GICR_TYPER_PLPIS ) {
255
255
if (value & GICR_CTLR_ENABLE_LPIS ) {
256
256
cs -> gicr_ctlr |= GICR_CTLR_ENABLE_LPIS ;
257
+ /* Check for any pending interr in pending table */
258
+ gicv3_redist_update_lpi (cs );
259
+ gicv3_redist_update (cs );
257
260
} else {
258
261
cs -> gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS ;
259
262
}
@@ -532,6 +535,144 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
532
535
return r ;
533
536
}
534
537
538
+ static void gicv3_redist_check_lpi_priority (GICv3CPUState * cs , int irq )
539
+ {
540
+ AddressSpace * as = & cs -> gic -> dma_as ;
541
+ uint64_t lpict_baddr ;
542
+ uint8_t lpite ;
543
+ uint8_t prio ;
544
+
545
+ lpict_baddr = cs -> gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK ;
546
+
547
+ address_space_read (as , lpict_baddr + ((irq - GICV3_LPI_INTID_START ) *
548
+ sizeof (lpite )), MEMTXATTRS_UNSPECIFIED , & lpite ,
549
+ sizeof (lpite ));
550
+
551
+ if (!(lpite & LPI_CTE_ENABLED )) {
552
+ return ;
553
+ }
554
+
555
+ if (cs -> gic -> gicd_ctlr & GICD_CTLR_DS ) {
556
+ prio = lpite & LPI_PRIORITY_MASK ;
557
+ } else {
558
+ prio = ((lpite & LPI_PRIORITY_MASK ) >> 1 ) | 0x80 ;
559
+ }
560
+
561
+ if ((prio < cs -> hpplpi .prio ) ||
562
+ ((prio == cs -> hpplpi .prio ) && (irq <= cs -> hpplpi .irq ))) {
563
+ cs -> hpplpi .irq = irq ;
564
+ cs -> hpplpi .prio = prio ;
565
+ /* LPIs are always non-secure Grp1 interrupts */
566
+ cs -> hpplpi .grp = GICV3_G1NS ;
567
+ }
568
+ }
569
+
570
+ void gicv3_redist_update_lpi (GICv3CPUState * cs )
571
+ {
572
+ /*
573
+ * This function scans the LPI pending table and for each pending
574
+ * LPI, reads the corresponding entry from LPI configuration table
575
+ * to extract the priority info and determine if the current LPI
576
+ * priority is lower than the last computed high priority lpi interrupt.
577
+ * If yes, replace current LPI as the new high priority lpi interrupt.
578
+ */
579
+ AddressSpace * as = & cs -> gic -> dma_as ;
580
+ uint64_t lpipt_baddr ;
581
+ uint32_t pendt_size = 0 ;
582
+ uint8_t pend ;
583
+ int i , bit ;
584
+ uint64_t idbits ;
585
+
586
+ idbits = MIN (FIELD_EX64 (cs -> gicr_propbaser , GICR_PROPBASER , IDBITS ),
587
+ GICD_TYPER_IDBITS );
588
+
589
+ if (!(cs -> gicr_ctlr & GICR_CTLR_ENABLE_LPIS ) || !cs -> gicr_propbaser ||
590
+ !cs -> gicr_pendbaser ) {
591
+ return ;
592
+ }
593
+
594
+ cs -> hpplpi .prio = 0xff ;
595
+
596
+ lpipt_baddr = cs -> gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK ;
597
+
598
+ /* Determine the highest priority pending interrupt among LPIs */
599
+ pendt_size = (1ULL << (idbits + 1 ));
600
+
601
+ for (i = GICV3_LPI_INTID_START / 8 ; i < pendt_size / 8 ; i ++ ) {
602
+ address_space_read (as , lpipt_baddr + i , MEMTXATTRS_UNSPECIFIED , & pend ,
603
+ sizeof (pend ));
604
+
605
+ while (pend ) {
606
+ bit = ctz32 (pend );
607
+ gicv3_redist_check_lpi_priority (cs , i * 8 + bit );
608
+ pend &= ~(1 << bit );
609
+ }
610
+ }
611
+ }
612
+
613
+ void gicv3_redist_lpi_pending (GICv3CPUState * cs , int irq , int level )
614
+ {
615
+ /*
616
+ * This function updates the pending bit in lpi pending table for
617
+ * the irq being activated or deactivated.
618
+ */
619
+ AddressSpace * as = & cs -> gic -> dma_as ;
620
+ uint64_t lpipt_baddr ;
621
+ bool ispend = false;
622
+ uint8_t pend ;
623
+
624
+ /*
625
+ * get the bit value corresponding to this irq in the
626
+ * lpi pending table
627
+ */
628
+ lpipt_baddr = cs -> gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK ;
629
+
630
+ address_space_read (as , lpipt_baddr + ((irq / 8 ) * sizeof (pend )),
631
+ MEMTXATTRS_UNSPECIFIED , & pend , sizeof (pend ));
632
+
633
+ ispend = extract32 (pend , irq % 8 , 1 );
634
+
635
+ /* no change in the value of pending bit, return */
636
+ if (ispend == level ) {
637
+ return ;
638
+ }
639
+ pend = deposit32 (pend , irq % 8 , 1 , level ? 1 : 0 );
640
+
641
+ address_space_write (as , lpipt_baddr + ((irq / 8 ) * sizeof (pend )),
642
+ MEMTXATTRS_UNSPECIFIED , & pend , sizeof (pend ));
643
+
644
+ /*
645
+ * check if this LPI is better than the current hpplpi, if yes
646
+ * just set hpplpi.prio and .irq without doing a full rescan
647
+ */
648
+ if (level ) {
649
+ gicv3_redist_check_lpi_priority (cs , irq );
650
+ } else {
651
+ if (irq == cs -> hpplpi .irq ) {
652
+ gicv3_redist_update_lpi (cs );
653
+ }
654
+ }
655
+ }
656
+
657
+ void gicv3_redist_process_lpi (GICv3CPUState * cs , int irq , int level )
658
+ {
659
+ uint64_t idbits ;
660
+
661
+ idbits = MIN (FIELD_EX64 (cs -> gicr_propbaser , GICR_PROPBASER , IDBITS ),
662
+ GICD_TYPER_IDBITS );
663
+
664
+ if (!(cs -> gicr_ctlr & GICR_CTLR_ENABLE_LPIS ) || !cs -> gicr_propbaser ||
665
+ !cs -> gicr_pendbaser || (irq > (1ULL << (idbits + 1 )) - 1 ) ||
666
+ irq < GICV3_LPI_INTID_START ) {
667
+ return ;
668
+ }
669
+
670
+ /* set/clear the pending bit for this irq */
671
+ gicv3_redist_lpi_pending (cs , irq , level );
672
+
673
+ gicv3_redist_update (cs );
674
+ }
675
+
535
676
void gicv3_redist_set_irq (GICv3CPUState * cs , int irq , int level )
536
677
{
537
678
/* Update redistributor state for a change in an external PPI input line */
0 commit comments