From: Stanislav Spassov <stanspas@amazon.com>
To: <linux-pci@vger.kernel.org>
Cc: "Stanislav Spassov" <stanspas@amazon.de>,
linux-acpi@vger.kernel.org, "Bjorn Helgaas" <bhelgaas@google.com>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Jan H . Schönherr" <jschoenh@amazon.de>,
"Jonathan Corbet" <corbet@lwn.net>,
"Ashok Raj" <ashok.raj@intel.com>,
"Alex Williamson" <alex.williamson@redhat.com>,
"Sinan Kaya" <okaya@kernel.org>,
"Rajat Jain" <rajatja@google.com>,
"kbuild test robot" <lkp@intel.com>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
linux-pm@vger.kernel.org, "Len Brown" <lenb@kernel.org>,
"Pavel Machek" <pavel@ucw.cz>, "Ingo Molnar" <mingo@redhat.com>,
"Borislav Petkov" <bp@alien8.de>,
x86@kernel.org,
"Srinivas Pandruvada" <srinivas.pandruvada@linux.intel.com>,
"Jiri Kosina" <jikos@kernel.org>,
"Benjamin Tissoires" <benjamin.tissoires@redhat.com>,
"Lee Jones" <lee.jones@linaro.org>,
"Mirko Lindner" <mlindner@marvell.com>,
"Stephen Hemminger" <stephen@networkplumber.org>,
"David S. Miller" <davem@davemloft.net>
Subject: [PATCH v3 08/17] PCI: Add more delay overrides to struct pci_dev
Date: Tue, 3 Mar 2020 14:28:43 +0100 [thread overview]
Message-ID: <20200303132852.13184-9-stanspas@amazon.com> (raw)
In-Reply-To: <20200303132852.13184-1-stanspas@amazon.com>
From: Stanislav Spassov <stanspas@amazon.de>
Almost all of the PCI_*_DELAY constants declared in drivers/pci/pci.h
can be overridden on a per-device basis, as explained in the constants'
comments. To allow storing per-device values, this patch introduces
a type to describe the various "initialization events":
enum pci_init_event
and an array in struct pci_dev, with an override for each event.
This array is initially populated with the PCI_*_DELAY constants,
but can be later overridden by pci_acpi_optimize_delay. Quirks and
drivers may also end up tweaking the values.
The new array replaces two previous members: d3_delay and d3cold_delay
Direct mentions of PCI_*_DELAY are replaced with the per-device
override where applicable.
Signed-off-by: Stanislav Spassov <stanspas@amazon.de>
---
Documentation/power/pci.rst | 4 ++-
arch/x86/pci/intel_mid_pci.c | 2 +-
drivers/hid/intel-ish-hid/ipc/ipc.c | 2 +-
drivers/mfd/intel-lpss-pci.c | 2 +-
drivers/net/ethernet/marvell/sky2.c | 2 +-
drivers/pci/iov.c | 4 +--
drivers/pci/pci-acpi.c | 42 ++++++++++++++++-------------
drivers/pci/pci.c | 36 ++++++++++++++++++-------
drivers/pci/quirks.c | 9 ++++---
include/linux/pci.h | 35 ++++++++++++++++++++++--
10 files changed, 97 insertions(+), 41 deletions(-)
diff --git a/Documentation/power/pci.rst b/Documentation/power/pci.rst
index 0924d29636ad..8136c8a4b150 100644
--- a/Documentation/power/pci.rst
+++ b/Documentation/power/pci.rst
@@ -320,7 +320,9 @@ that these callbacks operate on::
unsigned int d2_support:1; /* Low power state D2 is supported */
unsigned int no_d1d2:1; /* D1 and D2 are forbidden */
unsigned int wakeup_prepared:1; /* Device prepared for wake up */
- unsigned int d3_delay; /* D3->D0 transition time in ms */
+ unsigned int delay[PCI_INIT_EVENT_COUNT]; /* minimum waiting time
+ after various events
+ in ms */
...
};
diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c
index 00c62115f39c..b42b14cd0e00 100644
--- a/arch/x86/pci/intel_mid_pci.c
+++ b/arch/x86/pci/intel_mid_pci.c
@@ -322,7 +322,7 @@ static void pci_d3delay_fixup(struct pci_dev *dev)
*/
if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
return;
- dev->d3_delay = 0;
+ dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] = 0;
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
index 8f8dfdf64833..a209b954fbe8 100644
--- a/drivers/hid/intel-ish-hid/ipc/ipc.c
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -755,7 +755,7 @@ static int _ish_hw_reset(struct ishtp_device *dev)
csr |= PCI_D3hot;
pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
- mdelay(pdev->d3_delay);
+ mdelay(pdev->delay[PCI_INIT_EVENT_D3HOT_TO_D0]);
csr &= ~PCI_PM_CTRL_STATE_MASK;
csr |= PCI_D0;
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index c40a6c7d0cf8..5b9e458d0ab1 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -35,7 +35,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
info->mem = &pdev->resource[0];
info->irq = pdev->irq;
- pdev->d3cold_delay = 0;
+ pdev->delay[PCI_INIT_EVENT_RESET] = 0;
/* Probably it is enough to set this for iDMA capable devices only */
pci_set_master(pdev);
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index ebfd0ceac884..f808562e389d 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -5100,7 +5100,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&hw->restart_work, sky2_restart);
pci_set_drvdata(pdev, hw);
- pdev->d3_delay = 300;
+ pdev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] = 300;
return 0;
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index d4e4a0c0a97f..f71fc28b69e6 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -524,7 +524,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
pci_cfg_access_lock(dev);
pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
- msleep(PCI_VF_ENABLE_DELAY);
+ msleep(dev->delay[PCI_INIT_EVENT_VF_ENABLE]);
pci_cfg_access_unlock(dev);
rc = sriov_add_vfs(dev, initial);
@@ -735,7 +735,7 @@ static void sriov_restore_state(struct pci_dev *dev)
pci_iov_set_numvfs(dev, iov->num_VFs);
pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
- msleep(PCI_VF_ENABLE_DELAY);
+ msleep(dev->delay[PCI_INIT_EVENT_VF_ENABLE]);
}
/**
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 0ece144ac9c5..5b95785c5bb5 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1177,11 +1177,11 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
}
/**
- * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
- * @pdev: the PCI device whose delay is to be updated
+ * pci_acpi_optimize_delay - optimize PCI readiness delays from ACPI
+ * @pdev: the PCI device whose delays are to be updated
* @handle: ACPI handle of this device
*
- * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM
+ * Update the readiness delays of a PCI device from the ACPI _DSM
* Function 9 of the device, and cache the parent host bridge's flag for
* ignoring reset delay upon Sx Resume (the flag is originally set in
* acpi_pci_add_bus through _DSM Function 8).
@@ -1226,6 +1226,7 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
u64 value_us;
int value;
union acpi_object *obj, *elements;
+ int i;
pdev->ignore_reset_delay_on_sx_resume =
bridge->ignore_reset_delay_on_sx_resume;
@@ -1237,21 +1238,26 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
elements = obj->package.elements;
- if (elements[0].type == ACPI_TYPE_INTEGER) {
- value_us = elements[0].integer.value;
- value = (int)value_us / 1000;
- if ((int)value_us % 1000 > 0)
- value++;
- if (value < PCI_RESET_DELAY)
- pdev->d3cold_delay = value;
- }
- if (elements[3].type == ACPI_TYPE_INTEGER) {
- value_us = elements[3].integer.value;
- value = (int)value_us / 1000;
- if ((int)value_us % 1000 > 0)
- value++;
- if (value < PCI_PM_D3HOT_DELAY)
- pdev->d3_delay = value;
+ for (i = 0; i < 5; i++) {
+ if (elements[i].type == ACPI_TYPE_INTEGER) {
+ value_us = elements[i].integer.value;
+ value = (int)value_us / 1000;
+ if ((int)value_us % 1000 > 0)
+ value++;
+ /*
+ * XXX This relies on the initial values in the
+ * delay array being set using the PCI_*_DELAY
+ * macros in drivers/pci/pci.h
+ * Once the kernel has support for Readiness
+ * Time Reporting Extended Capability, this
+ * needs fixing to honor prioritization of
+ * overrides. Also, a flag would need to be
+ * set to disable the use of Readiness
+ * Notifications at some point.
+ */
+ if (value < pdev->delay[i])
+ pdev->delay[i] = value;
+ }
}
}
ACPI_FREE(obj);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index aaef00578487..ba54164652cc 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -43,6 +43,15 @@ const char *pci_power_names[] = {
};
EXPORT_SYMBOL_GPL(pci_power_names);
+const char *pci_init_event_names[] = {
+ [PCI_INIT_EVENT_RESET] = "conventional reset",
+ [PCI_INIT_EVENT_DL_UP] = "DL Up",
+ [PCI_INIT_EVENT_FLR] = "FLR",
+ [PCI_INIT_EVENT_D3HOT_TO_D0] = "PM D3hot->D0",
+ [PCI_INIT_EVENT_VF_ENABLE] = "VF Enable",
+};
+EXPORT_SYMBOL_GPL(pci_init_event_names);
+
int isa_dma_bridge_buggy;
EXPORT_SYMBOL(isa_dma_bridge_buggy);
@@ -66,7 +75,7 @@ struct pci_pme_device {
static void pci_dev_d3_sleep(struct pci_dev *dev)
{
- unsigned int delay = dev->d3_delay;
+ unsigned int delay = dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0];
if (delay < pci_pm_d3_delay)
delay = pci_pm_d3_delay;
@@ -2844,8 +2853,11 @@ void pci_pm_init(struct pci_dev *dev)
dev->pm_cap = pm;
dev->ignore_reset_delay_on_sx_resume = 0;
- dev->d3_delay = PCI_PM_D3HOT_DELAY;
- dev->d3cold_delay = PCI_RESET_DELAY;
+ dev->delay[PCI_INIT_EVENT_RESET] = PCI_RESET_DELAY;
+ dev->delay[PCI_INIT_EVENT_DL_UP] = PCI_DL_UP_DELAY;
+ dev->delay[PCI_INIT_EVENT_FLR] = PCI_FLR_DELAY;
+ dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] = PCI_PM_D3HOT_DELAY;
+ dev->delay[PCI_INIT_EVENT_VF_ENABLE] = PCI_VF_ENABLE_DELAY;
dev->bridge_d3 = pci_bridge_d3_possible(dev);
dev->d3cold_allowed = true;
@@ -4500,7 +4512,7 @@ int pcie_flr(struct pci_dev *dev)
if (dev->imm_ready)
return 0;
- msleep(PCI_FLR_DELAY);
+ msleep(dev->delay[PCI_INIT_EVENT_FLR]);
return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
}
@@ -4539,7 +4551,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
if (dev->imm_ready)
return 0;
- msleep(PCI_FLR_DELAY);
+ msleep(dev->delay[PCI_INIT_EVENT_FLR]);
return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
}
@@ -4556,7 +4568,9 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
*
* NOTE: This causes the caller to sleep for twice the device power transition
* cooldown period, which for the D0->D3hot and D3hot->D0 transitions is 10 ms
- * by default (i.e. unless the @dev's d3_delay field has a different value).
+ * by default (i.e. unless the @dev's delay[PCI_INIT_EVENT_D3HOT_TO_D0] field
+ * has a different value).
+ *
* Moreover, only devices in D0 can be reset by this function.
*/
static int pci_pm_reset(struct pci_dev *dev, int probe)
@@ -4666,12 +4680,14 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus)
const struct pci_dev *pdev;
int min_delay = 100;
int max_delay = 0;
+ int delay;
list_for_each_entry(pdev, &bus->devices, bus_list) {
- if (pdev->d3cold_delay < min_delay)
- min_delay = pdev->d3cold_delay;
- if (pdev->d3cold_delay > max_delay)
- max_delay = pdev->d3cold_delay;
+ delay = pdev->delay[PCI_INIT_EVENT_RESET];
+ if (delay < min_delay)
+ min_delay = delay;
+ if (delay > max_delay)
+ max_delay = delay;
}
return max(min_delay, max_delay);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 29f473ebf20f..12f22af0cbef 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1873,12 +1873,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
static void quirk_d3hot_delay(struct pci_dev *dev, unsigned int delay)
{
- if (dev->d3_delay >= delay)
+
+ if (dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] >= delay)
return;
- dev->d3_delay = delay;
+ dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] = delay;
pci_info(dev, "extending delay after power-on from D3hot to %d msec\n",
- dev->d3_delay);
+ dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0]);
}
static void quirk_radeon_pm(struct pci_dev *dev)
@@ -3310,7 +3311,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
*/
static void quirk_remove_d3_delay(struct pci_dev *dev)
{
- dev->d3_delay = 0;
+ dev->delay[PCI_INIT_EVENT_D3HOT_TO_D0] = 0;
}
/* C600 Series devices do not need 10ms d3_delay */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3_delay);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 22a5b7164c32..16dbfff2092e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -268,6 +268,36 @@ enum pci_bus_speed {
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev);
enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev);
+/*
+ * The first five constants correspond to delays specified in both:
+ * PCI Firmware Specification Rev. 3.2 (January 26, 2015),
+ * Section 4.6.9. "_DSM for Specifying Device Readiness Durations", and
+ * PCI Express Base Specification Revision 5.0 Version 1.0 (May 22, 2019)
+ * Section 7.9.17 "Readiness Time Reporting Extended Capability"
+ *
+ * The code assumes these constants are in the same order as in the
+ * PCI Firmware Specification.
+ */
+enum pci_init_event {
+ PCI_INIT_EVENT_RESET = 0, /* D3cold->D0, SBR */
+ PCI_INIT_EVENT_DL_UP = 1,
+ PCI_INIT_EVENT_FLR = 2,
+ PCI_INIT_EVENT_D3HOT_TO_D0 = 3,
+ PCI_INIT_EVENT_VF_ENABLE = 4,
+ PCI_INIT_EVENT_COUNT /* Keep this as last element */
+};
+
+/* Remember to update this when the list above changes! */
+extern const char *pci_init_event_names[];
+
+static inline const char *pci_init_event_name(enum pci_init_event event)
+{
+ if (event >= PCI_INIT_EVENT_COUNT)
+ return "<unknown>";
+ else
+ return pci_init_event_names[event];
+}
+
struct pci_cap_saved_data {
u16 cap_nr;
bool cap_extended;
@@ -356,8 +386,9 @@ struct pci_dev {
bit manually */
unsigned int ignore_reset_delay_on_sx_resume:1; /* Cached value from
pci_host_bridge */
- unsigned int d3_delay; /* D3->D0 transition time in ms */
- unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
+ unsigned int delay[PCI_INIT_EVENT_COUNT]; /* minimum waiting time
+ after various events
+ in ms */
#ifdef CONFIG_PCIEASPM
struct pcie_link_state *link_state; /* ASPM link state */
--
2.25.1
Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879
next prev parent reply other threads:[~2020-03-03 13:30 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-03 13:28 [PATCH v3 00/17] Improve PCI device post-reset readiness polling Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 01/17] PCI: Fall back to slot/bus reset if softer methods timeout Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 02/17] PCI: Remove unused PCI_PM_BUS_WAIT Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 03/17] PCI: Use pci_bridge_wait_for_secondary_bus after SBR Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 04/17] PCI: Do not override delay for D0->D3hot transition Stanislav Spassov
2020-03-03 18:57 ` Rafael J. Wysocki
2020-03-07 10:58 ` Spassov, Stanislav
2020-03-03 13:28 ` [PATCH v3 05/17] PCI: Fix handling of _DSM 8 (avoiding reset delays) Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 06/17] PCI: Fix us->ms conversion in pci_acpi_optimize_delay Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 07/17] PCI: Clean up and document PM/reset delays Stanislav Spassov
2020-03-03 19:03 ` Rafael J. Wysocki
2020-03-07 11:30 ` Spassov, Stanislav
2020-03-03 13:28 ` Stanislav Spassov [this message]
2020-03-03 13:28 ` [PATCH v3 09/17] PCI: Generalize pci_bus_max_d3cold_delay to pci_bus_max_delay Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 10/17] PCI: Use correct delay in pci_bridge_wait_for_secondary_bus Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 11/17] PCI: Refactor pci_dev_wait to remove timeout parameter Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 12/17] PCI: Refactor pci_dev_wait to take pci_init_event Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 13/17] PCI: Cache CRS Software Visibiliy in struct pci_dev Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 14/17] PCI: Introduce per-device reset_ready_poll override Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 15/17] PCI: Refactor polling loop out of pci_dev_wait Stanislav Spassov
2020-03-03 13:28 ` [PATCH v3 16/17] PCI: Add CRS handling to pci_dev_wait() Stanislav Spassov
2020-03-05 17:56 ` Raj, Ashok
2020-03-06 18:07 ` Spassov, Stanislav
2020-03-03 13:28 ` [PATCH v3 17/17] PCI: Lower PCIE_RESET_READY_POLL_MS from 1m to 1s Stanislav Spassov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200303132852.13184-9-stanspas@amazon.com \
--to=stanspas@amazon.com \
--cc=akpm@linux-foundation.org \
--cc=alex.williamson@redhat.com \
--cc=ashok.raj@intel.com \
--cc=benjamin.tissoires@redhat.com \
--cc=bhelgaas@google.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=jikos@kernel.org \
--cc=jschoenh@amazon.de \
--cc=lee.jones@linaro.org \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=lkp@intel.com \
--cc=mingo@redhat.com \
--cc=mlindner@marvell.com \
--cc=okaya@kernel.org \
--cc=pavel@ucw.cz \
--cc=rajatja@google.com \
--cc=rjw@rjwysocki.net \
--cc=srinivas.pandruvada@linux.intel.com \
--cc=stanspas@amazon.de \
--cc=stephen@networkplumber.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).