aboutsummaryrefslogtreecommitdiff
path: root/hw/psi.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-07-24 09:32:10 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-17 10:33:28 +1100
commit0279d8951ead549fdebce93130a2f6c673081862 (patch)
treeb0fee12867dbf0a4796ec98b3d4b12907d604ab0 /hw/psi.c
parent8110b0595f0de2df18a06e8e9aff66db45872fa7 (diff)
downloadskiboot-0279d8951ead549fdebce93130a2f6c673081862.zip
skiboot-0279d8951ead549fdebce93130a2f6c673081862.tar.gz
skiboot-0279d8951ead549fdebce93130a2f6c673081862.tar.bz2
Fast reboot for P8
This is an experimental patch that implements "Fast reboot" on P8 machines. The basic idea is that when the OS calls OPAL reboot, we gather all the threads in the system using a combination of patching the reset vector and soft-resetting them, then cleanup a few bits of hardware (we do re-probe PCIe for example), and reload & restart the bootloader. For Trusted Boot, this means we *add* measurements to the TPM, so you will get *different* PCR values as compared to a full IPL. This makes sense as if you want to be sure you are running something known then, well, do a full IPL as soft reset should never be trusted to clear any malicious code. This is very experimental and needs a lot of testing and also auditing code for other bits of HW that might need to be cleaned up. BenH TODO: I also need to check if we are properly PERST'ing PCI devices. This is partially based on old code I had to do that on P7. I only support it on P8 though as there are issues with the PSI interrupts on P7 that cannot be reliably solved. Even though this should be considered somewhat experimental, we've had a lot of success on a variety of machines. Dozens/hundreds of reboots across Tuleta, Garrison and Habanero. Currently, we've hidden it behind a NVRAM config option, which *is* liable to change in the future (to ensure that only those who know what they're doing enable it) You can enable the experimental support via nvram option: nvram -p ibm,skiboot --update-config experimental-fast-reset=feeling-lucky Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [stewart@linux.vnet.ibm.com: hide behind nvram option, include Mambo fixes from Mikey] Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/psi.c')
-rw-r--r--hw/psi.c103
1 files changed, 43 insertions, 60 deletions
diff --git a/hw/psi.c b/hw/psi.c
index 900886a..17e83a5 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -378,6 +378,36 @@ static uint64_t psi_p7_irq_attributes(struct irq_source *is __unused,
return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_FREQUENT;
}
+static const uint32_t psi_p8_irq_to_xivr[P8_IRQ_PSI_IRQ_COUNT] = {
+ [P8_IRQ_PSI_FSP] = PSIHB_XIVR_FSP,
+ [P8_IRQ_PSI_OCC] = PSIHB_XIVR_OCC,
+ [P8_IRQ_PSI_FSI] = PSIHB_XIVR_FSI,
+ [P8_IRQ_PSI_LPC] = PSIHB_XIVR_LPC,
+ [P8_IRQ_PSI_LOCAL_ERR] = PSIHB_XIVR_LOCAL_ERR,
+ [P8_IRQ_PSI_EXTERNAL]= PSIHB_XIVR_HOST_ERR,
+};
+
+static void psi_cleanup_irq(struct psi *psi)
+{
+ uint32_t irq;
+ uint64_t xivr, xivr_p;
+
+ for (irq = 0; irq < P8_IRQ_PSI_IRQ_COUNT; irq++) {
+ prlog(PR_DEBUG, "PSI[0x%03x]: Cleaning up IRQ %d\n",
+ psi->chip_id, irq);
+
+ xivr_p = psi_p8_irq_to_xivr[irq];
+ xivr = in_be64(psi->regs + xivr_p);
+ xivr |= (0xffull << 32);
+ out_be64(psi->regs + xivr_p, xivr);
+ time_wait_ms_nopoll(10);
+ xivr = in_be64(psi->regs + xivr_p);
+ if (xivr & PPC_BIT(39)) {
+ printf(" Need EOI !\n");
+ icp_send_eoi(psi->interrupt + irq);
+ }
+ }
+}
/* Called on a fast reset, make sure we aren't stuck with
* an accepted and never EOId PSI interrupt
@@ -385,27 +415,13 @@ static uint64_t psi_p7_irq_attributes(struct irq_source *is __unused,
void psi_irq_reset(void)
{
struct psi *psi;
- uint64_t xivr;
printf("PSI: Hot reset!\n");
- assert(proc_gen == proc_gen_p7);
+ assert(proc_gen == proc_gen_p8);
list_for_each(&psis, psi, list) {
- /* Mask the interrupt & clean the XIVR */
- xivr = 0x000000ff00000000UL;
- xivr |= P7_IRQ_BUID(psi->interrupt) << 16;
- out_be64(psi->regs + PSIHB_XIVR, xivr);
-
-#if 0 /* Seems to checkstop ... */
- /*
- * Maybe not anymore; we were just blindly sending
- * this on all iopaths, not just the active one;
- * We don't even know if those psis are even correct.
- */
- /* Send a dummy EOI to make sure the ICP is clear */
- icp_send_eoi(psi->interrupt);
-#endif
+ psi_cleanup_irq(psi);
}
}
@@ -416,34 +432,17 @@ static const struct irq_source_ops psi_p7_irq_ops = {
.attributes = psi_p7_irq_attributes,
};
+
static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t priority)
{
struct psi *psi = is->data;
uint64_t xivr_p, xivr;
+ uint32_t irq_idx = isn & 7;
- switch(isn & 7) {
- case P8_IRQ_PSI_FSP:
- xivr_p = PSIHB_XIVR_FSP;
- break;
- case P8_IRQ_PSI_OCC:
- xivr_p = PSIHB_XIVR_OCC;
- break;
- case P8_IRQ_PSI_FSI:
- xivr_p = PSIHB_XIVR_FSI;
- break;
- case P8_IRQ_PSI_LPC:
- xivr_p = PSIHB_XIVR_LPC;
- break;
- case P8_IRQ_PSI_LOCAL_ERR:
- xivr_p = PSIHB_XIVR_LOCAL_ERR;
- break;
- case P8_IRQ_PSI_EXTERNAL:
- xivr_p = PSIHB_XIVR_HOST_ERR;
- break;
- default:
- return OPAL_PARAMETER;
- }
+ if (irq_idx >= P8_IRQ_PSI_IRQ_COUNT)
+ return OPAL_PARAMETER;
+ xivr_p = psi_p8_irq_to_xivr[irq_idx];
/* Populate the XIVR */
xivr = (uint64_t)server << 40;
@@ -460,29 +459,12 @@ static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused,
{
struct psi *psi = is->data;
uint64_t xivr_p, xivr;
+ uint32_t irq_idx = isn & 7;
- switch(isn & 7) {
- case P8_IRQ_PSI_FSP:
- xivr_p = PSIHB_XIVR_FSP;
- break;
- case P8_IRQ_PSI_OCC:
- xivr_p = PSIHB_XIVR_OCC;
- break;
- case P8_IRQ_PSI_FSI:
- xivr_p = PSIHB_XIVR_FSI;
- break;
- case P8_IRQ_PSI_LPC:
- xivr_p = PSIHB_XIVR_LPC;
- break;
- case P8_IRQ_PSI_LOCAL_ERR:
- xivr_p = PSIHB_XIVR_LOCAL_ERR;
- break;
- case P8_IRQ_PSI_EXTERNAL:
- xivr_p = PSIHB_XIVR_HOST_ERR;
- break;
- default:
- return OPAL_PARAMETER;
- }
+ if (irq_idx >= P8_IRQ_PSI_IRQ_COUNT)
+ return OPAL_PARAMETER;
+
+ xivr_p = psi_p8_irq_to_xivr[irq_idx];
/* Read & decode the XIVR */
xivr = in_be64(psi->regs + xivr_p);
@@ -1053,3 +1035,4 @@ void psi_init(void)
psi_init_psihb(np);
}
+