Skip to content

Commit

Permalink
powerpc/eeh: Aux PE data for error log
Browse files Browse the repository at this point in the history
The patch allows PE (struct eeh_pe) instance to have auxillary data,
whose size is configurable on basis of platform. For PowerNV, the
auxillary data will be used to cache PHB diag-data for that PE
(frozen PE or fenced PHB). In turn, we can retrieve the diag-data
at any later points.

It's useful for the case of VFIO PCI devices where the error log
should be cached, and then be retrieved by the guest at later point.
Also, it can avoid PHB diag-data overwritting if another frozen PE
reported and the previous diag-data isn't fetched by guest.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Aug 5, 2014
1 parent f18440f commit bb593c0
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 15 deletions.
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/eeh.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct eeh_pe {
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 */
Expand Down Expand Up @@ -248,6 +249,7 @@ static inline void eeh_serialize_unlock(unsigned long flags)
#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);
Expand Down
26 changes: 25 additions & 1 deletion arch/powerpc/kernel/eeh_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,23 @@
#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
Expand All @@ -44,9 +59,16 @@ static LIST_HEAD(eeh_phb_pe);
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 */
Expand All @@ -56,6 +78,8 @@ static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
INIT_LIST_HEAD(&pe->child);
INIT_LIST_HEAD(&pe->edevs);

pe->data = (void *)pe + ALIGN(sizeof(struct eeh_pe),
cache_line_size());
return pe;
}

Expand Down
42 changes: 29 additions & 13 deletions arch/powerpc/platforms/powernv/eeh-ioda.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,16 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
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);
}

/**
Expand Down Expand Up @@ -323,7 +319,7 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
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;
Expand Down Expand Up @@ -373,7 +369,7 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
(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;
Expand Down Expand Up @@ -588,6 +584,24 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
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
Expand Down Expand Up @@ -805,7 +819,8 @@ static int ioda_eeh_next_error(struct eeh_pe **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;
}

Expand Down Expand Up @@ -853,7 +868,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
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);
}

/*
Expand Down Expand Up @@ -899,6 +914,7 @@ struct pnv_eeh_ops ioda_eeh_ops = {
.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
};
3 changes: 2 additions & 1 deletion arch/powerpc/platforms/powernv/eeh-powernv.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
* 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;
Expand Down Expand Up @@ -430,6 +430,7 @@ static int __init eeh_powernv_init(void)
{
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");
Expand Down

0 comments on commit bb593c0

Please sign in to comment.