On Thu, Feb 12, 2015 at 04:15:01PM +1100, David Gibson wrote: >On Wed, Feb 11, 2015 at 02:13:59PM +1100, Gavin Shan wrote: >> The emulation for EEH RTAS requests from guest isn't covered >> by QEMU yet and the patch implements them. >> >> The patch defines constants used by EEH RTAS calls and adds >> callbacks sPAPRPHBClass::{eeh_set_option, eeh_get_state, eeh_reset, >> eeh_configure}, which are going to be used as follows: >> >> * RTAS calls are received in spapr_pci.c, sanity check is done >> there. >> * RTAS handlers handle what they can. If there is something it >> cannot handle and the corresponding sPAPRPHBClass callback is >> defined, it is called. >> * Those callbacks are only implemented for VFIO now. They do ioctl() >> to the IOMMU container fd to complete the calls. Error codes from >> that ioctl() are transferred back to the guest. >> >> [aik: defined RTAS tokens for EEH RTAS calls] >> Signed-off-by: Gavin Shan <gws...@linux.vnet.ibm.com> >> --- >> hw/ppc/spapr_pci.c | 295 >> ++++++++++++++++++++++++++++++++++++++++++++ >> include/hw/pci-host/spapr.h | 4 + >> include/hw/ppc/spapr.h | 43 ++++++- >> 3 files changed, 340 insertions(+), 2 deletions(-) >> >> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c >> index 6deeb19..9c050e1 100644 >> --- a/hw/ppc/spapr_pci.c >> +++ b/hw/ppc/spapr_pci.c >> @@ -406,6 +406,282 @@ static void >> rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, >> rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */ >> } >> >> +static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + uint32_t addr, option; >> + uint64_t buid; >> + int ret; >> + >> + if ((nargs != 4) || (nret != 1)) { >> + goto param_error_exit; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + addr = rtas_ld(args, 0); >> + option = rtas_ld(args, 3); >> + >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto param_error_exit; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_set_option) { >> + goto param_error_exit; >> + } >> + >> + switch (option) { >> + case RTAS_EEH_ENABLE: >> + if (!find_dev(spapr, buid, addr)) { >> + goto param_error_exit; >> + } > >AFAICT the actual callback never uses the device address (and isn't >passed it), so why is that fact that it's valid relevant? >
RTAS call "ibm,set-eeh-option" with option RTAS_EEH_ENABLE is the first EEH RTAS call that guest calls into on basis of PCI devices. During that time, the guest doesn't call "ibm,get-config-addr-info2" and it doesn't know PE address yet. >> + break; >> + case RTAS_EEH_DISABLE: >> + case RTAS_EEH_THAW_IO: >> + case RTAS_EEH_THAW_DMA: >> + break; >> + default: >> + goto param_error_exit; > >So, you have stuff that's dependent on the option in both the generic >part and the callback which is not nice; I think you should move this >switchi into the callback. > Yes and I'll do. >> + } >> + >> + ret = spc->eeh_set_option(sphb, option); >> + rtas_st(rets, 0, ret); >> + return; >> + >> +param_error_exit: >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> +} >> + >> +static void rtas_ibm_get_config_addr_info2(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + PCIDevice *pdev; >> + uint32_t addr, option; >> + uint64_t buid; >> + >> + if ((nargs != 4) || (nret != 2)) { >> + goto param_error_exit; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto param_error_exit; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_set_option) { >> + goto param_error_exit; >> + } >> + >> + /* >> + * We always have PE address of form "00BB0001". "BB" >> + * represents the bus number of PE's primary bus. >> + */ >> + option = rtas_ld(args, 3); >> + switch (option) { >> + case RTAS_GET_PE_ADDR: >> + addr = rtas_ld(args, 0); >> + pdev = find_dev(spapr, buid, addr); >> + if (!pdev) { >> + goto param_error_exit; >> + } >> + >> + rtas_st(rets, 1, (pci_bus_num(pdev->bus) << 16) + 1); >> + break; >> + case RTAS_GET_PE_MODE: >> + rtas_st(rets, 1, RTAS_PE_MODE_SHARED); >> + break; >> + default: >> + goto param_error_exit; >> + } >> + >> + rtas_st(rets, 0, RTAS_OUT_SUCCESS); >> + return; >> + >> +param_error_exit: >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> +} >> + >> +static void rtas_ibm_read_slot_reset_state2(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t >> nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + uint64_t buid; >> + int state, ret; >> + >> + if ((nargs != 3) || (nret != 4 && nret != 5)) { >> + goto param_error_exit; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto param_error_exit; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_get_state) { >> + goto param_error_exit; >> + } >> + >> + ret = spc->eeh_get_state(sphb, &state); >> + rtas_st(rets, 0, ret); >> + if (ret != RTAS_OUT_SUCCESS) { >> + return; >> + } >> + >> + rtas_st(rets, 1, state); >> + rtas_st(rets, 2, RTAS_EEH_SUPPORT); >> + rtas_st(rets, 3, RTAS_EEH_PE_UNAVAIL_INFO); >> + if (nret >= 5) { >> + rtas_st(rets, 4, RTAS_EEH_PE_RECOVER_INFO); >> + } >> + return; >> + >> +param_error_exit: >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> +} >> + >> +static void rtas_ibm_set_slot_reset(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + uint32_t option; >> + uint64_t buid; >> + int ret; >> + >> + if ((nargs != 4) || (nret != 1)) { >> + goto param_error_exit; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + option = rtas_ld(args, 3); >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto param_error_exit; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_reset) { >> + goto param_error_exit; >> + } >> + >> + switch (option) { >> + case RTAS_SLOT_RESET_DEACTIVATE: >> + case RTAS_SLOT_RESET_HOT: >> + case RTAS_SLOT_RESET_FUNDAMENTAL: >> + break; >> + default: >> + goto param_error_exit; >> + } > >Again, you have a switch in both the generic part and the callback. I >think it should be moved into the callback. > Yes, I'll do. >> + ret = spc->eeh_reset(sphb, option); >> + rtas_st(rets, 0, ret); >> + return; >> + >> +param_error_exit: >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> +} >> + >> +static void rtas_ibm_configure_pe(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + uint64_t buid; >> + int ret; >> + >> + if ((nargs != 3) || (nret != 1)) { >> + goto param_error_exit; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto param_error_exit; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_configure) { >> + goto param_error_exit; >> + } >> + >> + ret = spc->eeh_configure(sphb); >> + rtas_st(rets, 0, ret); >> + return; >> + >> +param_error_exit: >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> +} >> + >> +/* To support it later */ >> +static void rtas_ibm_slot_error_detail(PowerPCCPU *cpu, >> + sPAPREnvironment *spapr, >> + uint32_t token, uint32_t nargs, >> + target_ulong args, uint32_t nret, >> + target_ulong rets) >> +{ >> + sPAPRPHBState *sphb; >> + sPAPRPHBClass *spc; >> + int option; >> + uint64_t buid; >> + >> + if ((nargs != 8) || (nret != 1)) { >> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); >> + return; >> + } >> + >> + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); >> + sphb = find_phb(spapr, buid); >> + if (!sphb) { >> + goto no_error_log; >> + } >> + >> + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); >> + if (!spc->eeh_set_option) { >> + goto no_error_log; >> + } >> + >> + option = rtas_ld(args, 7); >> + switch (option) { >> + case RTAS_SLOT_TEMP_ERR_LOG: >> + case RTAS_SLOT_PERM_ERR_LOG: >> + break; >> + default: >> + goto no_error_log; > >This has the same result as the valid cases, so what's the point of >the switch? > >It still seems deeply bogus to return NO_ERRORS_FOUND when the >parameters make no sense, despite what PAPR+ says. > The RTAS call is TBD. The error log complies with format defined by PAPR. I didn't expose it from host side yet. So it always returns "No error log" currently. Ok. In next revision, how about to have following return values? RTAS_OUT_PARAM_ERROR - On argument error RTAS_OUT_NO_ERRORS_FOUND - All other cases, even successful case because we don't have logs exposed from host side yet. Thanks, Gavin >> + } >> + >> + /* We don't get error log yet */ >> + rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND); >> + return; >> + >> +no_error_log: >> + rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND); >> +} >> + >> static int pci_spapr_swizzle(int slot, int pin) >> { >> return (slot + pin) % PCI_NUM_PINS; >> @@ -964,6 +1240,25 @@ void spapr_pci_rtas_init(void) >> spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi", >> rtas_ibm_change_msi); >> } >> + >> + spapr_rtas_register(RTAS_IBM_SET_EEH_OPTION, >> + "ibm,set-eeh-option", >> + rtas_ibm_set_eeh_option); >> + spapr_rtas_register(RTAS_IBM_GET_CONFIG_ADDR_INFO2, >> + "ibm,get-config-addr-info2", >> + rtas_ibm_get_config_addr_info2); >> + spapr_rtas_register(RTAS_IBM_READ_SLOT_RESET_STATE2, >> + "ibm,read-slot-reset-state2", >> + rtas_ibm_read_slot_reset_state2); >> + spapr_rtas_register(RTAS_IBM_SET_SLOT_RESET, >> + "ibm,set-slot-reset", >> + rtas_ibm_set_slot_reset); >> + spapr_rtas_register(RTAS_IBM_CONFIGURE_PE, >> + "ibm,configure-pe", >> + rtas_ibm_configure_pe); >> + spapr_rtas_register(RTAS_IBM_SLOT_ERROR_DETAIL, >> + "ibm,slot-error-detail", >> + rtas_ibm_slot_error_detail); >> } >> >> static void spapr_pci_register_types(void) >> diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h >> index 876ecf0..34d4bee 100644 >> --- a/include/hw/pci-host/spapr.h >> +++ b/include/hw/pci-host/spapr.h >> @@ -49,6 +49,10 @@ struct sPAPRPHBClass { >> PCIHostBridgeClass parent_class; >> >> void (*finish_realize)(sPAPRPHBState *sphb, Error **errp); >> + int (*eeh_set_option)(sPAPRPHBState *sphb, int option); >> + int (*eeh_get_state)(sPAPRPHBState *sphb, int *state); >> + int (*eeh_reset)(sPAPRPHBState *sphb, int option); >> + int (*eeh_configure)(sPAPRPHBState *sphb); >> }; >> >> typedef struct spapr_pci_msi { >> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h >> index 642cdc3..1cf5e89 100644 >> --- a/include/hw/ppc/spapr.h >> +++ b/include/hw/ppc/spapr.h >> @@ -338,6 +338,39 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, >> target_ulong opcode, >> int spapr_allocate_irq(int hint, bool lsi); >> int spapr_allocate_irq_block(int num, bool lsi, bool msi); >> >> +/* ibm,set-eeh-option */ >> +#define RTAS_EEH_DISABLE 0 >> +#define RTAS_EEH_ENABLE 1 >> +#define RTAS_EEH_THAW_IO 2 >> +#define RTAS_EEH_THAW_DMA 3 >> + >> +/* ibm,get-config-addr-info2 */ >> +#define RTAS_GET_PE_ADDR 0 >> +#define RTAS_GET_PE_MODE 1 >> +#define RTAS_PE_MODE_NONE 0 >> +#define RTAS_PE_MODE_NOT_SHARED 1 >> +#define RTAS_PE_MODE_SHARED 2 >> + >> +/* ibm,read-slot-reset-state2 */ >> +#define RTAS_EEH_PE_STATE_NORMAL 0 >> +#define RTAS_EEH_PE_STATE_RESET 1 >> +#define RTAS_EEH_PE_STATE_STOPPED_IO_DMA 2 >> +#define RTAS_EEH_PE_STATE_STOPPED_DMA 4 >> +#define RTAS_EEH_PE_STATE_UNAVAIL 5 >> +#define RTAS_EEH_NOT_SUPPORT 0 >> +#define RTAS_EEH_SUPPORT 1 >> +#define RTAS_EEH_PE_UNAVAIL_INFO 1000 >> +#define RTAS_EEH_PE_RECOVER_INFO 0 >> + >> +/* ibm,set-slot-reset */ >> +#define RTAS_SLOT_RESET_DEACTIVATE 0 >> +#define RTAS_SLOT_RESET_HOT 1 >> +#define RTAS_SLOT_RESET_FUNDAMENTAL 3 >> + >> +/* ibm,slot-error-detail */ >> +#define RTAS_SLOT_TEMP_ERR_LOG 1 >> +#define RTAS_SLOT_PERM_ERR_LOG 2 >> + >> /* RTAS return codes */ >> #define RTAS_OUT_SUCCESS 0 >> #define RTAS_OUT_NO_ERRORS_FOUND 1 >> @@ -382,8 +415,14 @@ int spapr_allocate_irq_block(int num, bool lsi, bool >> msi); >> #define RTAS_GET_SENSOR_STATE (RTAS_TOKEN_BASE + 0x1D) >> #define RTAS_IBM_CONFIGURE_CONNECTOR (RTAS_TOKEN_BASE + 0x1E) >> #define RTAS_IBM_OS_TERM (RTAS_TOKEN_BASE + 0x1F) >> - >> -#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x20) >> +#define RTAS_IBM_SET_EEH_OPTION (RTAS_TOKEN_BASE + 0x20) >> +#define RTAS_IBM_GET_CONFIG_ADDR_INFO2 (RTAS_TOKEN_BASE + 0x21) >> +#define RTAS_IBM_READ_SLOT_RESET_STATE2 (RTAS_TOKEN_BASE + 0x22) >> +#define RTAS_IBM_SET_SLOT_RESET (RTAS_TOKEN_BASE + 0x23) >> +#define RTAS_IBM_CONFIGURE_PE (RTAS_TOKEN_BASE + 0x24) >> +#define RTAS_IBM_SLOT_ERROR_DETAIL (RTAS_TOKEN_BASE + 0x25) >> + >> +#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x26) >> >> /* RTAS ibm,get-system-parameter token values */ >> #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 > >-- >David Gibson | I'll have my music baroque, and my code >david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ > | _way_ _around_! >http://www.ozlabs.org/~dgibson