Skip to content

Commit

Permalink
phb4: Verbose EEH options
Browse files Browse the repository at this point in the history
Enabled via nvram pci-eeh-verbose=true. ie.
  nvram -p ibm,skiboot --update-config pci-eeh-verbose=true

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
ozbenh authored and stewartsmith committed Jul 13, 2017
1 parent 877b917 commit b54845a
Showing 1 changed file with 118 additions and 24 deletions.
142 changes: 118 additions & 24 deletions hw/phb4.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ static bool phb4_init_rc_cfg(struct phb4 *p);
#define PHBLOGCFG(p, fmt, a...) do {} while (0)
#endif

static bool verbose_eeh;

enum capi_dma_tvt {
CAPI_DMA_TVT0,
CAPI_DMA_TVT1,
Expand All @@ -99,12 +101,12 @@ static inline uint64_t phb4_read_reg_asb(struct phb4 *p, uint32_t offset)
*
* This path isn't usable for outbound configuration space
*/
if ((offset & 0xfffffffc) == PHB_CONFIG_DATA) {
PHBERR(p, "XSCOM access to CONFIG_DATA unsupported\n");
if (((offset & 0xfffffffc) == PHB_CONFIG_DATA) && (offset & 3)) {
PHBERR(p, "XSCOM unaligned access to CONFIG_DATA unsupported\n");
return -1ull;
}
addr = XETU_HV_IND_ADDR_VALID | offset;
if (offset >= 0x1000 && offset < 0x1800)
if ((offset >= 0x1000 && offset < 0x1800) || (offset == PHB_CONFIG_DATA))
addr |= XETU_HV_IND_ADDR_4B;
rc = xscom_write(p->chip_id, p->etu_xscom + XETU_HV_IND_ADDRESS, addr);
if (rc != 0) {
Expand Down Expand Up @@ -133,12 +135,12 @@ static inline void phb4_write_reg_asb(struct phb4 *p,
*
* This path isn't usable for outbound configuration space
*/
if ((offset & 0xfffffffc) == PHB_CONFIG_DATA) {
if (((offset & 0xfffffffc) == PHB_CONFIG_DATA) && (offset & 3)) {
PHBERR(p, "XSCOM access to CONFIG_DATA unsupported\n");
return;
}
addr = XETU_HV_IND_ADDR_VALID | offset;
if (offset >= 0x1000 && offset < 0x1800)
if ((offset >= 0x1000 && offset < 0x1800) || (offset == PHB_CONFIG_DATA))
addr |= XETU_HV_IND_ADDR_4B;
rc = xscom_write(p->chip_id, p->etu_xscom + XETU_HV_IND_ADDRESS, addr);
if (rc != 0) {
Expand All @@ -163,6 +165,84 @@ static inline void phb4_ioda_sel(struct phb4 *p, uint32_t table,
SETFIELD(PHB_IODA_AD_TADR, 0ul, addr));
}

static void phb4_read_phb_status(struct phb4 *p,
struct OpalIoPhb4ErrorData *stat);
static void phb4_eeh_dump_regs(struct phb4 *p)
{
struct OpalIoPhb4ErrorData *s;
unsigned int i;

s = zalloc(sizeof(struct OpalIoPhb4ErrorData));
phb4_read_phb_status(p, s);

PHBERR(p, "brdgCtl = %08x\n", s->brdgCtl);

/* PHB4 cfg regs */
PHBERR(p, " deviceStatus = %08x\n", s->deviceStatus);
PHBERR(p, " slotStatus = %08x\n", s->slotStatus);
PHBERR(p, " linkStatus = %08x\n", s->linkStatus);
PHBERR(p, " devCmdStatus = %08x\n", s->devCmdStatus);
PHBERR(p, " devSecStatus = %08x\n", s->devSecStatus);
PHBERR(p, " rootErrorStatus = %08x\n", s->rootErrorStatus);
PHBERR(p, " uncorrErrorStatus = %08x\n", s->uncorrErrorStatus);
PHBERR(p, " corrErrorStatus = %08x\n", s->corrErrorStatus);
PHBERR(p, " uncorrErrorStatus = %08x\n", s->uncorrErrorStatus);
PHBERR(p, " tlpHdr1 = %08x\n", s->tlpHdr1);
PHBERR(p, " tlpHdr2 = %08x\n", s->tlpHdr2);
PHBERR(p, " tlpHdr3 = %08x\n", s->tlpHdr3);
PHBERR(p, " tlpHdr4 = %08x\n", s->tlpHdr4);
PHBERR(p, " sourceId = %08x\n", s->sourceId);
PHBERR(p, " tlpHdr1 = %08x\n", s->tlpHdr1);
PHBERR(p, " nFir = %016llx\n", s->nFir);
PHBERR(p, " nFirMask = %016llx\n", s->nFirMask);
PHBERR(p, " nFirWOF = %016llx\n", s->nFirWOF);
PHBERR(p, " phbPlssr = %016llx\n", s->phbPlssr);
PHBERR(p, " phbCsr = %016llx\n", s->phbCsr);
PHBERR(p, " lemFir = %016llx\n", s->lemFir);
PHBERR(p, " lemErrorMask = %016llx\n", s->lemErrorMask);
PHBERR(p, " lemWOF = %016llx\n", s->lemWOF);
PHBERR(p, " phbErrorStatus = %016llx\n", s->phbErrorStatus);
PHBERR(p, " phbFirstErrorStatus = %016llx\n", s->phbFirstErrorStatus);
PHBERR(p, " phbErrorLog0 = %016llx\n", s->phbErrorLog0);
PHBERR(p, " phbErrorLog1 = %016llx\n", s->phbErrorLog1);
PHBERR(p, " phbTxeErrorStatus = %016llx\n", s->phbTxeErrorStatus);
PHBERR(p, " phbTxeFirstErrorStatus = %016llx\n", s->phbTxeFirstErrorStatus);
PHBERR(p, " phbTxeErrorLog0 = %016llx\n", s->phbTxeErrorLog0);
PHBERR(p, " phbTxeErrorLog1 = %016llx\n", s->phbTxeErrorLog1);
PHBERR(p, " phbRxeArbErrorStatus = %016llx\n", s->phbRxeArbErrorStatus);
PHBERR(p, "phbRxeArbFrstErrorStatus = %016llx\n", s->phbRxeArbFirstErrorStatus);
PHBERR(p, " phbRxeArbErrorLog0 = %016llx\n", s->phbRxeArbErrorLog0);
PHBERR(p, " phbRxeArbErrorLog1 = %016llx\n", s->phbRxeArbErrorLog1);
PHBERR(p, " phbRxeMrgErrorStatus = %016llx\n", s->phbRxeMrgErrorStatus);
PHBERR(p, "phbRxeMrgFrstErrorStatus = %016llx\n", s->phbRxeMrgFirstErrorStatus);
PHBERR(p, " phbRxeMrgErrorLog0 = %016llx\n", s->phbRxeMrgErrorLog0);
PHBERR(p, " phbRxeMrgErrorLog1 = %016llx\n", s->phbRxeMrgErrorLog1);
PHBERR(p, " phbRxeTceErrorStatus = %016llx\n", s->phbRxeTceErrorStatus);
PHBERR(p, "phbRxeTceFrstErrorStatus = %016llx\n", s->phbRxeTceFirstErrorStatus);
PHBERR(p, " phbRxeTceErrorLog0 = %016llx\n", s->phbRxeTceErrorLog0);
PHBERR(p, " phbRxeTceErrorLog1 = %016llx\n", s->phbRxeTceErrorLog1);
PHBERR(p, " phbPblErrorStatus = %016llx\n", s->phbPblErrorStatus);
PHBERR(p, " phbPblFirstErrorStatus = %016llx\n", s->phbPblFirstErrorStatus);
PHBERR(p, " phbPblErrorLog0 = %016llx\n", s->phbPblErrorLog0);
PHBERR(p, " phbPblErrorLog1 = %016llx\n", s->phbPblErrorLog1);
PHBERR(p, " phbPcieDlpErrorLog1 = %016llx\n", s->phbPcieDlpErrorLog1);
PHBERR(p, " phbPcieDlpErrorLog2 = %016llx\n", s->phbPcieDlpErrorLog2);
PHBERR(p, " phbPcieDlpErrorStatus = %016llx\n", s->phbPcieDlpErrorStatus);

PHBERR(p, " phbRegbErrorStatus = %016llx\n", s->phbRegbErrorStatus);
PHBERR(p, " phbRegbFirstErrorStatus = %016llx\n", s->phbRegbFirstErrorStatus);
PHBERR(p, " phbRegbErrorLog0 = %016llx\n", s->phbRegbErrorLog0);
PHBERR(p, " phbRegbErrorLog1 = %016llx\n", s->phbRegbErrorLog1);

for (i = 0; i < OPAL_PHB4_NUM_PEST_REGS; i++) {
if (!s->pestA[i] && !s->pestB[i])
continue;
PHBERR(p, " PEST[%03d] = %016llx %016llx\n",
i, s->pestA[i], s->pestB[i]);
}
free(s);
}

/* Check if AIB is fenced via PBCQ NFIR */
static bool phb4_fenced(struct phb4 *p)
{
Expand Down Expand Up @@ -204,6 +284,9 @@ static bool phb4_fenced(struct phb4 *p)
p->flags |= PHB4_AIB_FENCED;
p->state = PHB4_STATE_FENCED;

if (verbose_eeh)
phb4_eeh_dump_regs(p);

return true;
}

Expand Down Expand Up @@ -241,7 +324,7 @@ static int64_t phb4_pcicfg_check(struct phb4 *p, uint32_t bdfn,
}

static int64_t phb4_rc_read(struct phb4 *p, uint32_t offset, uint8_t sz,
void *data)
void *data, bool use_asb)
{
uint32_t reg = offset & ~3;
uint32_t oval;
Expand All @@ -268,9 +351,13 @@ static int64_t phb4_rc_read(struct phb4 *p, uint32_t offset, uint8_t sz,
break;
default:
oval = 0xffffffff; /* default if offset too big */
if (reg < PHB_RC_CONFIG_SIZE)
/* XXX Add ASB support ? */
oval = in_le32(p->regs + PHB_RC_CONFIG_BASE + reg);
if (reg < PHB_RC_CONFIG_SIZE) {
if (use_asb)
oval = bswap_32(phb4_read_reg_asb(p, PHB_RC_CONFIG_BASE
+ reg));
else
oval = in_le32(p->regs + PHB_RC_CONFIG_BASE + reg);
}
}
switch (sz) {
case 1:
Expand All @@ -291,7 +378,7 @@ static int64_t phb4_rc_read(struct phb4 *p, uint32_t offset, uint8_t sz,
}

static int64_t phb4_rc_write(struct phb4 *p, uint32_t offset, uint8_t sz,
uint32_t val)
uint32_t val, bool use_asb)
{
uint32_t reg = offset & ~3;
uint32_t old, mask, shift, oldold;
Expand All @@ -302,7 +389,7 @@ static int64_t phb4_rc_write(struct phb4 *p, uint32_t offset, uint8_t sz,

/* If size isn't 4-bytes, do a RMW cycle */
if (sz < 4) {
rc = phb4_rc_read(p, reg, 4, &old);
rc = phb4_rc_read(p, reg, 4, &old, use_asb);
if (rc != OPAL_SUCCESS)
return rc;

Expand Down Expand Up @@ -366,11 +453,13 @@ static int64_t phb4_rc_write(struct phb4 *p, uint32_t offset, uint8_t sz,
case PCI_CFG_IO_BASE_U16: /* Includes PCI_CFG_IO_LIMIT_U16 */
break;
default:
/* XXX Add ASB support ? */
/* Workaround PHB config space enable */
if ((p->rev == PHB4_REV_NIMBUS_DD10) && (reg == PCI_CFG_CMD))
val |= PCI_CFG_CMD_MEM_EN | PCI_CFG_CMD_BUS_MASTER_EN;
out_le32(p->regs + PHB_RC_CONFIG_BASE + reg, val);
if (use_asb)
phb4_write_reg_asb(p, PHB_RC_CONFIG_BASE + reg, val);
else
out_le32(p->regs + PHB_RC_CONFIG_BASE + reg, val);
}
return OPAL_SUCCESS;
}
Expand Down Expand Up @@ -404,7 +493,7 @@ static int64_t phb4_pcicfg_read(struct phb4 *p, uint32_t bdfn,

/* Handle root complex MMIO based config space */
if (bdfn == 0)
return phb4_rc_read(p, offset, size, data);
return phb4_rc_read(p, offset, size, data, use_asb);

addr = PHB_CA_ENABLE;
addr = SETFIELD(PHB_CA_BDFN, addr, bdfn);
Expand Down Expand Up @@ -495,7 +584,7 @@ static int64_t phb4_pcicfg_write(struct phb4 *p, uint32_t bdfn,

/* Handle root complex MMIO based config space */
if (bdfn == 0)
return phb4_rc_write(p, offset, size, data);
return phb4_rc_write(p, offset, size, data, use_asb);

addr = PHB_CA_ENABLE;
addr = SETFIELD(PHB_CA_BDFN, addr, bdfn);
Expand Down Expand Up @@ -1702,19 +1791,14 @@ static void phb4_read_phb_status(struct phb4 *p,
stat->common.ioType = OPAL_PHB_ERROR_DATA_TYPE_PHB4;
stat->common.len = sizeof(struct OpalIoPhb4ErrorData);

/*
* TODO: investigate reading registers through ASB instead of AIB.
*
* Until this is implemented, some registers may be unreadable through
* a fence.
*/
/* Use ASB for config space if the PHB is fenced */
if (p->flags & PHB4_AIB_FENCED)
p->flags |= PHB4_CFG_USE_ASB;

/* Grab RC bridge control, make it 32-bit */
phb4_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &val);
stat->brdgCtl = val;

/* XXX: No UTL registers on PHB4? */

/*
* Grab various RC PCIe capability registers. All device, slot
* and link status are 16-bit, so we grab the pair control+status
Expand All @@ -1727,7 +1811,7 @@ static void phb4_read_phb_status(struct phb4 *p,
phb4_pcicfg_read32(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL,
&stat->linkStatus);

/*
/*
* I assume those are the standard config space header, cmd & status
* together makes 32-bit. Secondary status is 16-bit so I'll clear
* the top on that one
Expand All @@ -1754,6 +1838,9 @@ static void phb4_read_phb_status(struct phb4 *p,
phb4_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_SRCID,
&stat->sourceId);

/* Restore config space to MMIO instead of ASB */
p->flags &= ~PHB4_CFG_USE_ASB;

/* PEC NFIR, same as P8/PHB3 */
xscom_read(p->chip_id, p->pe_stk_xscom + 0x0, &stat->nFir);
xscom_read(p->chip_id, p->pe_stk_xscom + 0x3, &stat->nFirMask);
Expand Down Expand Up @@ -2890,6 +2977,9 @@ static int64_t phb4_get_diag_data(struct phb *phb,
phb4_fenced(p);
phb4_read_phb_status(p, data);

if (verbose_eeh && !(p->flags & PHB4_AIB_FENCED))
phb4_eeh_dump_regs(p);

/*
* We're running to here probably because of errors
* (INF class). For that case, we need clear the error
Expand Down Expand Up @@ -4433,6 +4523,10 @@ void probe_phb4(void)
{
struct dt_node *np;

verbose_eeh = nvram_query_eq("pci-eeh-verbose", "true");
if (verbose_eeh)
prlog(PR_INFO, "PHB4: Verbose EEH enabled\n");

/* Look for PBCQ XSCOM nodes */
dt_for_each_compatible(dt_root, np, "ibm,power9-pbcq")
phb4_probe_pbcq(np);
Expand Down

0 comments on commit b54845a

Please sign in to comment.