diff options
-rw-r--r-- | src/device/pciexp_device.c | 108 | ||||
-rw-r--r-- | src/include/device/pci.h | 2 | ||||
-rw-r--r-- | src/include/device/pci_def.h | 4 | ||||
-rw-r--r-- | src/soc/intel/broadwell/pch/pcie.c | 10 | ||||
-rw-r--r-- | src/soc/intel/common/block/pcie/pcie.c | 10 |
5 files changed, 82 insertions, 52 deletions
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c index 70f65144b6..d8ed5d9e3d 100644 --- a/src/device/pciexp_device.c +++ b/src/device/pciexp_device.c @@ -127,66 +127,92 @@ static void pciexp_enable_clock_power_pm(struct device *endp, unsigned int endp_ pci_write_config16(endp, endp_cap + PCI_EXP_LNKCTL, lnkctl); } -static void pciexp_config_max_latency(struct device *root, struct device *dev) +static bool _pciexp_ltr_supported(struct device *dev, unsigned int cap) { - unsigned int cap; - cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_LTR_ID); - if ((cap) && (root->ops->ops_pci != NULL) && - (root->ops->ops_pci->set_ltr_max_latencies != NULL)) - root->ops->ops_pci->set_ltr_max_latencies(dev, cap + 4); + return pci_read_config16(dev, cap + PCI_EXP_DEVCAP2) & PCI_EXP_DEVCAP2_LTR; } -static bool pciexp_is_ltr_supported(struct device *dev, unsigned int cap) +static bool _pciexp_ltr_enabled(struct device *dev, unsigned int cap) { - unsigned int val; + return pci_read_config16(dev, cap + PCI_EXP_DEVCTL2) & PCI_EXP_DEV2_LTR; +} - val = pci_read_config16(dev, cap + PCI_EXP_DEVCAP2); +static bool _pciexp_enable_ltr(struct device *parent, unsigned int parent_cap, + struct device *dev, unsigned int cap) +{ + if (!_pciexp_ltr_supported(dev, cap)) { + printk(BIOS_DEBUG, "%s: No LTR support\n", dev_path(dev)); + return false; + } - if (val & PCI_EXP_DEVCAP2_LTR) + if (_pciexp_ltr_enabled(dev, cap)) return true; - return false; + if (parent && + (parent->path.type != DEVICE_PATH_PCI || + !_pciexp_ltr_supported(parent, parent_cap) || + !_pciexp_ltr_enabled(parent, parent_cap))) + return false; + + pci_or_config16(dev, cap + PCI_EXP_DEVCTL2, PCI_EXP_DEV2_LTR); + printk(BIOS_INFO, "%s: Enabled LTR\n", dev_path(dev)); + return true; } -static void pciexp_configure_ltr(struct device *dev) +static void pciexp_enable_ltr(struct device *dev) { - unsigned int cap; - - cap = pci_find_capability(dev, PCI_CAP_ID_PCIE); + const unsigned int cap = pci_find_capability(dev, PCI_CAP_ID_PCIE); + if (!cap) + return; /* - * Check if capability pointer is valid and - * device supports LTR mechanism. + * If we have get_ltr_max_latencies(), treat `dev` as the root. + * If not, let _pciexp_enable_ltr() query the parent's state. */ - if (!cap || !pciexp_is_ltr_supported(dev, cap)) { - printk(BIOS_INFO, "Failed to enable LTR for dev = %s\n", - dev_path(dev)); - return; + struct device *parent = NULL; + unsigned int parent_cap = 0; + if (!dev->ops->ops_pci || !dev->ops->ops_pci->get_ltr_max_latencies) { + parent = dev->bus->dev; + parent_cap = pci_find_capability(dev, PCI_CAP_ID_PCIE); + if (!parent_cap) + return; } - cap += PCI_EXP_DEVCTL2; + (void)_pciexp_enable_ltr(parent, parent_cap, dev, cap); +} - /* Enable LTR for device */ - pci_update_config32(dev, cap, ~PCI_EXP_DEV2_LTR, PCI_EXP_DEV2_LTR); +static bool pciexp_get_ltr_max_latencies(struct device *dev, u16 *max_snoop, u16 *max_nosnoop) +{ + /* Walk the hierarchy up to find get_ltr_max_latencies(). */ + do { + if (dev->ops->ops_pci && dev->ops->ops_pci->get_ltr_max_latencies) + break; + if (dev->bus->dev == dev || dev->bus->dev->path.type != DEVICE_PATH_PCI) + return false; + dev = dev->bus->dev; + } while (true); - /* Configure Max Snoop Latency */ - pciexp_config_max_latency(dev->bus->dev, dev); + dev->ops->ops_pci->get_ltr_max_latencies(max_snoop, max_nosnoop); + return true; } -static void pciexp_enable_ltr(struct device *dev) +static void pciexp_configure_ltr(struct device *parent, unsigned int parent_cap, + struct device *dev, unsigned int cap) { - struct bus *bus; - struct device *child; + if (!_pciexp_enable_ltr(parent, parent_cap, dev, cap)) + return; - for (bus = dev->link_list ; bus ; bus = bus->next) { - for (child = bus->children; child; child = child->sibling) { - if (child->path.type != DEVICE_PATH_PCI) - continue; - pciexp_configure_ltr(child); - if (child->ops && child->ops->scan_bus) - pciexp_enable_ltr(child); - } - } + const unsigned int ltr_cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_LTR_ID); + if (!ltr_cap) + return; + + u16 max_snoop, max_nosnoop; + if (!pciexp_get_ltr_max_latencies(dev, &max_snoop, &max_nosnoop)) + return; + + pci_write_config16(dev, ltr_cap + PCI_LTR_MAX_SNOOP, max_snoop); + pci_write_config16(dev, ltr_cap + PCI_LTR_MAX_NOSNOOP, max_nosnoop); + printk(BIOS_INFO, "%s: Programmed LTR max latencies\n", dev_path(dev)); } static unsigned char pciexp_L1_substate_cal(struct device *dev, unsigned int endp_cap, @@ -471,12 +497,17 @@ static void pciexp_tune_dev(struct device *dev) /* Adjust Max_Payload_Size of link ends. */ pciexp_set_max_payload_size(root, root_cap, dev, cap); + + pciexp_configure_ltr(root, root_cap, dev, cap); } void pciexp_scan_bus(struct bus *bus, unsigned int min_devfn, unsigned int max_devfn) { struct device *child; + + pciexp_enable_ltr(bus->dev); + pci_scan_bus(bus, min_devfn, max_devfn); for (child = bus->children; child; child = child->sibling) { @@ -493,7 +524,6 @@ void pciexp_scan_bus(struct bus *bus, unsigned int min_devfn, void pciexp_scan_bridge(struct device *dev) { do_pci_scan_bridge(dev, pciexp_scan_bus); - pciexp_enable_ltr(dev); } /** Default device operations for PCI Express bridges */ diff --git a/src/include/device/pci.h b/src/include/device/pci.h index e80cb22907..db7cc69c8d 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -31,7 +31,7 @@ struct pci_operations { /* set the Subsystem IDs for the PCI device */ void (*set_subsystem)(struct device *dev, unsigned int vendor, unsigned int device); - void (*set_ltr_max_latencies)(struct device *dev, unsigned int off); + void (*get_ltr_max_latencies)(u16 *max_snoop, u16 *max_nosnoop); }; struct pci_driver { diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index b0558fa67e..d18e750520 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -518,6 +518,10 @@ #define PCI_PWR_CAP 12 /* Capability */ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ +/* Latency Tolerance Reporting */ +#define PCI_LTR_MAX_SNOOP 4 +#define PCI_LTR_MAX_NOSNOOP 6 + /* * The PCI interface treats multi-function devices as independent * devices. The slot/function address of each device is encoded diff --git a/src/soc/intel/broadwell/pch/pcie.c b/src/soc/intel/broadwell/pch/pcie.c index 05619f8023..26fde0bfb2 100644 --- a/src/soc/intel/broadwell/pch/pcie.c +++ b/src/soc/intel/broadwell/pch/pcie.c @@ -609,17 +609,15 @@ static void pch_pcie_enable(struct device *dev) root_port_commit_config(); } -static void pcie_set_ltr_max_latencies(struct device *dev, unsigned int off) +static void pcie_get_ltr_max_latencies(u16 *max_snoop, u16 *max_nosnoop) { - /* Set max snoop and non-snoop latency for Broadwell */ - pci_write_config32(dev, off, - PCIE_LTR_MAX_NO_SNOOP_LATENCY_3146US << 16 | - PCIE_LTR_MAX_SNOOP_LATENCY_3146US); + *max_snoop = PCIE_LTR_MAX_SNOOP_LATENCY_3146US; + *max_nosnoop = PCIE_LTR_MAX_NO_SNOOP_LATENCY_3146US; } static struct pci_operations pcie_ops = { .set_subsystem = pci_dev_set_subsystem, - .set_ltr_max_latencies = pcie_set_ltr_max_latencies, + .get_ltr_max_latencies = pcie_get_ltr_max_latencies, }; static struct device_operations device_ops = { diff --git a/src/soc/intel/common/block/pcie/pcie.c b/src/soc/intel/common/block/pcie/pcie.c index 346c0ff225..f7f0902ab7 100644 --- a/src/soc/intel/common/block/pcie/pcie.c +++ b/src/soc/intel/common/block/pcie/pcie.c @@ -45,16 +45,14 @@ static void pch_pcie_init(struct device *dev) pci_write_config16(dev, PCI_SEC_STATUS, reg16); } -static void pcie_set_ltr_max_latencies(struct device *dev, unsigned int offset) +static void pcie_get_ltr_max_latencies(u16 *max_snoop, u16 *max_nosnoop) { - /* Set max snoop and non-snoop latency for the SOC */ - pci_write_config32(dev, offset, - PCIE_LTR_MAX_NO_SNOOP_LATENCY_3146US << 16 | - PCIE_LTR_MAX_SNOOP_LATENCY_3146US); + *max_snoop = PCIE_LTR_MAX_SNOOP_LATENCY_3146US; + *max_nosnoop = PCIE_LTR_MAX_NO_SNOOP_LATENCY_3146US; } static struct pci_operations pcie_ops = { - .set_ltr_max_latencies = pcie_set_ltr_max_latencies, + .get_ltr_max_latencies = pcie_get_ltr_max_latencies, .set_subsystem = pci_dev_set_subsystem, }; |