summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/device/pciexp_device.c108
-rw-r--r--src/include/device/pci.h2
-rw-r--r--src/include/device/pci_def.h4
-rw-r--r--src/soc/intel/broadwell/pch/pcie.c10
-rw-r--r--src/soc/intel/common/block/pcie/pcie.c10
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,
};