/*
- * $Id: lspci.c,v 1.34 2000/01/20 21:23:14 mj Exp $
+ * $Id: lspci.c,v 1.43 2002/12/26 20:24:50 mj Exp $
*
* Linux PCI Utilities -- List All PCI Devices
*
- * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright (c) 1997--2002 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-v\t\tBe verbose\n\
-n\t\tShow numeric ID's\n\
-b\t\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\
--x\t\tShow hex-dump of config space\n\
+-x\t\tShow hex-dump of the standard portion of config space\n\
+-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n\
-s [[<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n\
-d [<vendor>]:[<device>]\tShow only selected devices\n\
-t\t\tShow bus tree\n\
#define IO_FORMAT "%04lx"
#endif
+/*
+ * If we aren't being compiled by GCC, use malloc() instead of alloca().
+ * This increases our memory footprint, but only slightly since we don't
+ * use alloca() much.
+ */
+
+#ifndef __GNUC__
+#define alloca malloc
+#endif
+
/* Our view of the PCI bus */
struct device {
static void
show_pm(struct device *d, int where, int cap)
{
- int t;
+ int t, b;
+ static int pm_aux_current[8] = { 0, 55, 100, 160, 220, 270, 320, 375 };
printf("Power Management version %d\n", cap & PCI_PM_CAP_VER_MASK);
if (verbose < 2)
return;
- printf("\t\tFlags: PMEClk%c AuxPwr%c DSI%c D1%c D2%c PME%c\n",
+ printf("\t\tFlags: PMEClk%c DSI%c D1%c D2%c AuxCurrent=%dmA PME(D0%c,D1%c,D2%c,D3hot%c,D3cold%c)\n",
FLAG(cap, PCI_PM_CAP_PME_CLOCK),
- FLAG(cap, PCI_PM_CAP_AUX_POWER),
FLAG(cap, PCI_PM_CAP_DSI),
FLAG(cap, PCI_PM_CAP_D1),
FLAG(cap, PCI_PM_CAP_D2),
- FLAG(cap, PCI_PM_CAP_PME));
+ pm_aux_current[(cap >> 6) & 7],
+ FLAG(cap, PCI_PM_CAP_PME_D0),
+ FLAG(cap, PCI_PM_CAP_PME_D1),
+ FLAG(cap, PCI_PM_CAP_PME_D2),
+ FLAG(cap, PCI_PM_CAP_PME_D3_HOT),
+ FLAG(cap, PCI_PM_CAP_PME_D3_COLD));
config_fetch(d, where + PCI_PM_CTRL, PCI_PM_SIZEOF - PCI_PM_CTRL);
t = get_conf_word(d, where + PCI_PM_CTRL);
- printf("\t\tStatus: D%d PME-Enable%c DSel=%x DScale=%x PME%c\n",
+ printf("\t\tStatus: D%d PME-Enable%c DSel=%d DScale=%d PME%c\n",
t & PCI_PM_CTRL_STATE_MASK,
FLAG(t, PCI_PM_CTRL_PME_ENABLE),
(t & PCI_PM_CTRL_DATA_SEL_MASK) >> 9,
(t & PCI_PM_CTRL_DATA_SCALE_MASK) >> 13,
FLAG(t, PCI_PM_CTRL_PME_STATUS));
+ b = get_conf_byte(d, where + PCI_PM_PPB_EXTENSIONS);
+ if (b)
+ printf("\t\tBridge: PM%c B3%c\n",
+ FLAG(t, PCI_PM_BPCC_ENABLE),
+ FLAG(~t, PCI_PM_PPB_B2_B3));
}
static void
-format_agp_rate(int rate, char *buf)
+format_agp_rate(int rate, char *buf, int agp3)
{
char *c = buf;
int i;
- for(i=0; i<2; i++)
+ for(i=0; i<=2; i++)
if (rate & (1 << i))
{
if (c != buf)
*c++ = ',';
*c++ = 'x';
- *c++ = '0' + (4 >> i);
+ *c++ = '0' + (1 << (i + 2*agp3));
}
if (c != buf)
*c = 0;
{
u32 t;
char rate[8];
+ int ver, rev;
+ int agp3 = 0;
- t = cap & 0xff;
- printf("AGP version %x.%x\n", cap/16, cap%16);
+ ver = (cap >> 4) & 0x0f;
+ rev = cap & 0x0f;
+ printf("AGP version %x.%x\n", ver, rev);
if (verbose < 2)
return;
config_fetch(d, where + PCI_AGP_STATUS, PCI_AGP_SIZEOF - PCI_AGP_STATUS);
t = get_conf_long(d, where + PCI_AGP_STATUS);
- format_agp_rate(t & 7, rate);
- printf("\t\tStatus: RQ=%d SBA%c 64bit%c FW%c Rate=%s\n",
- (t & PCI_AGP_STATUS_RQ_MASK) >> 24U,
+ if (ver >= 3 && (t & PCI_AGP_STATUS_AGP3))
+ agp3 = 1;
+ format_agp_rate(t & 7, rate, agp3);
+ printf("\t\tStatus: RQ=%d Iso%c ArqSz=%d Cal=%d SBA%c ITACoh%c GART64%c HTrans%c 64bit%c FW%c AGP3%c Rate=%s\n",
+ ((t & PCI_AGP_STATUS_RQ_MASK) >> 24U) + 1,
+ FLAG(t, PCI_AGP_STATUS_ISOCH),
+ ((t & PCI_AGP_STATUS_ARQSZ_MASK) >> 13),
+ ((t & PCI_AGP_STATUS_CAL_MASK) >> 10),
FLAG(t, PCI_AGP_STATUS_SBA),
+ FLAG(t, PCI_AGP_STATUS_ITA_COH),
+ FLAG(t, PCI_AGP_STATUS_GART64),
+ FLAG(t, PCI_AGP_STATUS_HTRANS),
FLAG(t, PCI_AGP_STATUS_64BIT),
FLAG(t, PCI_AGP_STATUS_FW),
+ FLAG(t, PCI_AGP_STATUS_AGP3),
rate);
t = get_conf_long(d, where + PCI_AGP_COMMAND);
- format_agp_rate(t & 7, rate);
- printf("\t\tCommand: RQ=%d SBA%c AGP%c 64bit%c FW%c Rate=%s\n",
- (t & PCI_AGP_COMMAND_RQ_MASK) >> 24U,
+ format_agp_rate(t & 7, rate, agp3);
+ printf("\t\tCommand: RQ=%d ArqSz=%d Cal=%d SBA%c AGP%c GART64%c 64bit%c FW%c Rate=%s\n",
+ ((t & PCI_AGP_COMMAND_RQ_MASK) >> 24U) + 1,
+ ((t & PCI_AGP_COMMAND_ARQSZ_MASK) >> 13),
+ ((t & PCI_AGP_COMMAND_CAL_MASK) >> 10),
FLAG(t, PCI_AGP_COMMAND_SBA),
FLAG(t, PCI_AGP_COMMAND_AGP),
+ FLAG(t, PCI_AGP_COMMAND_GART64),
FLAG(t, PCI_AGP_COMMAND_64BIT),
FLAG(t, PCI_AGP_COMMAND_FW),
rate);
}
+static void
+show_pcix_nobridge(struct device *d, int where)
+{
+ u16 command = get_conf_word(d, where + PCI_PCIX_COMMAND);
+ u32 status = get_conf_long(d, where + PCI_PCIX_STATUS);
+ printf("PCI-X non-bridge device.\n");
+ if (verbose < 2)
+ return;
+ printf("\t\tCommand: DPERE%c ERO%c RBC=%d OST=%d\n",
+ FLAG(command, PCI_PCIX_COMMAND_DPERE),
+ FLAG(command, PCI_PCIX_COMMAND_ERO),
+ ((command & PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT) >> 2U),
+ ((command & PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS) >> 4U));
+ printf("\t\tStatus: Bus=%u Dev=%u Func=%u 64bit%c 133MHz%c SCD%c USC%c, DC=%s, DMMRBC=%u, DMOST=%u, DMCRS=%u, RSCEM%c",
+ ((status >> 8) & 0xffU), // bus
+ ((status >> 3) & 0x1fU), // dev
+ (status & PCI_PCIX_BRIDGE_STATUS_FUNCTION), // function
+ FLAG(status, PCI_PCIX_STATUS_64BIT),
+ FLAG(status, PCI_PCIX_STATUS_133MHZ),
+ FLAG(status, PCI_PCIX_STATUS_SC_DISCARDED),
+ FLAG(status, PCI_PCIX_STATUS_UNEXPECTED_SC),
+ ((status & PCI_PCIX_STATUS_DEVICE_COMPLEXITY) ? "bridge" : "simple"),
+ ((status >> 21) & 3U),
+ ((status >> 23) & 7U),
+ ((status >> 26) & 7U),
+ FLAG(status, PCI_PCIX_STATUS_RCVD_SC_ERR_MESS));
+}
+
+static void
+show_pcix_bridge(struct device *d, int where)
+{
+ u16 secstatus;
+ u32 status, upstcr, downstcr;
+ printf("PCI-X bridge device.\n");
+ if (verbose < 2)
+ return;
+ secstatus = get_conf_word(d, where + PCI_PCIX_BRIDGE_SEC_STATUS);
+ printf("\t\tSecondary Status: 64bit%c, 133MHz%c, SCD%c, USC%c, SCO%c, SRD%c Freq=%d\n",
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_64BIT),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_133MHZ),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SC_DISCARDED),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_UNEXPECTED_SC),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SC_OVERRUN),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SPLIT_REQUEST_DELAYED),
+ ((secstatus >> 6) & 7));
+ status = get_conf_long(d, where + PCI_PCIX_BRIDGE_STATUS);
+ printf("\t\tStatus: Bus=%u Dev=%u Func=%u 64bit%c 133MHz%c SCD%c USC%c, SCO%c, SRD%c\n",
+ ((status >> 8) & 0xff), // bus
+ ((status >> 3) & 0x1f), // dev
+ (status & PCI_PCIX_BRIDGE_STATUS_FUNCTION), // function
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_64BIT),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_133MHZ),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SC_DISCARDED),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_UNEXPECTED_SC),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SC_OVERRUN),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SPLIT_REQUEST_DELAYED));
+ upstcr = get_conf_long(d, where + PCI_PCIX_BRIDGE_UPSTREAM_SPLIT_TRANS_CTRL);
+ printf("\t\t: Upstream: Capacity=%u, Commitment Limit=%u\n",
+ (upstcr & PCI_PCIX_BRIDGE_STR_CAPACITY),
+ (upstcr >> 16) & 0xffff);
+ downstcr = get_conf_long(d, where + PCI_PCIX_BRIDGE_DOWNSTREAM_SPLIT_TRANS_CTRL);
+ printf("\t\t: Downstream: Capacity=%u, Commitment Limit=%u\n",
+ (downstcr & PCI_PCIX_BRIDGE_STR_CAPACITY),
+ (downstcr >> 16) & 0xffff);
+}
+
+static void
+show_pcix(struct device *d, int where)
+{
+ switch (d->dev->hdrtype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ show_pcix_nobridge(d, where);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ show_pcix_bridge(d, where);
+ break;
+ }
+}
+
static void
show_rom(struct device *d)
{
case PCI_CAP_ID_MSI:
show_msi(d, where, cap);
break;
+ case PCI_CAP_ID_PCIX:
+ show_pcix(d, where);
+ break;
default:
printf("#%02x [%04x]\n", id, cap);
}
{
case PCI_HEADER_TYPE_NORMAL:
if (class == PCI_CLASS_BRIDGE_PCI)
- {
- badhdr:
- printf("\t!!! Header type %02x doesn't match class code %04x\n", htype, class);
- return;
- }
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
max_lat = get_conf_byte(d, PCI_MAX_LAT);
min_gnt = get_conf_byte(d, PCI_MIN_GNT);
subsys_v = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID);
break;
case PCI_HEADER_TYPE_BRIDGE:
if (class != PCI_CLASS_BRIDGE_PCI)
- goto badhdr;
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
irq = int_pin = min_gnt = max_lat = 0;
subsys_v = subsys_d = 0;
break;
case PCI_HEADER_TYPE_CARDBUS:
if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
- goto badhdr;
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
min_gnt = max_lat = 0;
subsys_v = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
subsys_d = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
FLAG(status, PCI_STATUS_DETECTED_PARITY));
if (cmd & PCI_COMMAND_MASTER)
{
- printf("\tLatency: ");
- if (min_gnt)
- printf("%d min, ", min_gnt);
- if (max_lat)
- printf("%d max, ", max_lat);
- printf("%d set", latency);
+ printf("\tLatency: %d", latency);
+ if (min_gnt || max_lat)
+ {
+ printf(" (");
+ if (min_gnt)
+ printf("%dns min", min_gnt*250);
+ if (min_gnt && max_lat)
+ printf(", ");
+ if (max_lat)
+ printf("%dns max", max_lat*250);
+ putchar(')');
+ }
if (cache_line)
printf(", cache line size %02x", cache_line);
putchar('\n');
struct bridge *c;
for(c=b->child; c; c=c->next)
if (c->secondary <= p->bus && p->bus <= c->subordinate)
- return insert_dev(d, c);
+ {
+ insert_dev(d, c);
+ return;
+ }
bus = new_bus(b, p->bus);
}
/* Simple insertion at the end _does_ guarantee the correct order as the