diff options
-rw-r--r-- | core/hmi.c | 126 | ||||
-rw-r--r-- | hw/capp.c | 9 | ||||
-rw-r--r-- | hw/phb3.c | 35 | ||||
-rw-r--r-- | hw/phb4.c | 33 | ||||
-rw-r--r-- | include/capp.h | 19 | ||||
-rw-r--r-- | include/phb4-capp.h | 3 |
6 files changed, 142 insertions, 83 deletions
@@ -19,7 +19,6 @@ #include <processor.h> #include <chiptod.h> #include <xscom.h> -#include <phb3-capp.h> #include <pci.h> #include <cpu.h> #include <chip.h> @@ -245,58 +244,6 @@ static int queue_hmi_event(struct OpalHMIEvent *hmi_evt, int recover) num_params, (uint64_t *)hmi_evt); } -static int is_capp_recoverable(int chip_id, int capp_index) -{ - uint64_t reg; - uint32_t reg_offset = capp_index ? CAPP1_REG_OFFSET : 0x0; - - xscom_read(chip_id, CAPP_ERR_STATUS_CTRL + reg_offset, ®); - return (reg & PPC_BIT(0)) != 0; -} - -#define CAPP_PHB3_ATTACHED(chip, phb_index) \ - ((chip)->capp_phb3_attached_mask & (1 << (phb_index))) - -#define CHIP_IS_NAPLES(chip) ((chip)->type == PROC_CHIP_P8_NAPLES) - -static int handle_capp_recoverable(int chip_id, int capp_index) -{ - struct dt_node *np; - u64 phb_id; - u32 dt_chip_id; - struct phb *phb; - u32 phb_index; - struct proc_chip *chip = get_chip(chip_id); - - dt_for_each_compatible(dt_root, np, "ibm,power8-pciex") { - dt_chip_id = dt_prop_get_u32(np, "ibm,chip-id"); - phb_index = dt_prop_get_u32(np, "ibm,phb-index"); - phb_id = dt_prop_get_u64(np, "ibm,opal-phbid"); - - /* - * Murano/Venice have a single capp (capp0) per chip, - * that can be attached to phb0, phb1 or phb2. - * The capp is identified as being attached to the chip, - * regardless of the phb index. - * - * Naples has two capps per chip: capp0 attached to phb0, - * and capp1 attached to phb1. - * Once we know that the capp is attached to the chip, - * we must also check that capp/phb indices are equal. - */ - if ((chip_id == dt_chip_id) && - CAPP_PHB3_ATTACHED(chip, phb_index) && - (!CHIP_IS_NAPLES(chip) || phb_index == capp_index)) { - phb = pci_get_phb(phb_id); - phb_lock(phb); - phb->ops->set_capp_recovery(phb); - phb_unlock(phb); - return 1; - } - } - return 0; -} - static bool decode_core_fir(struct cpu_thread *cpu, struct OpalHMIEvent *hmi_evt) { @@ -385,47 +332,60 @@ static void find_capp_checkstop_reason(int flat_chip_id, struct OpalHMIEvent *hmi_evt, bool *event_generated) { - int capp_index; - struct proc_chip *chip = get_chip(flat_chip_id); - int capp_num = CHIP_IS_NAPLES(chip) ? 2 : 1; - uint32_t reg_offset; + struct capp_info info; + struct phb *phb; uint64_t capp_fir; uint64_t capp_fir_mask; uint64_t capp_fir_action0; uint64_t capp_fir_action1; + uint64_t reg; + int64_t rc; - for (capp_index = 0; capp_index < capp_num; capp_index++) { - reg_offset = capp_index ? CAPP1_REG_OFFSET : 0x0; - - if (xscom_read(flat_chip_id, - CAPP_FIR + reg_offset, &capp_fir) || - xscom_read(flat_chip_id, - CAPP_FIR_MASK + reg_offset, &capp_fir_mask) || - xscom_read(flat_chip_id, - CAPP_FIR_ACTION0 + reg_offset, &capp_fir_action0) || - xscom_read(flat_chip_id, - CAPP_FIR_ACTION1 + reg_offset, &capp_fir_action1)) { - prerror("CAPP: Couldn't read CAPP#%d FIR registers by XSCOM!\n", - capp_index); + /* Find the CAPP on the chip associated with the HMI. */ + for_each_phb(phb) { + /* get the CAPP info */ + rc = capp_get_info(flat_chip_id, phb, &info); + if (rc == OPAL_PARAMETER) + continue; + + if (xscom_read(flat_chip_id, info.capp_fir_reg, &capp_fir) || + xscom_read(flat_chip_id, info.capp_fir_mask_reg, + &capp_fir_mask) || + xscom_read(flat_chip_id, info.capp_fir_action0_reg, + &capp_fir_action0) || + xscom_read(flat_chip_id, info.capp_fir_action1_reg, + &capp_fir_action1)) { + prerror("CAPP: Couldn't read CAPP#%d (PHB:#%x) FIR registers by XSCOM!\n", + info.capp_index, info.phb_index); continue; } if (!(capp_fir & ~capp_fir_mask)) continue; - prlog(PR_DEBUG, "HMI: CAPP#%d: FIR 0x%016llx mask 0x%016llx\n", - capp_index, capp_fir, capp_fir_mask); - prlog(PR_DEBUG, "HMI: CAPP#%d: ACTION0 0x%016llx, ACTION1 0x%016llx\n", - capp_index, capp_fir_action0, capp_fir_action1); - - if (is_capp_recoverable(flat_chip_id, capp_index)) { - if (handle_capp_recoverable(flat_chip_id, capp_index)) { - hmi_evt->severity = OpalHMI_SEV_NO_ERROR; - hmi_evt->type = OpalHMI_ERROR_CAPP_RECOVERY; - queue_hmi_event(hmi_evt, 1); - *event_generated = true; - return; - } + prlog(PR_DEBUG, "HMI: CAPP#%d (PHB:#%x): FIR 0x%016llx mask 0x%016llx\n", + info.capp_index, info.phb_index, capp_fir, + capp_fir_mask); + prlog(PR_DEBUG, "HMI: CAPP#%d (PHB:#%x): ACTION0 0x%016llx, ACTION1 0x%016llx\n", + info.capp_index, info.phb_index, capp_fir_action0, + capp_fir_action1); + + /* + * If this bit is set (=1) a Recoverable Error has been + * detected + */ + xscom_read(flat_chip_id, info.capp_err_status_ctrl_reg, ®); + if ((reg & PPC_BIT(0)) != 0) { + phb_lock(phb); + phb->ops->set_capp_recovery(phb); + phb_unlock(phb); + + hmi_evt->severity = OpalHMI_SEV_NO_ERROR; + hmi_evt->type = OpalHMI_ERROR_CAPP_RECOVERY; + queue_hmi_event(hmi_evt, 1); + *event_generated = true; + + return; } } } @@ -35,6 +35,7 @@ static struct { #define CAPP_UCODE_MAX_SIZE 0x20000 struct lock capi_lock = LOCK_UNLOCKED; +struct capp_ops capi_ops = { NULL }; bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index) { @@ -229,3 +230,11 @@ int64_t capp_load_ucode(unsigned int chip_id, uint32_t opal_id, return OPAL_SUCCESS; } + +int64_t capp_get_info(int chip_id, struct phb *phb, struct capp_info *info) +{ + if (capi_ops.get_capp_info) + return capi_ops.get_capp_info(chip_id, phb, info); + + return OPAL_PARAMETER; +} @@ -3394,6 +3394,38 @@ static int64_t phb3_get_diag_data(struct phb *phb, return OPAL_SUCCESS; } +static int64_t phb3_get_capp_info(int chip_id, struct phb *phb, + struct capp_info *info) +{ + struct phb3 *p = phb_to_phb3(phb); + struct proc_chip *chip = get_chip(p->chip_id); + uint32_t offset; + + if (chip_id != p->chip_id) + return OPAL_PARAMETER; + + if (!((1 << p->index) & chip->capp_phb3_attached_mask)) + return OPAL_PARAMETER; + + offset = PHB3_CAPP_REG_OFFSET(p); + + if (PHB3_IS_NAPLES(p)) { + if (p->index == 0) + info->capp_index = 0; + else + info->capp_index = 1; + } else + info->capp_index = 0; + info->phb_index = p->index; + info->capp_fir_reg = CAPP_FIR + offset; + info->capp_fir_mask_reg = CAPP_FIR_MASK + offset; + info->capp_fir_action0_reg = CAPP_FIR_ACTION0 + offset; + info->capp_fir_action1_reg = CAPP_FIR_ACTION1 + offset; + info->capp_err_status_ctrl_reg = CAPP_ERR_STATUS_CTRL + offset; + + return OPAL_SUCCESS; +} + static void phb3_init_capp_regs(struct phb3 *p, bool dma_mode) { uint64_t reg; @@ -3606,6 +3638,9 @@ static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number, bool dma_mod return OPAL_HARDWARE; } + /* set callbacks to handle HMI events */ + capi_ops.get_capp_info = &phb3_get_capp_info; + return OPAL_SUCCESS; } @@ -2762,6 +2762,35 @@ static uint64_t tve_encode_50b_noxlate(uint64_t start_addr, uint64_t end_addr) return tve; } +static int64_t phb4_get_capp_info(int chip_id, struct phb *phb, + struct capp_info *info) +{ + struct phb4 *p = phb_to_phb4(phb); + struct proc_chip *chip = get_chip(p->chip_id); + uint32_t offset; + + if (chip_id != p->chip_id) + return OPAL_PARAMETER; + + if (!((1 << p->index) & chip->capp_phb4_attached_mask)) + return OPAL_PARAMETER; + + offset = PHB4_CAPP_REG_OFFSET(p); + + if (p->index == CAPP0_PHB_INDEX) + info->capp_index = 0; + if (p->index == CAPP1_PHB_INDEX) + info->capp_index = 1; + info->phb_index = p->index; + info->capp_fir_reg = CAPP_FIR + offset; + info->capp_fir_mask_reg = CAPP_FIR_MASK + offset; + info->capp_fir_action0_reg = CAPP_FIR_ACTION0 + offset; + info->capp_fir_action1_reg = CAPP_FIR_ACTION1 + offset; + info->capp_err_status_ctrl_reg = CAPP_ERR_STATUS_CTRL + offset; + + return OPAL_SUCCESS; +} + static void phb4_init_capp_regs(struct phb4 *p) { uint64_t reg; @@ -3031,6 +3060,10 @@ static int64_t enable_capi_mode(struct phb4 *p, uint64_t pe_number, PHBERR(p, "CAPP: Failed to sync timebase\n"); return OPAL_HARDWARE; } + + /* set callbacks to handle HMI events */ + capi_ops.get_capp_info = &phb4_get_capp_info; + return OPAL_SUCCESS; } diff --git a/include/capp.h b/include/capp.h index 587cc3a..597401d 100644 --- a/include/capp.h +++ b/include/capp.h @@ -65,8 +65,24 @@ enum capp_reg { apc_master_powerbus_ctrl = 0xB }; +struct capp_info { + unsigned int capp_index; + unsigned int phb_index; + uint64_t capp_fir_reg; + uint64_t capp_fir_mask_reg; + uint64_t capp_fir_action0_reg; + uint64_t capp_fir_action1_reg; + uint64_t capp_err_status_ctrl_reg; +}; + +struct capp_ops { + int64_t (*get_capp_info)(int, struct phb *, struct capp_info *); +}; + struct proc_chip; extern struct lock capi_lock; +extern struct capp_ops capi_ops; + extern bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index); extern int64_t capp_load_ucode(unsigned int chip_id, uint32_t opal_id, @@ -77,4 +93,7 @@ extern int64_t capp_load_ucode(unsigned int chip_id, uint32_t opal_id, uint64_t snp_array_addr, uint64_t snp_array_write); +extern int64_t capp_get_info(int chip_id, struct phb *phb, + struct capp_info *info); + #endif /* __CAPP_H */ diff --git a/include/phb4-capp.h b/include/phb4-capp.h index 89de034..a9b81f6 100644 --- a/include/phb4-capp.h +++ b/include/phb4-capp.h @@ -23,6 +23,9 @@ #define CAPP_APC_MASTER_ARRAY_WRITE_REG 0x2010842 /* Satellite 2 */ #define CAPP_FIR 0x2010800 +#define CAPP_FIR_MASK 0x2010803 +#define CAPP_FIR_ACTION0 0x2010806 +#define CAPP_FIR_ACTION1 0x2010807 #define CAPP_ERR_RPT_CLR 0x2010813 #define APC_MASTER_PB_CTRL 0x2010818 #define APC_MASTER_CAPI_CTRL 0x2010819 |