Expand the set of APIs available for locating PCI capabilities:

- pci_find_extcap() is repurposed to be used for fetching PCI-express
  extended capabilities (PCIZ_* constants in <dev/pci/pcireg.h>).
- pci_find_htcap() can be used to locate a specific HyperTransport
  capability (PCIM_HTCAP_* constants in <dev/pci/pcireg.h>).
- Cache the starting location of the PCI-express capability for PCI-express
  devices in PCI device ivars.
This commit is contained in:
jhb 2012-03-03 18:08:57 +00:00
parent 5794e3ef03
commit db63f69541
7 changed files with 181 additions and 7 deletions

View File

@ -196,6 +196,14 @@ pci_hostb_assign_interrupt(device_t dev, device_t child)
return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
}
static int
pci_hostb_find_cap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_cap(dev, capability, capreg));
}
static int
pci_hostb_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
@ -204,6 +212,14 @@ pci_hostb_find_extcap(device_t dev, device_t child, int capability,
return (pci_find_extcap(dev, capability, capreg));
}
static int
pci_hostb_find_htcap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_htcap(dev, capability, capreg));
}
static device_method_t pci_hostb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pci_hostb_probe),
@ -233,7 +249,9 @@ static device_method_t pci_hostb_methods[] = {
DEVMETHOD(pci_get_powerstate, pci_hostb_get_powerstate),
DEVMETHOD(pci_set_powerstate, pci_hostb_set_powerstate),
DEVMETHOD(pci_assign_interrupt, pci_hostb_assign_interrupt),
DEVMETHOD(pci_find_cap, pci_hostb_find_cap),
DEVMETHOD(pci_find_extcap, pci_hostb_find_extcap),
DEVMETHOD(pci_find_htcap, pci_hostb_find_htcap),
{ 0, 0 }
};

View File

@ -177,7 +177,9 @@ static device_method_t pci_methods[] = {
DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method),
DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method),
DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
DEVMETHOD(pci_find_cap, pci_find_cap_method),
DEVMETHOD(pci_find_extcap, pci_find_extcap_method),
DEVMETHOD(pci_find_htcap, pci_find_htcap_method),
DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method),
DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method),
DEVMETHOD(pci_remap_msix, pci_remap_msix_method),
@ -737,6 +739,9 @@ pci_read_cap(device_t pcib, pcicfgregs *cfg)
* at least one PCI-express device.
*/
pcie_chipset = 1;
cfg->pcie.pcie_location = ptr;
val = REG(ptr + PCIR_EXPRESS_FLAGS, 2);
cfg->pcie.pcie_type = val & PCIM_EXP_FLAGS_TYPE;
break;
default:
break;
@ -1154,12 +1159,55 @@ pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw,
}
/*
* Find the requested extended capability and return the offset in
* configuration space via the pointer provided. The function returns
* 0 on success and error code otherwise.
* Find the requested HyperTransport capability and return the offset
* in configuration space via the pointer provided. The function
* returns 0 on success and an error code otherwise.
*/
int
pci_find_extcap_method(device_t dev, device_t child, int capability,
pci_find_htcap_method(device_t dev, device_t child, int capability, int *capreg)
{
int ptr, error;
uint16_t val;
error = pci_find_cap(child, PCIY_HT, &ptr);
if (error)
return (error);
/*
* Traverse the capabilities list checking each HT capability
* to see if it matches the requested HT capability.
*/
while (ptr != 0) {
val = pci_read_config(child, ptr + PCIR_HT_COMMAND, 2);
if (capability == PCIM_HTCAP_SLAVE ||
capability == PCIM_HTCAP_HOST)
val &= 0xe000;
else
val &= PCIM_HTCMD_CAP_MASK;
if (val == capability) {
if (capreg != NULL)
*capreg = ptr;
return (0);
}
/* Skip to the next HT capability. */
while (ptr != 0) {
ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
if (pci_read_config(child, ptr + PCICAP_ID, 1) ==
PCIY_HT)
break;
}
}
return (ENOENT);
}
/*
* Find the requested capability and return the offset in
* configuration space via the pointer provided. The function returns
* 0 on success and an error code otherwise.
*/
int
pci_find_cap_method(device_t dev, device_t child, int capability,
int *capreg)
{
struct pci_devinfo *dinfo = device_get_ivars(child);
@ -1206,6 +1254,43 @@ pci_find_extcap_method(device_t dev, device_t child, int capability,
return (ENOENT);
}
/*
* Find the requested extended capability and return the offset in
* configuration space via the pointer provided. The function returns
* 0 on success and an error code otherwise.
*/
int
pci_find_extcap_method(device_t dev, device_t child, int capability,
int *capreg)
{
struct pci_devinfo *dinfo = device_get_ivars(child);
pcicfgregs *cfg = &dinfo->cfg;
uint32_t ecap;
uint16_t ptr;
/* Only supported for PCI-express devices. */
if (cfg->pcie.pcie_location == 0)
return (ENXIO);
ptr = PCIR_EXTCAP;
ecap = pci_read_config(child, ptr, 4);
if (ecap == 0xffffffff || ecap == 0)
return (ENOENT);
for (;;) {
if (PCI_EXTCAP_ID(ecap) == capability) {
if (capreg != NULL)
*capreg = ptr;
return (0);
}
ptr = PCI_EXTCAP_NEXTPTR(ecap);
if (ptr == 0)
break;
ecap = pci_read_config(child, ptr, 4);
}
return (ENOENT);
}
/*
* Support for MSI-X message interrupts.
*/
@ -1696,10 +1781,12 @@ pci_ht_map_msi(device_t dev, uint64_t addr)
int
pci_get_max_read_req(device_t dev)
{
struct pci_devinfo *dinfo = device_get_ivars(dev);
int cap;
uint16_t val;
if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
cap = dinfo->cfg.pcie.pcie_location;
if (cap == 0)
return (0);
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
@ -1710,10 +1797,12 @@ pci_get_max_read_req(device_t dev)
int
pci_set_max_read_req(device_t dev, int size)
{
struct pci_devinfo *dinfo = device_get_ivars(dev);
int cap;
uint16_t val;
if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
cap = dinfo->cfg.pcie.pcie_location;
if (cap == 0)
return (0);
if (size < 128)
size = 128;

View File

@ -105,6 +105,13 @@ METHOD int assign_interrupt {
device_t child;
};
METHOD int find_cap {
device_t dev;
device_t child;
int capability;
int *capreg;
};
METHOD int find_extcap {
device_t dev;
device_t child;
@ -112,6 +119,13 @@ METHOD int find_extcap {
int *capreg;
};
METHOD int find_htcap {
device_t dev;
device_t child;
int capability;
int *capreg;
};
METHOD int alloc_msi {
device_t dev;
device_t child;

View File

@ -80,8 +80,12 @@ int pci_enable_busmaster_method(device_t dev, device_t child);
int pci_disable_busmaster_method(device_t dev, device_t child);
int pci_enable_io_method(device_t dev, device_t child, int space);
int pci_disable_io_method(device_t dev, device_t child, int space);
int pci_find_cap_method(device_t dev, device_t child,
int capability, int *capreg);
int pci_find_extcap_method(device_t dev, device_t child,
int capability, int *capreg);
int pci_find_htcap_method(device_t dev, device_t child,
int capability, int *capreg);
int pci_alloc_msi_method(device_t dev, device_t child, int *count);
int pci_alloc_msix_method(device_t dev, device_t child, int *count);
int pci_remap_msix_method(device_t dev, device_t child,

View File

@ -123,6 +123,12 @@ struct pcicfg_ht {
uint64_t ht_msiaddr; /* MSI mapping base address */
};
/* Interesting values for PCI-express */
struct pcicfg_pcie {
uint8_t pcie_location; /* Offset of PCI-e capability registers. */
uint8_t pcie_type; /* Device type. */
};
/* config header information common to all header types */
typedef struct pcicfg {
struct device *dev; /* device which owns this */
@ -164,6 +170,7 @@ typedef struct pcicfg {
struct pcicfg_msi msi; /* PCI MSI */
struct pcicfg_msix msix; /* PCI MSI-X */
struct pcicfg_ht ht; /* HyperTransport */
struct pcicfg_pcie pcie; /* PCI Express */
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */
@ -409,7 +416,7 @@ pci_get_powerstate(device_t dev)
static __inline int
pci_find_cap(device_t dev, int capability, int *capreg)
{
return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
return (PCI_FIND_CAP(device_get_parent(dev), dev, capability, capreg));
}
static __inline int
@ -418,6 +425,12 @@ pci_find_extcap(device_t dev, int capability, int *capreg)
return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
}
static __inline int
pci_find_htcap(device_t dev, int capability, int *capreg)
{
return (PCI_FIND_HTCAP(device_get_parent(dev), dev, capability, capreg));
}
static __inline int
pci_alloc_msi(device_t dev, int *count)
{

View File

@ -313,6 +313,14 @@ vga_pci_assign_interrupt(device_t dev, device_t child)
return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
}
static int
vga_pci_find_cap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_cap(dev, capability, capreg));
}
static int
vga_pci_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
@ -321,6 +329,14 @@ vga_pci_find_extcap(device_t dev, device_t child, int capability,
return (pci_find_extcap(dev, capability, capreg));
}
static int
vga_pci_find_htcap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_htcap(dev, capability, capreg));
}
static int
vga_pci_alloc_msi(device_t dev, device_t child, int *count)
{
@ -422,7 +438,9 @@ static device_method_t vga_pci_methods[] = {
DEVMETHOD(pci_get_powerstate, vga_pci_get_powerstate),
DEVMETHOD(pci_set_powerstate, vga_pci_set_powerstate),
DEVMETHOD(pci_assign_interrupt, vga_pci_assign_interrupt),
DEVMETHOD(pci_find_cap, vga_pci_find_cap),
DEVMETHOD(pci_find_extcap, vga_pci_find_extcap),
DEVMETHOD(pci_find_htcap, vga_pci_find_htcap),
DEVMETHOD(pci_alloc_msi, vga_pci_alloc_msi),
DEVMETHOD(pci_alloc_msix, vga_pci_alloc_msix),
DEVMETHOD(pci_remap_msix, vga_pci_remap_msix),

View File

@ -278,6 +278,14 @@ siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
}
static int
siba_bwn_find_cap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_cap(dev, capability, capreg));
}
static int
siba_bwn_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
@ -286,6 +294,14 @@ siba_bwn_find_extcap(device_t dev, device_t child, int capability,
return (pci_find_extcap(dev, capability, capreg));
}
static int
siba_bwn_find_htcap(device_t dev, device_t child, int capability,
int *capreg)
{
return (pci_find_htcap(dev, capability, capreg));
}
static int
siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
{
@ -405,7 +421,9 @@ static device_method_t siba_bwn_methods[] = {
DEVMETHOD(bus_teardown_intr, siba_bwn_teardown_intr),
/* PCI interface */
DEVMETHOD(pci_find_cap, siba_bwn_find_cap),
DEVMETHOD(pci_find_extcap, siba_bwn_find_extcap),
DEVMETHOD(pci_find_htcap, siba_bwn_find_htcap),
DEVMETHOD(pci_alloc_msi, siba_bwn_alloc_msi),
DEVMETHOD(pci_release_msi, siba_bwn_release_msi),
DEVMETHOD(pci_msi_count, siba_bwn_msi_count),