PCIe unsupported request with Intel 760p
Matthew Wilcox
willy at infradead.org
Mon May 7 08:16:27 PDT 2018
On Mon, May 07, 2018 at 09:12:47AM -0600, Keith Busch wrote:
> Hi Willy,
>
> Thank you for the detailed analysis. :)
You're welcome! Here's the program I wrote to decode the TLP. It's not
exactly fleshed out, but it could be used as the basis for a more
fully-featured TLP decoder in the future.
/*
* Decode TLPs as reported by Linux's AER support
*
* Copyright (c) Matthew Wilcox 2018
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* The format of the report looks like this:
*
* TLP Header: 34000000 70000010 00000000 88468846
*
* That's a stream of bytes, *not* 32-bit words. In that example, the
* byte 0x34 is byte 0, not byte 3.
*/
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
bool debug = false;
static int parse_header(unsigned char *header)
{
char s[256];
char *p;
int i;
p = fgets(s, 256, stdin);
if (p)
p = strstr(p, "TLP Header: ");
if (!p) {
fprintf(stderr, "Can\'t find \"TLP Header: \"\n");
return 1;
}
p += 12;
for (i = 0; i < 4; i++) {
unsigned long val = strtoul(p, NULL, 16);
header[0] = val >> 24;
header[1] = val >> 16;
header[2] = val >> 8;
header[3] = val;
p += 9;
header += 4;
}
return 0;
}
static void decode_requester(unsigned char *header)
{
printf("Requester ID %02x:%02x.%d\n", header[4], header[5] >> 3,
header[5] & 7);
}
static void decode_msg(unsigned char *header)
{
unsigned char code = header[7];
if (code == 0x00)
printf("Unlock Message\n");
if (code == 0x10)
printf("Latency Tolerance Reporting Message\n");
if (code == 0x12)
printf("Optimised Buffer Flush/Fill Message\n");
if (code == 0x14)
printf("PM NAK Message\n");
if (code == 0x18)
printf("PM PME Message\n");
if (code == 0x19)
printf("PM Turn Off Message\n");
if (code == 0x1b)
printf("PM Ack Turn Off Message\n");
if (code >= 0x20 && code <= 0x27)
printf("Legacy Interrupt Message (%d)\n", code & 7);
if (code == 0x30)
printf("Error Detected (Correctable) Message\n");
if (code == 0x31)
printf("Error Detected (NonFatal) Message\n");
if (code == 0x33)
printf("Error Detected (Fatal) Message\n");
if (code >= 0x40 && code <= 0x48)
printf("Hotplug Signalling Message\n");
if (code == 0x7e || code == 0x7f)
printf("Vendor Defined (Type %d) Message\n", code - 0x7e);
if (code == 0x90)
printf("Set Slot Power Limit Message\n");
decode_requester(header);
}
static void decode_type(unsigned char *header)
{
unsigned char type = *header;
if (type == 0x00 || type == 0x20)
printf("Memory Read Request\n");
if (type == 0x01 || type == 0x21)
printf("Memory Read Request Locked\n");
if (type == 0x40 || type == 0x60)
printf("Memory Write Request\n");
if (type == 0x02)
printf("I/O Read Request\n");
if (type == 0x42)
printf("I/O Write Request\n");
if (type == 0x04)
printf("Cfg0 Read Request\n");
if (type == 0x44)
printf("Cfg0 Write Request\n");
if (type == 0x05)
printf("Cfg1 Read Request\n");
if (type == 0x45)
printf("Cfg1 Write Request\n");
if (type == 0x1b)
printf("TCfg Read Request\n");
if (type == 0x5b)
printf("TCfg Write Request\n");
if (type >= 0x30 && type <= 0x37)
return decode_msg(header);
if (type >= 0x70 && type <= 0x77)
printf("Msg with Data Request\n");
if (type == 0x0a)
printf("Completion\n");
if (type == 0x4a)
printf("Completion with Data\n");
if (type == 0x0b)
printf("Completion of Locked Read without Data\n");
if (type == 0x4b)
printf("Completion of Locked Read with Data\n");
if (type == 0x4c || type == 0x6c)
printf("FetchAdd Request\n");
if (type == 0x4d || type == 0x6d)
printf("Swap Request\n");
if (type == 0x4e || type == 0x6e)
printf("CAS Request\n");
if (type >= 0x80 && type <= 0x8f) {
printf("Local TLP Prefix %d\n", type & 0xf);
return decode_type(header + 1);
}
if (type >= 0x90 && type <= 0x9f) {
printf("End-End TLP Prefix %d\n", type & 0xf);
return decode_type(header + 1);
}
}
static int usage(char **argv)
{
fprintf(stderr, "Usage: %s [-d]\n", argv[0]);
return 1;
}
int main(int argc, char **argv)
{
unsigned char header[16];
int opt;
while ((opt = getopt(argc, argv, "d")) != -1) {
switch (opt) {
case 'd':
debug = true;
break;
default:
return usage(argv);
}
}
if (argc > optind)
return usage(argv);
if (parse_header(header))
return 1;
if (debug)
printf("TLP Header: %02x%02x%02x%02x %02x%02x%02x%02x "
"%02x%02x%02x%02x %02x%02x%02x%02x\n",
header[0], header[1], header[2], header[3],
header[4], header[5], header[6], header[7],
header[8], header[9], header[10], header[11],
header[12], header[13], header[14], header[15]);
decode_type(header);
return 0;
}
More information about the Linux-nvme
mailing list