diff options
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 117 |
1 files changed, 68 insertions, 49 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 2bf295102f6a..c91ae2b67845 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -862,46 +862,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) | |||
862 | * set, we know the host wants us out so let's do it now | 862 | * set, we know the host wants us out so let's do it now |
863 | */ | 863 | */ |
864 | do_ext_interrupt: | 864 | do_ext_interrupt: |
865 | lbz r0, HSTATE_HOST_IPI(r13) | 865 | bl kvmppc_read_intr |
866 | cmpwi r0, 0 | 866 | cmpdi r3, 0 |
867 | bne ext_interrupt_to_host | 867 | bgt ext_interrupt_to_host |
868 | |||
869 | /* Now read the interrupt from the ICP */ | ||
870 | ld r5, HSTATE_XICS_PHYS(r13) | ||
871 | li r7, XICS_XIRR | ||
872 | cmpdi r5, 0 | ||
873 | beq- ext_interrupt_to_host | ||
874 | lwzcix r3, r5, r7 | ||
875 | rlwinm. r0, r3, 0, 0xffffff | ||
876 | sync | ||
877 | beq 3f /* if nothing pending in the ICP */ | ||
878 | |||
879 | /* We found something in the ICP... | ||
880 | * | ||
881 | * If it's not an IPI, stash it in the PACA and return to | ||
882 | * the host, we don't (yet) handle directing real external | ||
883 | * interrupts directly to the guest | ||
884 | */ | ||
885 | cmpwi r0, XICS_IPI | ||
886 | bne ext_stash_for_host | ||
887 | |||
888 | /* It's an IPI, clear the MFRR and EOI it */ | ||
889 | li r0, 0xff | ||
890 | li r6, XICS_MFRR | ||
891 | stbcix r0, r5, r6 /* clear the IPI */ | ||
892 | stwcix r3, r5, r7 /* EOI it */ | ||
893 | sync | ||
894 | |||
895 | /* We need to re-check host IPI now in case it got set in the | ||
896 | * meantime. If it's clear, we bounce the interrupt to the | ||
897 | * guest | ||
898 | */ | ||
899 | lbz r0, HSTATE_HOST_IPI(r13) | ||
900 | cmpwi r0, 0 | ||
901 | bne- 1f | ||
902 | 868 | ||
903 | /* Allright, looks like an IPI for the guest, we need to set MER */ | 869 | /* Allright, looks like an IPI for the guest, we need to set MER */ |
904 | 3: | ||
905 | /* Check if any CPU is heading out to the host, if so head out too */ | 870 | /* Check if any CPU is heading out to the host, if so head out too */ |
906 | ld r5, HSTATE_KVM_VCORE(r13) | 871 | ld r5, HSTATE_KVM_VCORE(r13) |
907 | lwz r0, VCORE_ENTRY_EXIT(r5) | 872 | lwz r0, VCORE_ENTRY_EXIT(r5) |
@@ -930,17 +895,6 @@ do_ext_interrupt: | |||
930 | mtspr SPRN_LPCR, r8 | 895 | mtspr SPRN_LPCR, r8 |
931 | b fast_guest_return | 896 | b fast_guest_return |
932 | 897 | ||
933 | /* We raced with the host, we need to resend that IPI, bummer */ | ||
934 | 1: li r0, IPI_PRIORITY | ||
935 | stbcix r0, r5, r6 /* set the IPI */ | ||
936 | sync | ||
937 | b ext_interrupt_to_host | ||
938 | |||
939 | ext_stash_for_host: | ||
940 | /* It's not an IPI and it's for the host, stash it in the PACA | ||
941 | * before exit, it will be picked up by the host ICP driver | ||
942 | */ | ||
943 | stw r3, HSTATE_SAVED_XIRR(r13) | ||
944 | ext_interrupt_to_host: | 898 | ext_interrupt_to_host: |
945 | 899 | ||
946 | guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ | 900 | guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ |
@@ -1816,6 +1770,71 @@ machine_check_realmode: | |||
1816 | b fast_interrupt_c_return | 1770 | b fast_interrupt_c_return |
1817 | 1771 | ||
1818 | /* | 1772 | /* |
1773 | * Determine what sort of external interrupt is pending (if any). | ||
1774 | * Returns: | ||
1775 | * 0 if no interrupt is pending | ||
1776 | * 1 if an interrupt is pending that needs to be handled by the host | ||
1777 | * -1 if there was a guest wakeup IPI (which has now been cleared) | ||
1778 | */ | ||
1779 | kvmppc_read_intr: | ||
1780 | /* see if a host IPI is pending */ | ||
1781 | li r3, 1 | ||
1782 | lbz r0, HSTATE_HOST_IPI(r13) | ||
1783 | cmpwi r0, 0 | ||
1784 | bne 1f | ||
1785 | |||
1786 | /* Now read the interrupt from the ICP */ | ||
1787 | ld r6, HSTATE_XICS_PHYS(r13) | ||
1788 | li r7, XICS_XIRR | ||
1789 | cmpdi r6, 0 | ||
1790 | beq- 1f | ||
1791 | lwzcix r0, r6, r7 | ||
1792 | rlwinm. r3, r0, 0, 0xffffff | ||
1793 | sync | ||
1794 | beq 1f /* if nothing pending in the ICP */ | ||
1795 | |||
1796 | /* We found something in the ICP... | ||
1797 | * | ||
1798 | * If it's not an IPI, stash it in the PACA and return to | ||
1799 | * the host, we don't (yet) handle directing real external | ||
1800 | * interrupts directly to the guest | ||
1801 | */ | ||
1802 | cmpwi r3, XICS_IPI /* if there is, is it an IPI? */ | ||
1803 | li r3, 1 | ||
1804 | bne 42f | ||
1805 | |||
1806 | /* It's an IPI, clear the MFRR and EOI it */ | ||
1807 | li r3, 0xff | ||
1808 | li r8, XICS_MFRR | ||
1809 | stbcix r3, r6, r8 /* clear the IPI */ | ||
1810 | stwcix r0, r6, r7 /* EOI it */ | ||
1811 | sync | ||
1812 | |||
1813 | /* We need to re-check host IPI now in case it got set in the | ||
1814 | * meantime. If it's clear, we bounce the interrupt to the | ||
1815 | * guest | ||
1816 | */ | ||
1817 | lbz r0, HSTATE_HOST_IPI(r13) | ||
1818 | cmpwi r0, 0 | ||
1819 | bne- 43f | ||
1820 | |||
1821 | /* OK, it's an IPI for us */ | ||
1822 | li r3, -1 | ||
1823 | 1: blr | ||
1824 | |||
1825 | 42: /* It's not an IPI and it's for the host, stash it in the PACA | ||
1826 | * before exit, it will be picked up by the host ICP driver | ||
1827 | */ | ||
1828 | stw r0, HSTATE_SAVED_XIRR(r13) | ||
1829 | b 1b | ||
1830 | |||
1831 | 43: /* We raced with the host, we need to resend that IPI, bummer */ | ||
1832 | li r0, IPI_PRIORITY | ||
1833 | stbcix r0, r6, r8 /* set the IPI */ | ||
1834 | sync | ||
1835 | b 1b | ||
1836 | |||
1837 | /* | ||
1819 | * Save away FP, VMX and VSX registers. | 1838 | * Save away FP, VMX and VSX registers. |
1820 | * r3 = vcpu pointer | 1839 | * r3 = vcpu pointer |
1821 | */ | 1840 | */ |