aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/pci-opal.c19
-rw-r--r--hw/p7ioc-phb.c33
-rw-r--r--hw/phb3.c35
-rw-r--r--include/opal.h9
-rw-r--r--include/pci.h2
5 files changed, 96 insertions, 2 deletions
diff --git a/core/pci-opal.c b/core/pci-opal.c
index 59f4d5c..2048d7f 100644
--- a/core/pci-opal.c
+++ b/core/pci-opal.c
@@ -93,6 +93,25 @@ static int64_t opal_pci_eeh_freeze_clear(uint64_t phb_id, uint64_t pe_number,
}
opal_call(OPAL_PCI_EEH_FREEZE_CLEAR, opal_pci_eeh_freeze_clear, 3);
+static int64_t opal_pci_eeh_freeze_set(uint64_t phb_id, uint64_t pe_number,
+ uint64_t eeh_action_token)
+{
+ struct phb *phb = pci_get_phb(phb_id);
+ int64_t rc;
+
+ if (!phb)
+ return OPAL_PARAMETER;
+ if (!phb->ops->eeh_freeze_set)
+ return OPAL_UNSUPPORTED;
+ phb->ops->lock(phb);
+ rc = phb->ops->eeh_freeze_set(phb, pe_number, eeh_action_token);
+ phb->ops->unlock(phb);
+ pci_put_phb(phb);
+
+ return rc;
+}
+opal_call(OPAL_PCI_EEH_FREEZE_SET, opal_pci_eeh_freeze_set, 3);
+
static int64_t opal_pci_err_injct(uint64_t phb_id, uint32_t pe_no,
uint32_t type, uint32_t function,
uint64_t addr, uint64_t mask)
diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c
index 64dbfed..834a794 100644
--- a/hw/p7ioc-phb.c
+++ b/hw/p7ioc-phb.c
@@ -1301,6 +1301,38 @@ static int64_t p7ioc_eeh_freeze_clear(struct phb *phb, uint64_t pe_number,
return OPAL_SUCCESS;
}
+static int64_t p7ioc_eeh_freeze_set(struct phb *phb, uint64_t pe_number,
+ uint64_t eeh_action_token)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
+ uint64_t data;
+
+ if (pe_number > 127)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_MMIO &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_DMA &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_ALL)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_MMIO) {
+ p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA_PESTA_MMIO_FROZEN;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_DMA) {
+ p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA_PESTB_DMA_STOPPED;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ return OPAL_SUCCESS;
+}
+
+
static int64_t p7ioc_err_injct(struct phb *phb, uint32_t pe_no,
uint32_t type, uint32_t function,
uint64_t address, uint64_t mask)
@@ -2526,6 +2558,7 @@ static const struct phb_ops p7ioc_phb_ops = {
.pci_reinit = p7ioc_pci_reinit,
.eeh_freeze_status = p7ioc_eeh_freeze_status,
.eeh_freeze_clear = p7ioc_eeh_freeze_clear,
+ .eeh_freeze_set = p7ioc_eeh_freeze_set,
.err_injct = p7ioc_err_injct,
.get_diag_data = NULL,
.get_diag_data2 = p7ioc_get_diag_data,
diff --git a/hw/phb3.c b/hw/phb3.c
index 6989083..90e5be5 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -2431,6 +2431,40 @@ static int64_t phb3_eeh_freeze_clear(struct phb *phb, uint64_t pe_number,
return OPAL_SUCCESS;
}
+static int64_t phb3_eeh_freeze_set(struct phb *phb, uint64_t pe_number,
+ uint64_t eeh_action_token)
+{
+ struct phb3 *p = phb_to_phb3(phb);
+ uint64_t data;
+
+ if (p->state == PHB3_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ if (pe_number >= PHB3_MAX_PE_NUM)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_MMIO &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_DMA &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_ALL)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_MMIO) {
+ phb3_ioda_sel(p, IODA2_TBL_PESTA, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA2_PESTA_MMIO_FROZEN;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_DMA) {
+ phb3_ioda_sel(p, IODA2_TBL_PESTB, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA2_PESTB_DMA_STOPPED;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ return OPAL_SUCCESS;
+}
+
static int64_t phb3_eeh_next_error(struct phb *phb,
uint64_t *first_frozen_pe,
uint16_t *pci_error_type,
@@ -3009,6 +3043,7 @@ static const struct phb_ops phb3_ops = {
.poll = phb3_poll,
.eeh_freeze_status = phb3_eeh_freeze_status,
.eeh_freeze_clear = phb3_eeh_freeze_clear,
+ .eeh_freeze_set = phb3_eeh_freeze_set,
.next_error = phb3_eeh_next_error,
.err_injct = phb3_err_injct,
.get_diag_data = NULL,
diff --git a/include/opal.h b/include/opal.h
index 592f139..43b7c80 100644
--- a/include/opal.h
+++ b/include/opal.h
@@ -132,7 +132,8 @@
#define OPAL_DUMP_INFO2 94
#define OPAL_WRITE_OPPANEL_ASYNC 95
#define OPAL_PCI_ERR_INJCT 96
-#define OPAL_LAST 96
+#define OPAL_PCI_EEH_FREEZE_SET 97
+#define OPAL_LAST 97
#ifndef __ASSEMBLY__
@@ -157,7 +158,11 @@ enum OpalFreezeState {
enum OpalEehFreezeActionToken {
OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1,
OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2,
- OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3
+ OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3,
+
+ OPAL_EEH_ACTION_SET_FREEZE_MMIO = 1,
+ OPAL_EEH_ACTION_SET_FREEZE_DMA = 2,
+ OPAL_EEH_ACTION_SET_FREEZE_ALL = 3
};
enum OpalPciStatusToken {
diff --git a/include/pci.h b/include/pci.h
index 9acc068..aff70b3 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -252,6 +252,8 @@ struct phb_ops {
uint64_t *phb_status);
int64_t (*eeh_freeze_clear)(struct phb *phb, uint64_t pe_number,
uint64_t eeh_action_token);
+ int64_t (*eeh_freeze_set)(struct phb *phb, uint64_t pe_number,
+ uint64_t eeh_action_token);
int64_t (*err_injct)(struct phb *phb, uint32_t pe_no, uint32_t type,
uint32_t function, uint64_t addr, uint64_t mask);
int64_t (*get_diag_data)(struct phb *phb, void *diag_buffer,