largely reimplement pci_conf_print():

* print all configuration space registers.  Then, where possible,
  interpret them.  (That is, PRESENT ALL THE DATA, then interpret it --
  don't hide data behind interpretation.  Also, when interpreting
  fields, try to print out the specific value that's being interpreted.)
* handle different header types.
* allow caller to specify a function which can interpret the
  device-dependent header and is responsible for pretty-printing it.

It spews (use 'options MSGBUFSIZE=...' 8-), but when you want the data,
you really want _all_ of it.

Still needs some cleanup and additional code (e.g. interepretation
of PCI-PCI (type 1) and PCI-Cardbus (type 2(?)) bridge headers).
This commit is contained in:
cgd 1998-05-18 17:25:17 +00:00
parent 27b21a3a47
commit 4b0876c74b
2 changed files with 202 additions and 104 deletions

View File

@ -1,8 +1,9 @@
/* $NetBSD: pci_subr.c,v 1.25 1998/05/03 19:46:15 thorpej Exp $ */
/* $NetBSD: pci_subr.c,v 1.26 1998/05/18 17:25:17 cgd Exp $ */
/*
* Copyright (c) 1997 Zubin D. Dittia. All rights reserved.
* Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved.
* Copyright (c) 1995, 1996, 1998
* Christopher G. Demetriou. All rights reserved.
* Copyright (c) 1994 Charles Hannum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -49,6 +50,11 @@
#include <dev/pci/pcidevs.h>
#endif
static void pci_conf_print_common __P((pci_chipset_tag_t, pcitag_t,
const pcireg_t *regs));
static void pci_conf_print_type1 __P((pci_chipset_tag_t, pcitag_t,
const pcireg_t *regs));
/*
* Descriptions of known PCI classes and subclasses.
*
@ -317,26 +323,26 @@ pci_devinfo(id_reg, class_reg, showclass, cp)
* pci_conf_print(pa->pa_pc, pa->pa_tag);
* #endif
*/
void
pci_conf_print(pc, tag)
#define i2o(i) ((i) * 4)
#define o2i(o) ((o) / 4)
static void
pci_conf_print_common(pc, tag, regs)
pci_chipset_tag_t pc;
pcitag_t tag;
const pcireg_t *regs;
{
pcireg_t rval, mask;
int reg, s;
#ifdef PCIVERBOSE
struct pci_knowndev *kdp;
static const char on_str[] = "ON", off_str[] = "OFF";
#endif
struct pci_class *classp, *subclassp;
pcireg_t rval;
printf("PCI configuration registers:\n");
rval = pci_conf_read(pc, tag, PCI_ID_REG);
rval = regs[o2i(PCI_ID_REG)];
#ifndef PCIVERBOSE
printf(" Vendor ID: 0x%04x\n", PCI_VENDOR(rval));
printf(" Device ID: 0x%04x\n", PCI_PRODUCT(rval));
printf(" Vendor ID: 0x%04x\n", PCI_VENDOR(rval));
printf(" Device ID: 0x%04x\n", PCI_PRODUCT(rval));
#else
for (kdp = pci_knowndevs; kdp->vendorname != NULL; kdp++) {
if (kdp->vendor == PCI_VENDOR(rval) &&
@ -346,48 +352,41 @@ pci_conf_print(pc, tag)
}
}
if (kdp->vendorname != NULL)
printf(" Vendor Name: %s\n", kdp->vendorname);
printf(" Vendor Name: %s (0x%04x)\n", kdp->vendorname,
PCI_VENDOR(rval));
else
printf(" Vendor ID: 0x%04x\n", PCI_VENDOR(rval));
printf(" Vendor ID: 0x%04x\n", PCI_VENDOR(rval));
if (kdp->productname != NULL && (kdp->flags & PCI_KNOWNDEV_NOPROD) == 0)
printf(" Device Name: %s\n", kdp->productname);
printf(" Device Name: %s (0x%04x)\n", kdp->productname,
PCI_PRODUCT(rval));
else
printf(" Device ID: 0x%04x\n", PCI_PRODUCT(rval));
printf(" Device ID: 0x%04x\n", PCI_PRODUCT(rval));
#endif /* PCIVERBOSE */
rval = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
#define onoff(str, bit) \
printf(" %s: %s\n", (str), (rval & (bit)) ? "on" : "off");
#ifndef PCIVERBOSE
printf(" Command/Status Register: 0x%08x\n", rval);
#else
rval = regs[o2i(PCI_COMMAND_STATUS_REG)];
#define onoff(reg) ((rval & (reg)) ? on_str : off_str)
printf(" Command Register:\n");
printf(" I/O space accesses %s\n", onoff(PCI_COMMAND_IO_ENABLE));
printf(" Mem space accesses %s\n", onoff(PCI_COMMAND_MEM_ENABLE));
printf(" Bus mastering %s\n", onoff(PCI_COMMAND_MASTER_ENABLE));
printf(" Special cycles %s\n", onoff(PCI_COMMAND_SPECIAL_ENABLE));
printf(" MWI transactions %s\n",
onoff(PCI_COMMAND_INVALIDATE_ENABLE));
printf(" Palette snooping %s\n", onoff(PCI_COMMAND_PALETTE_ENABLE));
printf(" Parity error checking %s\n",
onoff(PCI_COMMAND_PARITY_ENABLE));
printf(" Address/Data stepping %s\n",
onoff(PCI_COMMAND_STEPPING_ENABLE));
printf(" System Error (SERR) %s\n", onoff(PCI_COMMAND_SERR_ENABLE));
printf(" Fast back-to-back transactions %s\n",
onoff(PCI_COMMAND_BACKTOBACK_ENABLE));
printf(" Status Register:\n");
printf(" 66 MHz capable %s\n", onoff(PCI_STATUS_66MHZ_SUPPORT));
printf(" User Definable Features (UDF) support %s\n",
onoff(PCI_STATUS_UDF_SUPPORT));
printf(" Fast back-to-back capable %s\n",
onoff(PCI_STATUS_BACKTOBACK_SUPPORT));
printf(" Data parity error detected %s\n",
onoff(PCI_STATUS_PARITY_ERROR));
printf(" Command register: 0x%04x\n", rval & 0xffff);
onoff("I/O space accesses", PCI_COMMAND_IO_ENABLE);
onoff("Memory space accesses", PCI_COMMAND_MEM_ENABLE);
onoff("Bus mastering", PCI_COMMAND_MASTER_ENABLE);
onoff("Special cycles", PCI_COMMAND_SPECIAL_ENABLE);
onoff("MWI transactions", PCI_COMMAND_INVALIDATE_ENABLE);
onoff("Palette snooping", PCI_COMMAND_PALETTE_ENABLE);
onoff("Parity error checking", PCI_COMMAND_PARITY_ENABLE);
onoff("Address/data stepping", PCI_COMMAND_STEPPING_ENABLE);
onoff("System error (SERR)", PCI_COMMAND_SERR_ENABLE);
onoff("Fast back-to-back transactions", PCI_COMMAND_BACKTOBACK_ENABLE);
printf(" DEVSEL timing ");
printf(" Status register: 0x%04x\n", (rval >> 16) & 0xffff);
onoff("66 MHz capable", PCI_STATUS_66MHZ_SUPPORT);
onoff("User Definable Features (UDF) support", PCI_STATUS_UDF_SUPPORT);
onoff("Fast back-to-back capable", PCI_STATUS_BACKTOBACK_SUPPORT);
onoff("Data parity error detected", PCI_STATUS_PARITY_ERROR);
printf(" DEVSEL timing: ");
switch (rval & PCI_STATUS_DEVSEL_MASK) {
case PCI_STATUS_DEVSEL_FAST:
printf("fast");
@ -398,23 +397,21 @@ pci_conf_print(pc, tag)
case PCI_STATUS_DEVSEL_SLOW:
printf("slow");
break;
default:
printf("unknown/reserved"); /* XXX */
break;
}
printf("\n");
printf(" (0x%x)\n", (rval & PCI_STATUS_DEVSEL_MASK) >> 25);
printf(" Slave signaled Target Abort %s\n",
onoff(PCI_STATUS_TARGET_TARGET_ABORT));
printf(" Master received Target Abort %s\n",
onoff(PCI_STATUS_MASTER_TARGET_ABORT));
printf(" Master received Master Abort %s\n",
onoff(PCI_STATUS_MASTER_ABORT));
printf(" Asserted System Error (SERR) %s\n",
onoff(PCI_STATUS_SPECIAL_ERROR));
printf(" Parity error detected %s\n",
onoff(PCI_STATUS_PARITY_DETECT));
#endif /* PCIVERBOSE */
onoff("Slave signaled Target Abort", PCI_STATUS_TARGET_TARGET_ABORT);
onoff("Master received Target Abort", PCI_STATUS_MASTER_TARGET_ABORT);
onoff("Master received Master Abort", PCI_STATUS_MASTER_ABORT);
onoff("Asserted System Error (SERR)", PCI_STATUS_SPECIAL_ERROR);
onoff("Parity error detected", PCI_STATUS_PARITY_DETECT);
rval = pci_conf_read(pc, tag, PCI_CLASS_REG);
#undef onoff
rval = regs[o2i(PCI_CLASS_REG)];
for (classp = pci_class; classp->name != NULL; classp++) {
if (PCI_CLASS(rval) == classp->val)
break;
@ -426,26 +423,39 @@ pci_conf_print(pc, tag)
subclassp++;
}
if (classp->name != NULL) {
printf(" Class Name: %s\n", classp->name);
printf(" Class Name: %s (0x%02x)\n", classp->name,
PCI_CLASS(rval));
if (subclassp != NULL && subclassp->name != NULL)
printf(" Subclass Name: %s\n", subclassp->name);
printf(" Subclass Name: %s (0x%02x)\n",
subclassp->name, PCI_SUBCLASS(rval));
else
printf(" Subclass ID: 0x%02x\n", PCI_SUBCLASS(rval));
printf(" Subclass ID: 0x%02x\n", PCI_SUBCLASS(rval));
} else {
printf(" Class ID: 0x%02x\n", PCI_CLASS(rval));
printf(" Subclass ID: 0x%02x\n", PCI_SUBCLASS(rval));
printf(" Class ID: 0x%02x\n", PCI_CLASS(rval));
printf(" Subclass ID: 0x%02x\n", PCI_SUBCLASS(rval));
}
printf(" Interface: 0x%02x\n", PCI_INTERFACE(rval));
printf(" Revision ID: 0x%02x\n", PCI_REVISION(rval));
printf(" Interface: 0x%02x\n", PCI_INTERFACE(rval));
printf(" Revision ID: 0x%02x\n", PCI_REVISION(rval));
rval = pci_conf_read(pc, tag, PCI_BHLC_REG);
rval = regs[o2i(PCI_BHLC_REG)];
printf(" BIST: 0x%02x\n", PCI_BIST(rval));
printf(" Header Type: 0x%02x%s (0x%02x)\n", PCI_HDRTYPE_TYPE(rval),
PCI_HDRTYPE_MULTIFN(rval) ? "+multifunction" : "",
PCI_HDRTYPE(rval));
printf(" Latency Timer: 0x%02x\n", PCI_LATTIMER(rval));
printf(" Cache Line Size: 0x%02x\n", PCI_CACHELINE(rval));
}
printf(" BIST: 0x%02x\n", PCI_BIST(rval));
printf(" Header Type: 0x%02x\n", PCI_HDRTYPE(rval));
printf(" Latency Timer: 0x%02x\n", PCI_LATTIMER(rval));
printf(" Cache Line Size: 0x%02x\n", PCI_CACHELINE(rval));
static void
pci_conf_print_type1(pc, tag, regs)
pci_chipset_tag_t pc;
pcitag_t tag;
const pcireg_t *regs;
{
int off, s;
pcireg_t mask, rval;
for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
for (off = PCI_MAPREG_START; off < PCI_MAPREG_END; off += 4) {
/*
* Section 6.2.5.1, `Address Maps', tells us that:
*
@ -456,51 +466,76 @@ pci_conf_print(pc, tag)
* the bottom n bits of the address to 0. As recommended,
* we write all 1s and see what we get back.
*/
s = splhigh();
rval = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, 0xffffffff);
mask = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, rval);
splx(s);
rval = regs[o2i(off)];
if (rval != 0) {
/*
* The following sequence seems to make some devices
* (e.g. host bus bridges, which don't normally
* have their space mapped) very unhappy, to
* the point of crashing the system.
*
* Therefore, if the mapping register is zero to
* start out with, don't bother trying.
*/
s = splhigh();
pci_conf_write(pc, tag, off, 0xffffffff);
mask = pci_conf_read(pc, tag, off);
pci_conf_write(pc, tag, off, rval);
splx(s);
} else
mask = 0;
printf(" Mapping register at 0x%02x: ", off);
if (rval == 0) {
printf("not implemented(?)\n");
} else if (PCI_MAPREG_TYPE(rval) == PCI_MAPREG_TYPE_MEM) {
const char *type, *cache;
if (PCI_MAPREG_TYPE(rval) == PCI_MAPREG_TYPE_MEM) {
if (PCI_MAPREG_MEM_SIZE(mask) == 0)
continue;
printf(" Mapping register 0x%02x\n", reg);
printf(" Base Address: 0x%08x, size 0x%08x, "
"type = mem", PCI_MAPREG_MEM_ADDR(rval),
PCI_MAPREG_MEM_SIZE(mask));
switch (PCI_MAPREG_MEM_TYPE(rval)) {
case PCI_MAPREG_MEM_TYPE_32BIT:
printf(", 32-bit");
type = "32-bit";
break;
case PCI_MAPREG_MEM_TYPE_32BIT_1M:
printf(", 32-bit-1M");
type = "32-bit-1M";
break;
case PCI_MAPREG_MEM_TYPE_64BIT:
printf(", 64-bit");
type = "64-bit";
break;
default:
type = "unknown (XXX)";
break;
}
if (PCI_MAPREG_MEM_CACHEABLE(rval))
printf(", cacheable");
cache = "";
else
printf(", not cacheable");
printf("\n");
cache = "non";
printf("%s %scacheable memory\n", type, cache);
printf(" base address: 0x%08x, size: 0x%08x\n",
PCI_MAPREG_MEM_ADDR(rval),
PCI_MAPREG_MEM_SIZE(mask));
} else {
if (PCI_MAPREG_IO_SIZE(mask) == 0)
continue;
printf(" Mapping register 0x%02x\n", reg);
printf(" Base Address: 0x%08x, size 0x%08x, "
"type = i/o\n", PCI_MAPREG_IO_ADDR(rval),
printf("i/o\n");
printf(" base address: 0x%08x, size: 0x%08x\n",
PCI_MAPREG_IO_ADDR(rval),
PCI_MAPREG_IO_SIZE(mask));
}
}
rval = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
printf(" Cardbus CIS Pointer: 0x%08x\n", regs[o2i(0x28)]);
printf(" Maximum Latency: 0x%08x\n", (rval >> 24) & 0xff);
printf(" Minimum Grant: 0x%08x\n", (rval >> 16) & 0xff);
printf(" Interrupt pin: 0x%08x", PCI_INTERRUPT_PIN(rval));
rval = regs[o2i(0x2c)];
printf(" Subsystem vendor ID: 0x%04x\n", PCI_VENDOR(rval));
printf(" Subsystem ID: 0x%04x\n", PCI_PRODUCT(rval));
/* XXX */
printf(" Expansion ROM Base Address: 0x%08x\n", regs[o2i(0x30)]);
printf(" Reserved @ 0x34: 0x%08x\n", regs[o2i(0x34)]);
printf(" Reserved @ 0x38: 0x%08x\n", regs[o2i(0x38)]);
rval = regs[o2i(PCI_INTERRUPT_REG)];
printf(" Maximum Latency: 0x%02x\n", (rval >> 24) & 0xff);
printf(" Minimum Grant: 0x%02x\n", (rval >> 16) & 0xff);
printf(" Interrupt pin: 0x%02x", PCI_INTERRUPT_PIN(rval));
switch (PCI_INTERRUPT_PIN(rval)) {
case PCI_INTERRUPT_PIN_NONE:
printf(" (none)");
@ -519,5 +554,67 @@ pci_conf_print(pc, tag)
break;
}
printf("\n");
printf(" Interrupt line: 0x%08x\n", PCI_INTERRUPT_LINE(rval));
printf(" Interrupt line: 0x%02x\n", PCI_INTERRUPT_LINE(rval));
}
void
pci_conf_print(pc, tag, printfn)
pci_chipset_tag_t pc;
pcitag_t tag;
void (*printfn)(pci_chipset_tag_t, pcitag_t, const pcireg_t *);
{
pcireg_t regs[o2i(256)];
int off, hdrtype;
void (*typeprintfn)(pci_chipset_tag_t, pcitag_t, const pcireg_t *);
printf("PCI configuration registers:\n");
for (off = 0; off < 256; off += 4)
regs[o2i(off)] = pci_conf_read(pc, tag, off);
#define print16regs(offset) \
printf(" 0x%02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", (offset), \
regs[o2i((offset))], regs[o2i((offset) + 4)], \
regs[o2i((offset) + 8)], regs[o2i((offset) + 12)]);
/* common header */
printf(" Common header:\n");
for (off = 0; off < 16; off += 16)
print16regs(off);
printf("\n");
pci_conf_print_common(pc, tag, regs);
printf("\n");
/* type-dependent header */
hdrtype = PCI_HDRTYPE_TYPE(regs[o2i(PCI_BHLC_REG)]);
printf(" Type %d header:\n", hdrtype);
for (off = 16; off < 64; off += 16)
print16regs(off);
printf("\n");
switch (hdrtype) { /* XXX make a table, eventually */
case 0:
typeprintfn = &pci_conf_print_type1;
break;
case 1:
/* XXX */
default:
typeprintfn = 0;
}
if (typeprintfn)
(*typeprintfn)(pc, tag, regs);
else
printf(" Don't know how to pretty-print type %d header.\n",
hdrtype);
printf("\n");
/* device-dependent header */
printf(" Device-dependent header:\n");
for (off = 64; off < 256; off += 16)
print16regs(off);
printf("\n");
if (printfn)
(*printfn)(pc, tag, regs);
else
printf(" Don't know how to pretty-print device-dependent header.\n");
printf("\n");
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcivar.h,v 1.30 1998/05/15 12:35:06 tsubai Exp $ */
/* $NetBSD: pcivar.h,v 1.31 1998/05/18 17:25:18 cgd Exp $ */
/*
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
@ -159,7 +159,8 @@ int pci_mapreg_map __P((struct pci_attach_args *, int, pcireg_t, int,
* Helper functions for autoconfiguration.
*/
void pci_devinfo __P((pcireg_t, pcireg_t, int, char *));
void pci_conf_print __P((pci_chipset_tag_t, pcitag_t));
void pci_conf_print __P((pci_chipset_tag_t, pcitag_t,
void (*)(pci_chipset_tag_t, pcitag_t, const pcireg_t *)));
void set_pci_isa_bridge_callback __P((void (*)(void *), void *));
#endif /* _DEV_PCI_PCIVAR_H_ */