Skip to content

Commit

Permalink
s390/pci: add error record for CC 2 retries
Browse files Browse the repository at this point in the history
Currently it is not detectable from within Linux when PCI instructions
are retried because of a busy condition. Detecting such conditions and
especially how long they lasted can however be quite useful in problem
determination. This patch enables this by adding an s390dbf error log
when a CC 2 is first encountered as well as after the retried
instruction.

Despite being unlikely it may be possible that these added debug
messages drown out important other messages so allow setting the debug
level in zpci_err_insn*() and set their level to 1 so they can be
filtered out if need be.

Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
  • Loading branch information
Niklas Schnelle authored and Heiko Carstens committed Apr 25, 2022
1 parent cde8833 commit 34fb0e7
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 18 deletions.
7 changes: 6 additions & 1 deletion arch/s390/include/asm/pci_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ extern debug_info_t *pci_debug_err_id;
debug_text_event(pci_debug_err_id, 0, debug_buffer); \
} while (0)

static inline void zpci_err_hex_level(int level, void *addr, int len)
{
debug_event(pci_debug_err_id, level, addr, len);
}

static inline void zpci_err_hex(void *addr, int len)
{
debug_event(pci_debug_err_id, 0, addr, len);
zpci_err_hex_level(0, addr, len);
}

#endif
74 changes: 57 additions & 17 deletions arch/s390/pci/pci_insn.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@ struct zpci_err_insn_data {
};
} __packed;

static inline void zpci_err_insn_req(u8 insn, u8 cc, u8 status,
static inline void zpci_err_insn_req(int lvl, u8 insn, u8 cc, u8 status,
u64 req, u64 offset)
{
struct zpci_err_insn_data data = {
.insn = insn, .cc = cc, .status = status,
.req = req, .offset = offset};

zpci_err_hex(&data, sizeof(data));
zpci_err_hex_level(lvl, &data, sizeof(data));
}

static inline void zpci_err_insn_addr(u8 insn, u8 cc, u8 status,
static inline void zpci_err_insn_addr(int lvl, u8 insn, u8 cc, u8 status,
u64 addr, u64 len)
{
struct zpci_err_insn_data data = {
.insn = insn, .cc = cc, .status = status,
.addr = addr, .len = len};

zpci_err_hex(&data, sizeof(data));
zpci_err_hex_level(lvl, &data, sizeof(data));
}

/* Modify PCI Function Controls */
Expand All @@ -71,16 +71,24 @@ static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)

u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
{
bool retried = false;
u8 cc;

do {
cc = __mpcifc(req, fib, status);
if (cc == 2)
if (cc == 2) {
msleep(ZPCI_INSN_BUSY_DELAY);
if (!retried) {
zpci_err_insn_req(1, 'M', cc, *status, req, 0);
retried = true;
}
}
} while (cc == 2);

if (cc)
zpci_err_insn_req('M', cc, *status, req, 0);
zpci_err_insn_req(0, 'M', cc, *status, req, 0);
else if (retried)
zpci_err_insn_req(1, 'M', cc, *status, req, 0);

return cc;
}
Expand All @@ -104,16 +112,24 @@ static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)

int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
{
bool retried = false;
u8 cc, status;

do {
cc = __rpcit(fn, addr, range, &status);
if (cc == 2)
if (cc == 2) {
udelay(ZPCI_INSN_BUSY_DELAY);
if (!retried) {
zpci_err_insn_addr(1, 'R', cc, status, addr, range);
retried = true;
}
}
} while (cc == 2);

if (cc)
zpci_err_insn_addr('R', cc, status, addr, range);
zpci_err_insn_addr(0, 'R', cc, status, addr, range);
else if (retried)
zpci_err_insn_addr(1, 'R', cc, status, addr, range);

if (cc == 1 && (status == 4 || status == 16))
return -ENOMEM;
Expand Down Expand Up @@ -168,17 +184,25 @@ static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)

int __zpci_load(u64 *data, u64 req, u64 offset)
{
bool retried = false;
u8 status;
int cc;

do {
cc = __pcilg(data, req, offset, &status);
if (cc == 2)
if (cc == 2) {
udelay(ZPCI_INSN_BUSY_DELAY);
if (!retried) {
zpci_err_insn_req(1, 'l', cc, status, req, offset);
retried = true;
}
}
} while (cc == 2);

if (cc)
zpci_err_insn_req('l', cc, status, req, offset);
zpci_err_insn_req(0, 'l', cc, status, req, offset);
else if (retried)
zpci_err_insn_req(1, 'l', cc, status, req, offset);

return (cc > 0) ? -EIO : cc;
}
Expand Down Expand Up @@ -222,7 +246,7 @@ int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)

cc = __pcilg_mio(data, (__force u64) addr, len, &status);
if (cc)
zpci_err_insn_addr('L', cc, status, (__force u64) addr, len);
zpci_err_insn_addr(0, 'L', cc, status, (__force u64) addr, len);

return (cc > 0) ? -EIO : cc;
}
Expand All @@ -249,17 +273,25 @@ static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)

int __zpci_store(u64 data, u64 req, u64 offset)
{
bool retried = false;
u8 status;
int cc;

do {
cc = __pcistg(data, req, offset, &status);
if (cc == 2)
if (cc == 2) {
udelay(ZPCI_INSN_BUSY_DELAY);
if (!retried) {
zpci_err_insn_req(1, 's', cc, status, req, offset);
retried = true;
}
}
} while (cc == 2);

if (cc)
zpci_err_insn_req('s', cc, status, req, offset);
zpci_err_insn_req(0, 's', cc, status, req, offset);
else if (retried)
zpci_err_insn_req(1, 's', cc, status, req, offset);

return (cc > 0) ? -EIO : cc;
}
Expand Down Expand Up @@ -302,7 +334,7 @@ int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)

cc = __pcistg_mio(data, (__force u64) addr, len, &status);
if (cc)
zpci_err_insn_addr('S', cc, status, (__force u64) addr, len);
zpci_err_insn_addr(0, 'S', cc, status, (__force u64) addr, len);

return (cc > 0) ? -EIO : cc;
}
Expand All @@ -328,17 +360,25 @@ static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)

int __zpci_store_block(const u64 *data, u64 req, u64 offset)
{
bool retried = false;
u8 status;
int cc;

do {
cc = __pcistb(data, req, offset, &status);
if (cc == 2)
if (cc == 2) {
udelay(ZPCI_INSN_BUSY_DELAY);
if (!retried) {
zpci_err_insn_req(0, 'b', cc, status, req, offset);
retried = true;
}
}
} while (cc == 2);

if (cc)
zpci_err_insn_req('b', cc, status, req, offset);
zpci_err_insn_req(0, 'b', cc, status, req, offset);
else if (retried)
zpci_err_insn_req(1, 'b', cc, status, req, offset);

return (cc > 0) ? -EIO : cc;
}
Expand Down Expand Up @@ -382,7 +422,7 @@ int zpci_write_block(volatile void __iomem *dst,

cc = __pcistb_mio(src, (__force u64) dst, len, &status);
if (cc)
zpci_err_insn_addr('B', cc, status, (__force u64) dst, len);
zpci_err_insn_addr(0, 'B', cc, status, (__force u64) dst, len);

return (cc > 0) ? -EIO : cc;
}
Expand Down

0 comments on commit 34fb0e7

Please sign in to comment.