int false_positives; /* Times of reported #ff's */
atomic_t pass_dev_cnt; /* Count of passed through devs */
struct eeh_pe *parent; /* Parent PE */
+ void *data; /* PE auxillary data */
struct list_head child_list; /* Link PE to the child list */
struct list_head edevs; /* Link list of EEH devices */
struct list_head child; /* Child PEs */
#define EEH_MAX_ALLOWED_FREEZES 5
typedef void *(*eeh_traverse_func)(void *data, void *flag);
+void eeh_set_pe_aux_size(int size);
int eeh_phb_pe_create(struct pci_controller *phb);
struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
+static int eeh_pe_aux_size = 0;
static LIST_HEAD(eeh_phb_pe);
+/**
+ * eeh_set_pe_aux_size - Set PE auxillary data size
+ * @size: PE auxillary data size
+ *
+ * Set PE auxillary data size
+ */
+void eeh_set_pe_aux_size(int size)
+{
+ if (size < 0)
+ return;
+
+ eeh_pe_aux_size = size;
+}
+
/**
* eeh_pe_alloc - Allocate PE
* @phb: PCI controller
static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
{
struct eeh_pe *pe;
+ size_t alloc_size;
+
+ alloc_size = sizeof(struct eeh_pe);
+ if (eeh_pe_aux_size) {
+ alloc_size = ALIGN(alloc_size, cache_line_size());
+ alloc_size += eeh_pe_aux_size;
+ }
/* Allocate PHB PE */
- pe = kzalloc(sizeof(struct eeh_pe), GFP_KERNEL);
+ pe = kzalloc(alloc_size, GFP_KERNEL);
if (!pe) return NULL;
/* Initialize PHB PE */
INIT_LIST_HEAD(&pe->child);
INIT_LIST_HEAD(&pe->edevs);
+ pe->data = (void *)pe + ALIGN(sizeof(struct eeh_pe),
+ cache_line_size());
return pe;
}
return ret;
}
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
+static void ioda_eeh_phb_diag(struct eeh_pe *pe)
{
- struct pnv_phb *phb = hose->private_data;
+ struct pnv_phb *phb = pe->phb->private_data;
long rc;
- rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data,
PNV_PCI_DIAG_BUF_SIZE);
- if (rc != OPAL_SUCCESS) {
+ if (rc != OPAL_SUCCESS)
pr_warn("%s: Failed to get diag-data for PHB#%x (%ld)\n",
- __func__, hose->global_number, rc);
- return;
- }
-
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+ __func__, pe->phb->global_number, rc);
}
/**
result |= EEH_STATE_DMA_ENABLED;
} else if (!(pe->state & EEH_PE_ISOLATED)) {
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(pe);
}
return result;
(EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
!(pe->state & EEH_PE_ISOLATED)) {
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(pe);
}
return result;
return ret;
}
+/**
+ * ioda_eeh_get_log - Retrieve error log
+ * @pe: frozen PE
+ * @severity: permanent or temporary error
+ * @drv_log: device driver log
+ * @len: length of device driver log
+ *
+ * Retrieve error log, which contains log from device driver
+ * and firmware.
+ */
+int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
+ char *drv_log, unsigned long len)
+{
+ pnv_pci_dump_phb_diag_data(pe->phb, pe->data);
+
+ return 0;
+}
+
/**
* ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
* @pe: EEH PE
"detected, location: %s\n",
hose->global_number,
eeh_pe_loc_get(phb_pe));
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(phb_pe);
+ pnv_pci_dump_phb_diag_data(hose, phb_pe->data);
ret = EEH_NEXT_ERR_NONE;
}
ret == EEH_NEXT_ERR_FENCED_PHB) &&
!((*pe)->state & EEH_PE_ISOLATED)) {
eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(*pe);
}
/*
.set_option = ioda_eeh_set_option,
.get_state = ioda_eeh_get_state,
.reset = ioda_eeh_reset,
+ .get_log = ioda_eeh_get_log,
.configure_bridge = ioda_eeh_configure_bridge,
.next_error = ioda_eeh_next_error
};
* Retrieve the temporary or permanent error from the PE.
*/
static int powernv_eeh_get_log(struct eeh_pe *pe, int severity,
- char *drv_log, unsigned long len)
+ char *drv_log, unsigned long len)
{
struct pci_controller *hose = pe->phb;
struct pnv_phb *phb = hose->private_data;
{
int ret = -EINVAL;
+ eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE);
ret = eeh_ops_register(&powernv_eeh_ops);
if (!ret)
pr_info("EEH: PowerNV platform initialized\n");