aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.vnet.ibm.com>2017-06-13 14:21:22 +0200
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-06-19 17:20:55 +1000
commit71de2375d28d8dba3b50f4857540bc68da3e5856 (patch)
tree0a57c66735a0bc93b8f2d60f36512c4bfb47f3a4
parente50764d4f2b11fc9e9fe0b2fd0a4617b32593bfa (diff)
downloadskiboot-71de2375d28d8dba3b50f4857540bc68da3e5856.zip
skiboot-71de2375d28d8dba3b50f4857540bc68da3e5856.tar.gz
skiboot-71de2375d28d8dba3b50f4857540bc68da3e5856.tar.bz2
capi: Handle HMI events
Find the CAPP on the chip associated with the HMI event for PHB4. The recovery mode (re-initialization of the capp, resume of functional operations) is only available with P9 DD2. A new patch will be provided to support this feature. Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> Reviewed-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/hmi.c126
-rw-r--r--hw/capp.c9
-rw-r--r--hw/phb3.c35
-rw-r--r--hw/phb4.c33
-rw-r--r--include/capp.h19
-rw-r--r--include/phb4-capp.h3
6 files changed, 142 insertions, 83 deletions
diff --git a/core/hmi.c b/core/hmi.c
index c5c554a..84f2c2d 100644
--- a/core/hmi.c
+++ b/core/hmi.c
@@ -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, &reg);
- 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, &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;
}
}
}
diff --git a/hw/capp.c b/hw/capp.c
index ae79b0f..28a0a4e 100644
--- a/hw/capp.c
+++ b/hw/capp.c
@@ -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;
+}
diff --git a/hw/phb3.c b/hw/phb3.c
index 7922098..bc04c36 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -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;
}
diff --git a/hw/phb4.c b/hw/phb4.c
index 27b970a..e56a3f4 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -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