Created
January 6, 2012 03:18
-
-
Save syuu1228/1568777 to your computer and use it in GitHub Desktop.
Register Dump Tool for MSI Address Register & MSI Data Register / GPLv2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <pci/pci.h> | |
#define FLAG(x,y) ((x & y) ? '+' : '-') | |
/* | |
* Constants for Intel APIC based MSI messages. | |
*/ | |
/* | |
* Shifts for MSI data | |
*/ | |
#define MSI_DATA_VECTOR_SHIFT 0 | |
#define MSI_DATA_VECTOR_MASK 0x000000ff | |
#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & \ | |
MSI_DATA_VECTOR_MASK) | |
#define MSI_DATA_DELIVERY_MODE_SHIFT 8 | |
#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT) | |
#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT) | |
#define MSI_DATA_LEVEL_SHIFT 14 | |
#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | |
#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | |
#define MSI_DATA_TRIGGER_SHIFT 15 | |
#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | |
#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | |
/* | |
* Shift/mask fields for msi address | |
*/ | |
#define MSI_ADDR_BASE_HI 0 | |
#define MSI_ADDR_BASE_LO 0xfee00000 | |
#define MSI_ADDR_DEST_MODE_SHIFT 2 | |
#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT) | |
#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT) | |
#define MSI_ADDR_REDIRECTION_SHIFT 3 | |
#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | |
/* dedicated cpu */ | |
#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | |
/* lowest priority */ | |
#define MSI_ADDR_DEST_ID_SHIFT 12 | |
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 | |
#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \ | |
MSI_ADDR_DEST_ID_MASK) | |
#define MSI_ADDR_EXT_DEST_ID(dest) ((dest) & 0xffffff00) | |
#define MSI_ADDR_IR_EXT_INT (1 << 4) | |
#define MSI_ADDR_IR_SHV (1 << 3) | |
#define MSI_ADDR_IR_INDEX1(index) ((index & 0x8000) >> 13) | |
#define MSI_ADDR_IR_INDEX2(index) ((index & 0x7fff) << 5) | |
typedef uint8_t byte; | |
typedef uint16_t word; | |
struct device { | |
struct device *next; | |
struct pci_dev *dev; | |
unsigned int config_cnt; | |
byte config[256]; | |
}; | |
/* Config space accesses */ | |
static inline byte | |
get_conf_byte(struct device *d, unsigned int pos) | |
{ | |
return d->config[pos]; | |
} | |
static word | |
get_conf_word(struct device *d, unsigned int pos) | |
{ | |
return d->config[pos] | (d->config[pos+1] << 8); | |
} | |
static u32 | |
get_conf_long(struct device *d, unsigned int pos) | |
{ | |
return d->config[pos] | | |
(d->config[pos+1] << 8) | | |
(d->config[pos+2] << 16) | | |
(d->config[pos+3] << 24); | |
} | |
static void | |
show_msi(struct device *d, int where, int cap) | |
{ | |
int is64; | |
u32 address_hi, address_lo; | |
u16 data; | |
printf("Message Signalled Interrupts: 64bit%c Queue=%d/%d Enable%c\n", | |
FLAG(cap, PCI_MSI_FLAGS_64BIT), | |
(cap & PCI_MSI_FLAGS_QSIZE) >> 4, | |
(cap & PCI_MSI_FLAGS_QMASK) >> 1, | |
FLAG(cap, PCI_MSI_FLAGS_ENABLE)); | |
is64 = cap & PCI_MSI_FLAGS_64BIT; | |
if (!pci_read_block(d->dev, where + PCI_MSI_ADDRESS_LO, | |
d->config + where + PCI_MSI_ADDRESS_LO, | |
(is64 ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32) + 2 | |
- PCI_MSI_ADDRESS_LO)) { | |
printf("Unable to read 4 bytes of configuration space."); | |
return ; | |
} | |
if (is64) { | |
address_hi = get_conf_long(d, where + PCI_MSI_ADDRESS_HI); | |
data = get_conf_word(d, where + PCI_MSI_DATA_64); | |
}else{ | |
address_hi = 0; | |
data = get_conf_word(d, where + PCI_MSI_DATA_32); | |
} | |
address_lo = get_conf_long(d, where + PCI_MSI_ADDRESS_LO); | |
printf("address_hi=%x\n", address_hi); | |
printf("address_lo=%x dest_mode=%s redirection=%s dest_id=%u\n", | |
address_lo, | |
(address_lo & MSI_ADDR_DEST_MODE_LOGICAL) ? "logical" : "physical", | |
(address_lo & MSI_ADDR_REDIRECTION_LOWPRI) ? "lowpri" : "cpu", | |
(address_lo & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT); | |
printf("data=%x trigger=%s level=%s delivery_mode=%s vector=%u\n", | |
data, | |
(data & MSI_DATA_TRIGGER_LEVEL) ? "level" : "edge", | |
(data & MSI_DATA_LEVEL_ASSERT) ? "assert" : "deassert", | |
(data & MSI_DATA_DELIVERY_LOWPRI) ? "lowpri" : "fixed", | |
data & MSI_DATA_VECTOR_MASK); | |
} | |
int main(int argc, char **argv) | |
{ | |
struct pci_access *pacc; | |
struct pci_filter filter; /* Device filter */ | |
struct pci_dev *p; | |
struct device *d; | |
char *msg; | |
u16 vendor; | |
u8 header_type; | |
int found = 0; | |
if (argc < 2) { | |
printf("more args required\n"); | |
return -1; | |
} | |
pacc = pci_alloc(); | |
pci_filter_init(pacc, &filter); | |
pci_init(pacc); | |
if (msg = pci_filter_parse_slot(&filter, argv[1])) { | |
printf("pci_filter_parse_slot %s\n", msg); | |
return -1; | |
} | |
pci_scan_bus(pacc); | |
for (p = pacc->devices; p; p = p->next) { | |
if (!pci_filter_match(&filter, p)) | |
continue; | |
else { | |
found = 1; | |
break; | |
} | |
} | |
if (!found) { | |
printf("device not found\n"); | |
return -1; | |
} | |
d = malloc(sizeof(struct device)); | |
bzero(d, sizeof(*d)); | |
d->dev = p; | |
if (!pci_read_block(p, 0, d->config, 64)) { | |
printf("Unable to read 64 bytes of configuration space."); | |
return -1; | |
} | |
d->config_cnt = 64; | |
pci_setup_cache(p, d->config, d->config_cnt); | |
pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); | |
int where = get_conf_byte(d, PCI_CAPABILITY_LIST) & ~3; | |
while (where) | |
{ | |
int id, next, cap; | |
if (!pci_read_block(d->dev, where, d->config + where, 4)) { | |
printf("Unable to read 4 bytes of configuration space."); | |
return -1; | |
} | |
id = get_conf_byte(d, where + PCI_CAP_LIST_ID); | |
next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT) & ~3; | |
cap = get_conf_word(d, where + PCI_CAP_FLAGS); | |
if (id == 0xff) | |
{ | |
printf("cap chain broken\n"); | |
break; | |
} | |
if (id == PCI_CAP_ID_MSI) | |
show_msi(d, where, cap); | |
where = next; | |
} | |
pci_cleanup(pacc); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
need to be built inside pciutils package
replace "#include <pci/pci.h>" to "#include "lib/pci.h"" in msireg.c file
updated Makefile as below
The example of use of libpci
example$(EXEEXT): example.o lib/$(PCIIMPLIB)
example.o: example.c $(PCIINC)
msireg$(EXEEXT): msireg.o lib/$(PCIIMPLIB)
msireg.o: msireg.c $(PCIINC)