aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.vnet.ibm.com>2021-10-14 17:56:57 +0200
committerVasant Hegde <hegdevasant@linux.vnet.ibm.com>2021-10-19 12:26:01 +0530
commit6ad2feaeb1a44365367ed94989b18f2ed7012d98 (patch)
treea8e6f2a60723f6f7b918a9439b5ffd332e946d14
parenta7eae3eef52a3081f0f2188a10cd4dc1d7b8f1c1 (diff)
downloadskiboot-6ad2feaeb1a44365367ed94989b18f2ed7012d98.zip
skiboot-6ad2feaeb1a44365367ed94989b18f2ed7012d98.tar.gz
skiboot-6ad2feaeb1a44365367ed94989b18f2ed7012d98.tar.bz2
pau: enable interrupt on error
The default action for the errors (unexpected errors on the opencapi link) reported in the PAU FIR2 registe is mostly set to system checkstop. This patch changes the default action of those errors so that the PAU will raise an interrupt instead. Interrupt information are logged so that the error can be debugged and linux can catch the event. Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> Reviewed-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
-rw-r--r--hw/pau.c157
-rw-r--r--include/pau-regs.h12
-rw-r--r--include/pau.h2
3 files changed, 171 insertions, 0 deletions
diff --git a/hw/pau.c b/hw/pau.c
index 36c5f224..eb31715 100644
--- a/hw/pau.c
+++ b/hw/pau.c
@@ -5,6 +5,7 @@
#include <interrupts.h>
#include <pci-slot.h>
#include <phys-map.h>
+#include <xive.h>
#include <pau.h>
#include <pau-regs.h>
#include <xscom-p10-regs.h>
@@ -237,6 +238,15 @@ static int pau_opencapi_set_fence_control(struct pau_dev *dev,
return OPAL_HARDWARE;
}
+#define PAU_DEV_STATUS_BROKEN 0x1
+
+static void pau_opencapi_set_broken(struct pau_dev *dev)
+{
+ PAUDEVDBG(dev, "Update status to broken\n");
+
+ dev->status = PAU_DEV_STATUS_BROKEN;
+}
+
static void pau_opencapi_mask_firs(struct pau *pau)
{
uint64_t reg, val;
@@ -310,6 +320,113 @@ static void pau_opencapi_assign_bars(struct pau *pau)
}
}
+static uint64_t pau_opencapi_ipi_attributes(struct irq_source *is,
+ uint32_t isn)
+{
+ struct pau *pau = is->data;
+ uint32_t level = isn - pau->irq_base;
+
+ if (level >= 37 && level <= 40) {
+ /* level 37-40: OTL/XSL interrupt */
+ return IRQ_ATTR_TARGET_OPAL |
+ IRQ_ATTR_TARGET_RARE |
+ IRQ_ATTR_TYPE_MSI;
+ }
+
+ return IRQ_ATTR_TARGET_LINUX;
+}
+
+static void pau_opencapi_ipi_interrupt(struct irq_source *is,
+ uint32_t isn)
+{
+ struct pau *pau = is->data;
+ uint32_t level = isn - pau->irq_base;
+ struct pau_dev *dev;
+
+ switch (level) {
+ case 37 ... 40:
+ pau_for_each_opencapi_dev(dev, pau)
+ pau_opencapi_set_broken(dev);
+
+ opal_update_pending_evt(OPAL_EVENT_PCI_ERROR,
+ OPAL_EVENT_PCI_ERROR);
+ break;
+ default:
+ PAUERR(pau, "Received unknown interrupt %d\n", level);
+ return;
+ }
+}
+
+#define PAU_IRQ_LEVELS 60
+
+static char *pau_opencapi_ipi_name(struct irq_source *is, uint32_t isn)
+{
+ struct pau *pau = is->data;
+ uint32_t level = isn - pau->irq_base;
+
+ switch (level) {
+ case 0 ... 19:
+ return strdup("Reserved");
+ case 20:
+ return strdup("An error event related to PAU CQ functions");
+ case 21:
+ return strdup("An error event related to PAU MISC functions");
+ case 22 ... 34:
+ return strdup("Reserved");
+ case 35:
+ return strdup("Translation failure for OCAPI link 0");
+ case 36:
+ return strdup("Translation failure for OCAPI link 1");
+ case 37:
+ return strdup("An error event related to OTL for link 0");
+ case 38:
+ return strdup("An error event related to OTL for link 1");
+ case 39:
+ return strdup("An error event related to XSL for link 0");
+ case 40:
+ return strdup("An error event related to XSL for link 1");
+ case 41 ... 59:
+ return strdup("Reserved");
+ }
+
+ return strdup("Unknown");
+}
+
+static const struct irq_source_ops pau_opencapi_ipi_ops = {
+ .attributes = pau_opencapi_ipi_attributes,
+ .interrupt = pau_opencapi_ipi_interrupt,
+ .name = pau_opencapi_ipi_name,
+};
+
+static void pau_opencapi_setup_irqs(struct pau *pau)
+{
+ uint64_t reg, val;
+ uint32_t base;
+
+ base = xive2_alloc_ipi_irqs(pau->chip_id, PAU_IRQ_LEVELS, 64);
+ if (base == XIVE_IRQ_ERROR) {
+ PAUERR(pau, "Failed to allocate interrupt sources\n");
+ return;
+ }
+
+ xive2_register_ipi_source(base, PAU_IRQ_LEVELS, pau, &pau_opencapi_ipi_ops);
+
+ /* Set IPI configuration */
+ reg = PAU_MISC_CONFIG;
+ val = pau_read(pau, reg);
+ val = SETFIELD(PAU_MISC_CONFIG_IPI_PS, val, PAU_MISC_CONFIG_IPI_PS_64K);
+ val = SETFIELD(PAU_MISC_CONFIG_IPI_OS, val, PAU_MISC_CONFIG_IPI_OS_AIX);
+ pau_write(pau, reg, val);
+
+ /* Set IRQ base */
+ reg = PAU_MISC_INT_BAR;
+ val = SETFIELD(PAU_MISC_INT_BAR_ADDR, 0ull,
+ (uint64_t)xive2_get_trigger_port(base) >> 12);
+ pau_write(pau, reg, val);
+
+ pau->irq_base = base;
+}
+
static void pau_opencapi_enable_bars(struct pau_dev *dev, bool enable)
{
struct pau *pau = dev->pau;
@@ -769,6 +886,41 @@ static void pau_opencapi_address_translation_config(struct pau_dev *dev)
/* XSL_GP - use defaults */
}
+static void pau_opencapi_enable_interrupt_on_error(struct pau_dev *dev)
+{
+ struct pau *pau = dev->pau;
+ uint64_t reg, val;
+
+ PAUDEVDBG(dev, "Enable Interrupt-on-error\n");
+
+ /* translation fault */
+ reg = PAU_MISC_INT_2_CONFIG;
+ val = pau_read(pau, reg);
+ val |= PAU_MISC_INT_2_CONFIG_XFAULT_2_5(dev->index);
+ pau_write(pau, reg, val);
+
+ /* freeze disable */
+ reg = PAU_MISC_FREEZE_1_CONFIG;
+ val = pau_read(pau, reg);
+ val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+ val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+ pau_write(pau, reg, val);
+
+ /* fence disable */
+ reg = PAU_MISC_FENCE_1_CONFIG;
+ val = pau_read(pau, reg);
+ val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+ val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+ pau_write(pau, reg, val);
+
+ /* irq disable */
+ reg = PAU_MISC_INT_1_CONFIG;
+ val = pau_read(pau, reg);
+ val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+ val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+ pau_write(pau, reg, val);
+}
+
static void pau_opencapi_enable_ref_clock(struct pau_dev *dev)
{
uint64_t reg, val;
@@ -817,6 +969,7 @@ static void pau_opencapi_init_hw(struct pau *pau)
pau_opencapi_mask_firs(pau);
pau_opencapi_assign_bars(pau);
+ pau_opencapi_setup_irqs(pau);
/* Create phb */
pau_for_each_opencapi_dev(dev, pau) {
@@ -893,6 +1046,10 @@ static void pau_opencapi_init_hw(struct pau *pau)
* AFU's memory
*/
+ /* Procedure 17.1.3.11 - Interrupt Configuration */
+ /* done in pau_opencapi_setup_irqs() */
+ pau_opencapi_enable_interrupt_on_error(dev);
+
/* Reset disabled. Place OTLs into Run State */
pau_opencapi_set_fence_control(dev, 0b00);
diff --git a/include/pau-regs.h b/include/pau-regs.h
index e4ff7cc..d98f435 100644
--- a/include/pau-regs.h
+++ b/include/pau-regs.h
@@ -139,6 +139,18 @@
#define PAU_MISC_HOLD (PAU_BLOCK_PAU_MISC + 0x020)
#define PAU_MISC_HOLD_NDL_STALL PPC_BITMASK(0, 3)
#define PAU_MISC_CONFIG (PAU_BLOCK_PAU_MISC + 0x030)
+#define PAU_MISC_CONFIG_IPI_PS PPC_BIT(11)
+#define PAU_MISC_CONFIG_IPI_PS_64K 1
+#define PAU_MISC_CONFIG_IPI_OS PPC_BIT(12)
+#define PAU_MISC_CONFIG_IPI_OS_AIX 0
#define PAU_MISC_CONFIG_OC_MODE PPC_BIT(16)
+#define PAU_MISC_FREEZE_1_CONFIG (PAU_BLOCK_PAU_MISC + 0x048)
+#define PAU_MISC_FENCE_1_CONFIG (PAU_BLOCK_PAU_MISC + 0x058)
+#define PAU_MISC_INT_1_CONFIG (PAU_BLOCK_PAU_MISC + 0x068)
+#define PAU_MISC_INT_BAR (PAU_BLOCK_PAU_MISC + 0x098)
+#define PAU_MISC_INT_BAR_ADDR PPC_BITMASK(0, 39)
+#define PAU_MISC_INT_2_CONFIG (PAU_BLOCK_PAU_MISC + 0x408)
+#define PAU_MISC_INT_2_CONFIG_XFAULT_2_5(n) PPC_BIT(0 + (n))
+#define PAU_MISC_INT_2_CONFIG_XFAULT_0_1(n) PPC_BIT(54 + (n))
#endif /* __PAU_REGS_H */
diff --git a/include/pau.h b/include/pau.h
index 0246a63..b6fabe7 100644
--- a/include/pau.h
+++ b/include/pau.h
@@ -33,6 +33,7 @@ struct pau_dev {
uint32_t index;
struct dt_node *dn;
struct phb phb;
+ uint32_t status;
struct pau_bar ntl_bar;
struct pau_bar genid_bar;
@@ -59,6 +60,7 @@ struct pau {
uint64_t regs[2];
bool mmio_access;
+ uint32_t irq_base;
struct lock lock;
uint32_t links;