diff options
author | scottl <scottl@FreeBSD.org> | 2003-09-14 19:30:00 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2003-09-14 19:30:00 +0000 |
commit | 0ef16e15fc4e3586c3d2f2b4bd3a5b454cbd52fa (patch) | |
tree | 8a08fc4815fbb424ae0e825350ac89b61fd15e89 /sys | |
parent | 4b89f38d2e819883e012f22dbe91bb83bdc2081b (diff) | |
download | FreeBSD-src-0ef16e15fc4e3586c3d2f2b4bd3a5b454cbd52fa.zip FreeBSD-src-0ef16e15fc4e3586c3d2f2b4bd3a5b454cbd52fa.tar.gz |
Teach the PCI code to parse MSI extended capabilities. Re-arrange the
pcicfg struct a bit to hold extcap structures instead of structure members.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/pci.c | 54 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 2 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 22 |
3 files changed, 55 insertions, 23 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7991b39..a4e1a54 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -431,14 +431,22 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg) /* Process this entry */ switch (REG(ptr, 1)) { case PCIY_PMG: /* PCI power management */ - if (cfg->pp_cap == 0) { - cfg->pp_cap = REG(ptr + PCIR_POWER_CAP, 2); - cfg->pp_status = ptr + PCIR_POWER_STATUS; - cfg->pp_pmcsr = ptr + PCIR_POWER_PMCSR; + if (cfg->pp.pp_cap == 0) { + cfg->pp.pp_cap = REG(ptr + PCIR_POWER_CAP, 2); + cfg->pp.pp_status = ptr + PCIR_POWER_STATUS; + cfg->pp.pp_pmcsr = ptr + PCIR_POWER_PMCSR; if ((nextptr - ptr) > PCIR_POWER_DATA) - cfg->pp_data = ptr + PCIR_POWER_DATA; + cfg->pp.pp_data = ptr + PCIR_POWER_DATA; } break; + case PCIY_MSI: /* PCI MSI */ + cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2); + if (cfg->msi.msi_ctrl & PCIM_MSICTRL_64BIT) + cfg->msi.msi_data = PCIR_MSI_DATA_64BIT; + else + cfg->msi.msi_data = PCIR_MSI_DATA; + cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl & + PCIM_MSICTRL_MMC_MASK)>>1); default: break; } @@ -477,22 +485,23 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) uint16_t status; int result; - if (cfg->pp_cap != 0) { - status = PCI_READ_CONFIG(dev, child, cfg->pp_status, 2) & ~PCIM_PSTAT_DMASK; + if (cfg->pp.pp_cap != 0) { + status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2) + & ~PCIM_PSTAT_DMASK; result = 0; switch (state) { case PCI_POWERSTATE_D0: status |= PCIM_PSTAT_D0; break; case PCI_POWERSTATE_D1: - if (cfg->pp_cap & PCIM_PCAP_D1SUPP) { + if (cfg->pp.pp_cap & PCIM_PCAP_D1SUPP) { status |= PCIM_PSTAT_D1; } else { result = EOPNOTSUPP; } break; case PCI_POWERSTATE_D2: - if (cfg->pp_cap & PCIM_PCAP_D2SUPP) { + if (cfg->pp.pp_cap & PCIM_PCAP_D2SUPP) { status |= PCIM_PSTAT_D2; } else { result = EOPNOTSUPP; @@ -505,7 +514,8 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) result = EINVAL; } if (result == 0) - PCI_WRITE_CONFIG(dev, child, cfg->pp_status, status, 2); + PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_status, status, + 2); } else { result = ENXIO; } @@ -520,8 +530,8 @@ pci_get_powerstate_method(device_t dev, device_t child) uint16_t status; int result; - if (cfg->pp_cap != 0) { - status = PCI_READ_CONFIG(dev, child, cfg->pp_status, 2); + if (cfg->pp.pp_cap != 0) { + status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2); switch (status & PCIM_PSTAT_DMASK) { case PCIM_PSTAT_D0: result = PCI_POWERSTATE_D0; @@ -671,16 +681,26 @@ pci_print_verbose(struct pci_devinfo *dinfo) if (cfg->intpin > 0) printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); - if (cfg->pp_cap) { + if (cfg->pp.pp_cap) { uint16_t status; - status = pci_read_config(cfg->dev, cfg->pp_status, 2); + status = pci_read_config(cfg->dev, cfg->pp.pp_status, 2); printf("\tpowerspec %d supports D0%s%s D3 current D%d\n", - cfg->pp_cap & PCIM_PCAP_SPEC, - cfg->pp_cap & PCIM_PCAP_D1SUPP ? " D1" : "", - cfg->pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "", + cfg->pp.pp_cap & PCIM_PCAP_SPEC, + cfg->pp.pp_cap & PCIM_PCAP_D1SUPP ? " D1" : "", + cfg->pp.pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "", status & PCIM_PSTAT_DMASK); } + if (cfg->msi.msi_data) { + int ctrl; + + ctrl = cfg->msi.msi_ctrl; + printf("\tMSI supports %d message%s%s%s\n", + cfg->msi.msi_msgnum, + (cfg->msi.msi_msgnum == 1) ? "" : "s", + (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", + (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks":""); + } } } diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 25c8f08..9f0f612 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -349,7 +349,7 @@ #define PCIR_MSI_ADDR 0x4 #define PCIR_MSI_ADDR_HIGH 0x8 #define PCIR_MSI_DATA 0x8 -#define PCIR_MSI_DATA_HIGH 0xc +#define PCIR_MSI_DATA_64BIT 0xc #define PCIR_MSI_MASK 0x10 #define PCIR_MSI_PENDING 0x14 diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index de084f6..ef24d89 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -51,6 +51,21 @@ typedef uint64_t pci_addr_t; /* uint64_t for system with 64bit addresses */ typedef uint32_t pci_addr_t; /* uint64_t for system with 64bit addresses */ #endif +/* Interesting values for PCI power management */ +struct pcicfg_pp { + uint16_t pp_cap; /* PCI power management capabilities */ + uint8_t pp_status; /* config space address of PCI power status reg */ + uint8_t pp_pmcsr; /* config space address of PMCSR reg */ + uint8_t pp_data; /* config space address of PCI power data reg */ +}; + +/* Interesting values for PCI MSI */ +struct pcicfg_msi { + uint16_t msi_ctrl; /* Message Control */ + uint8_t msi_msgnum; /* Number of messages */ + uint16_t msi_data; /* Location of MSI data word */ +}; + /* config header information common to all header types */ typedef struct pcicfg { @@ -85,11 +100,8 @@ typedef struct pcicfg { uint8_t slot; /* config space slot address */ uint8_t func; /* config space function number */ - uint16_t pp_cap; /* PCI power management capabilities */ - uint8_t pp_status; /* config space address of PCI power status reg */ - uint8_t pp_pmcsr; /* config space address of PMCSR reg */ - uint8_t pp_data; /* config space address of PCI power data reg */ - + struct pcicfg_pp pp; /* pci power management */ + struct pcicfg_msi msi; /* pci msi */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ |