prints out if bootverbose is set. This is to facilitate the code being removed from the kernel at a later date. While we're here, fix the __packed structures, and add some other PCI interrupt router IDs. Submitted by: jhb (with some tweaks) MFC after: 3 weeks
306 lines
7.7 KiB
C
306 lines
7.7 KiB
C
/*
|
|
* Copyright (c) 2002-2005 Bruce M. Simpson.
|
|
* All rights reserved
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Bruce M. Simpson.
|
|
* 4. Neither the name of Bruce M. Simpson nor the names of
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY BRUCE M. SIMPSON AND AFFILIATES
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/memrange.h>
|
|
#include <sys/stat.h>
|
|
#include <machine/endian.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <libgen.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "pirtable.h"
|
|
|
|
#define _PATH_DEVMEM "/dev/mem"
|
|
|
|
void usage(void);
|
|
void banner(void);
|
|
pir_table_t *find_pir_table(unsigned char *base);
|
|
void dump_pir_table(pir_table_t *pir, char *map_addr);
|
|
void pci_print_irqmask(u_int16_t irqs);
|
|
void print_irq_line(int entry, pir_entry_t *p, char line, u_int8_t link,
|
|
u_int16_t irqs);
|
|
char *lookup_southbridge(u_int32_t id);
|
|
|
|
char *progname = NULL;
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int ch, r;
|
|
int err = -1;
|
|
int mem_fd = -1;
|
|
pir_table_t *pir = NULL;
|
|
void *map_addr = MAP_FAILED;
|
|
char *real_pir;
|
|
|
|
progname = basename(argv[0]);
|
|
while ((ch = getopt(argc, argv, "h")) != -1)
|
|
switch (ch) {
|
|
case 'h':
|
|
default:
|
|
usage();
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (argc > 0)
|
|
usage();
|
|
|
|
banner();
|
|
/*
|
|
* Map the PIR region into our process' linear space.
|
|
*/
|
|
if ((mem_fd = open(_PATH_DEVMEM, O_RDONLY)) == -1) {
|
|
perror("open");
|
|
goto cleanup;
|
|
}
|
|
map_addr = mmap(NULL, PIR_SIZE, PROT_READ, MAP_SHARED, mem_fd,
|
|
PIR_BASE);
|
|
if (map_addr == MAP_FAILED) {
|
|
perror("mmap");
|
|
goto cleanup;
|
|
}
|
|
/*
|
|
* Find and print the PIR table.
|
|
*/
|
|
if ((pir = find_pir_table(map_addr)) == NULL) {
|
|
fprintf(stderr, "PIR table signature not found.\r\n");
|
|
} else {
|
|
dump_pir_table(pir, map_addr);
|
|
err = 0;
|
|
}
|
|
|
|
cleanup:
|
|
if (map_addr != MAP_FAILED)
|
|
munmap(map_addr, PIR_SIZE);
|
|
if (mem_fd != -1)
|
|
close(mem_fd);
|
|
|
|
exit ((err == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
|
|
fprintf(stderr, "usage: %s [-h]\r\n", progname);
|
|
fprintf(stderr, "-h\tdisplay this message\r\n", progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
banner(void)
|
|
{
|
|
|
|
fprintf(stderr, "PIRTOOL (c) 2002-2006 Bruce M. Simpson\r\n");
|
|
fprintf(stderr,
|
|
"---------------------------------------------\r\n\r\n");
|
|
}
|
|
|
|
pir_table_t *
|
|
find_pir_table(unsigned char *base)
|
|
{
|
|
unsigned int csum = 0;
|
|
unsigned char *p, *pend;
|
|
pir_table_t *pir = NULL;
|
|
|
|
/*
|
|
* From Microsoft's PCI IRQ Routing Table Specification 1.0:
|
|
*
|
|
* The PCI IRQ Routing Table can be detected by searching the
|
|
* system memory from F0000h to FFFFFh at every 16-byte boundary
|
|
* for the PCI IRQ routing signature ("$PIR").
|
|
*/
|
|
pend = base + PIR_SIZE;
|
|
for (p = base; p < pend; p += 16) {
|
|
if (strncmp(p, "$PIR", 4) == 0) {
|
|
pir = (pir_table_t *)p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now validate the table:
|
|
* Version: Must be 1.0.
|
|
* Table size: Must be larger than 32 and must be a multiple of 16.
|
|
* Checksum: The entire structure's checksum must be 0.
|
|
*/
|
|
if (pir && (pir->major == 1) && (pir->minor == 0) &&
|
|
(pir->size > 32) && ((pir->size % 16) == 0)) {
|
|
p = (unsigned char *)pir;
|
|
pend = p + pir->size;
|
|
|
|
while (p < pend)
|
|
csum += *p++;
|
|
|
|
if ((csum % 256) != 0)
|
|
fprintf(stderr,
|
|
"WARNING: PIR table checksum is invalid.\n");
|
|
}
|
|
|
|
return ((pir_table_t *)pir);
|
|
}
|
|
|
|
void
|
|
pci_print_irqmask(u_int16_t irqs)
|
|
{
|
|
int i, first;
|
|
|
|
if (irqs == 0) {
|
|
printf("none");
|
|
return;
|
|
}
|
|
first = 1;
|
|
for (i = 0; i < 16; i++, irqs >>= 1)
|
|
if (irqs & 1) {
|
|
if (!first)
|
|
printf(" ");
|
|
else
|
|
first = 0;
|
|
printf("%d", i);
|
|
}
|
|
}
|
|
|
|
void
|
|
dump_pir_table(pir_table_t *pir, char *map_addr)
|
|
{
|
|
int i, num_slots;
|
|
pir_entry_t *p, *pend;
|
|
|
|
num_slots = (pir->size - offsetof(pir_table_t, entry[0])) / 16;
|
|
|
|
printf( "PCI Interrupt Routing Table at 0x%08lX\r\n"
|
|
"-----------------------------------------\r\n"
|
|
"0x%02x: Signature: %c%c%c%c\r\n"
|
|
"0x%02x: Version: %u.%u\r\n"
|
|
"0x%02x: Size: %u bytes (%u entries)\r\n"
|
|
"0x%02x: Device: %u:%u:%u\r\n",
|
|
(u_int32_t)(((char *)pir - map_addr) + PIR_BASE),
|
|
offsetof(pir_table_t, signature),
|
|
((char *)&pir->signature)[0],
|
|
((char *)&pir->signature)[1],
|
|
((char *)&pir->signature)[2],
|
|
((char *)&pir->signature)[3],
|
|
offsetof(pir_table_t, minor),
|
|
pir->major, pir->minor,
|
|
offsetof(pir_table_t, size),
|
|
pir->size,
|
|
num_slots,
|
|
offsetof(pir_table_t, bus),
|
|
pir->bus,
|
|
PIR_DEV(pir->devfunc),
|
|
PIR_FUNC(pir->devfunc));
|
|
printf(
|
|
"0x%02x: PCI Exclusive IRQs: ",
|
|
offsetof(pir_table_t, excl_irqs));
|
|
pci_print_irqmask(pir->excl_irqs);
|
|
printf("\r\n"
|
|
"0x%02x: Compatible with: 0x%08X %s\r\n"
|
|
"0x%02x: Miniport Data: 0x%08X\r\n"
|
|
"0x%02x: Checksum: 0x%02X\r\n"
|
|
"\r\n",
|
|
offsetof(pir_table_t, compatible),
|
|
pir->compatible,
|
|
lookup_southbridge(pir->compatible),
|
|
offsetof(pir_table_t, miniport_data),
|
|
pir->miniport_data,
|
|
offsetof(pir_table_t, checksum),
|
|
pir->checksum);
|
|
|
|
p = pend = &pir->entry[0];
|
|
pend += num_slots;
|
|
printf("Entry Location Bus Device Pin Link IRQs\n");
|
|
for (i = 0; p < pend; i++, p++) {
|
|
print_irq_line(i, p, 'A', p->inta_link, p->inta_irqs);
|
|
print_irq_line(i, p, 'B', p->intb_link, p->intb_irqs);
|
|
print_irq_line(i, p, 'C', p->intc_link, p->intc_irqs);
|
|
print_irq_line(i, p, 'D', p->intd_link, p->intd_irqs);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Print interrupt map for a given PCI interrupt line.
|
|
*/
|
|
void
|
|
print_irq_line(int entry, pir_entry_t *p, char line, u_int8_t link,
|
|
u_int16_t irqs)
|
|
{
|
|
|
|
if (link == 0)
|
|
return;
|
|
|
|
printf("%3d ", entry);
|
|
if (p->slot == 0)
|
|
printf("embedded ");
|
|
else
|
|
printf("slot %-3d ", p->slot);
|
|
|
|
printf(" %3d %3d %c 0x%02x ", p->bus, PIR_DEV(p->devfunc),
|
|
line, link);
|
|
pci_print_irqmask(irqs);
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* Lookup textual descriptions for commonly-used south-bridges.
|
|
*/
|
|
char *
|
|
lookup_southbridge(u_int32_t id)
|
|
{
|
|
|
|
switch (id) {
|
|
case 0x157310b9:
|
|
return ("ALi M1573 (Hypertransport)");
|
|
case 0x06861106:
|
|
return ("VIA VT82C686/686A/686B (Apollo)");
|
|
case 0x122E8086:
|
|
return ("Intel 82371FB (Triton I/PIIX)");
|
|
case 0x26418086:
|
|
return ("Intel 82801FBM (ICH6M)");
|
|
case 0x70008086:
|
|
return ("Intel 82371SB (Natoma/Triton II/PIIX3)");
|
|
default:
|
|
return ("unknown chipset");
|
|
}
|
|
}
|