public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org
Cc: Justin Forbes <jmforbes@linuxtx.org>,
	Zwane Mwaikambo <zwane@arm.linux.org.uk>,
	"Theodore Ts'o" <tytso@mit.edu>,
	Randy Dunlap <rdunlap@xenotime.net>,
	Dave Jones <davej@redhat.com>,
	Chuck Wolber <chuckw@quantumlinux.com>,
	Chris Wedgwood <reviews@ml.cw.f00f.org>,
	Michael Krufky <mkrufky@linuxtv.org>,
	Chuck Ebbert <cebbert@redhat.com>,
	Domenico Andreoli <cavokz@gmail.com>, Willy Tarreau <w@1wt.eu>,
	Rodrigo Rubira Branco <rbranco@la.checkpoint.com>,
	Jake Edge <jake@lwn.net>, Eugene Teo <eteo@redhat.com>,
	torvalds@linux-foundation.org, akpm@linux-foundation.org,
	alan@lxorguk.ukuu.org.uk, Shaohua Li <shaohua.li@intel.com>,
	Jesse Barnes <jbarnes@virtuousgeek.org>
Subject: [patch 01/46] PCI: keep ASPM link state consistent throughout PCIe hierarchy
Date: Thu, 22 Jan 2009 17:11:26 -0800	[thread overview]
Message-ID: <20090123011126.GB19756@kroah.com> (raw)
In-Reply-To: <20090123011110.GA19756@kroah.com>

[-- Attachment #1: pci-keep-aspm-link-state-consistent-throughout-pcie-hierarchy.patch --]
[-- Type: text/plain, Size: 7500 bytes --]

2.6.28-stable review patch.  If anyone has any objections, please let us know.

------------------

From: Shaohua Li <shaohua.li@intel.com>

commit 46bbdfa44cfc0d352148a0dc33ba9f6db02ccdf0 upstream.

In a PCIe hierarchy with a switch present, if the link state of an
endpoint device is changed, we must check the whole hierarchy from the
endpoint device to root port, and for each link in the hierarchy, the new
link state should be configured. Previously, the implementation checked
the state but forgot to configure the links between root port to switch.
Fixes Novell bz #448987.

Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Tested-by: Andrew Patterson <andrew.patterson@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/pci/pcie/aspm.c |  127 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 107 insertions(+), 20 deletions(-)

--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -33,6 +33,11 @@ struct endpoint_state {
 struct pcie_link_state {
 	struct list_head sibiling;
 	struct pci_dev *pdev;
+	bool downstream_has_switch;
+
+	struct pcie_link_state *parent;
+	struct list_head children;
+	struct list_head link;
 
 	/* ASPM state */
 	unsigned int support_state;
@@ -125,7 +130,7 @@ static void pcie_set_clock_pm(struct pci
 	link_state->clk_pm_enabled = !!enable;
 }
 
-static void pcie_check_clock_pm(struct pci_dev *pdev)
+static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist)
 {
 	int pos;
 	u32 reg32;
@@ -149,10 +154,26 @@ static void pcie_check_clock_pm(struct p
 		if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
 			enabled = 0;
 	}
-	link_state->clk_pm_capable = capable;
 	link_state->clk_pm_enabled = enabled;
 	link_state->bios_clk_state = enabled;
-	pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
+	if (!blacklist) {
+		link_state->clk_pm_capable = capable;
+		pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
+	} else {
+		link_state->clk_pm_capable = 0;
+		pcie_set_clock_pm(pdev, 0);
+	}
+}
+
+static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev)
+{
+	struct pci_dev *child_dev;
+
+	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
+		if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM)
+			return true;
+	}
+	return false;
 }
 
 /*
@@ -419,9 +440,9 @@ static unsigned int pcie_aspm_check_stat
 {
 	struct pci_dev *child_dev;
 
-	/* If no child, disable the link */
+	/* If no child, ignore the link */
 	if (list_empty(&pdev->subordinate->devices))
-		return 0;
+		return state;
 	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
 		if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
 			/*
@@ -462,6 +483,9 @@ static void __pcie_aspm_config_link(stru
 	int valid = 1;
 	struct pcie_link_state *link_state = pdev->link_state;
 
+	/* If no child, disable the link */
+	if (list_empty(&pdev->subordinate->devices))
+		state = 0;
 	/*
 	 * if the downstream component has pci bridge function, don't do ASPM
 	 * now
@@ -493,20 +517,52 @@ static void __pcie_aspm_config_link(stru
 	link_state->enabled_state = state;
 }
 
+static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link)
+{
+	struct pcie_link_state *root_port_link = link;
+	while (root_port_link->parent)
+		root_port_link = root_port_link->parent;
+	return root_port_link;
+}
+
+/* check the whole hierarchy, and configure each link in the hierarchy */
 static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
 	unsigned int state)
 {
 	struct pcie_link_state *link_state = pdev->link_state;
+	struct pcie_link_state *root_port_link = get_root_port_link(link_state);
+	struct pcie_link_state *leaf;
 
-	if (link_state->support_state == 0)
-		return;
 	state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
 
-	/* state 0 means disabling aspm */
-	state = pcie_aspm_check_state(pdev, state);
+	/* check all links who have specific root port link */
+	list_for_each_entry(leaf, &link_list, sibiling) {
+		if (!list_empty(&leaf->children) ||
+			get_root_port_link(leaf) != root_port_link)
+			continue;
+		state = pcie_aspm_check_state(leaf->pdev, state);
+	}
+	/* check root port link too in case it hasn't children */
+	state = pcie_aspm_check_state(root_port_link->pdev, state);
+
 	if (link_state->enabled_state == state)
 		return;
-	__pcie_aspm_config_link(pdev, state);
+
+	/*
+	 * we must change the hierarchy. See comments in
+	 * __pcie_aspm_config_link for the order
+	 **/
+	if (state & PCIE_LINK_STATE_L1) {
+		list_for_each_entry(leaf, &link_list, sibiling) {
+			if (get_root_port_link(leaf) == root_port_link)
+				__pcie_aspm_config_link(leaf->pdev, state);
+		}
+	} else {
+		list_for_each_entry_reverse(leaf, &link_list, sibiling) {
+			if (get_root_port_link(leaf) == root_port_link)
+				__pcie_aspm_config_link(leaf->pdev, state);
+		}
+	}
 }
 
 /*
@@ -570,6 +626,7 @@ void pcie_aspm_init_link_state(struct pc
 	unsigned int state;
 	struct pcie_link_state *link_state;
 	int error = 0;
+	int blacklist;
 
 	if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
 		return;
@@ -580,29 +637,58 @@ void pcie_aspm_init_link_state(struct pc
 	if (list_empty(&pdev->subordinate->devices))
 		goto out;
 
-	if (pcie_aspm_sanity_check(pdev))
-		goto out;
+	blacklist = !!pcie_aspm_sanity_check(pdev);
 
 	mutex_lock(&aspm_lock);
 
 	link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
 	if (!link_state)
 		goto unlock_out;
-	pdev->link_state = link_state;
 
-	pcie_aspm_configure_common_clock(pdev);
-
-	pcie_aspm_cap_init(pdev);
+	link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev);
+	INIT_LIST_HEAD(&link_state->children);
+	INIT_LIST_HEAD(&link_state->link);
+	if (pdev->bus->self) {/* this is a switch */
+		struct pcie_link_state *parent_link_state;
+
+		parent_link_state = pdev->bus->parent->self->link_state;
+		if (!parent_link_state) {
+			kfree(link_state);
+			goto unlock_out;
+		}
+		list_add(&link_state->link, &parent_link_state->children);
+		link_state->parent = parent_link_state;
+	}
 
-	/* config link state to avoid BIOS error */
-	state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev));
-	__pcie_aspm_config_link(pdev, state);
+	pdev->link_state = link_state;
 
-	pcie_check_clock_pm(pdev);
+	if (!blacklist) {
+		pcie_aspm_configure_common_clock(pdev);
+		pcie_aspm_cap_init(pdev);
+	} else {
+		link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
+		link_state->bios_aspm_state = 0;
+		/* Set support state to 0, so we will disable ASPM later */
+		link_state->support_state = 0;
+	}
 
 	link_state->pdev = pdev;
 	list_add(&link_state->sibiling, &link_list);
 
+	if (link_state->downstream_has_switch) {
+		/*
+		 * If link has switch, delay the link config. The leaf link
+		 * initialization will config the whole hierarchy. but we must
+		 * make sure BIOS doesn't set unsupported link state
+		 **/
+		state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state);
+		__pcie_aspm_config_link(pdev, state);
+	} else
+		__pcie_aspm_configure_link_state(pdev,
+			policy_to_aspm_state(pdev));
+
+	pcie_check_clock_pm(pdev, blacklist);
+
 unlock_out:
 	if (error)
 		free_link_state(pdev);
@@ -635,6 +721,7 @@ void pcie_aspm_exit_link_state(struct pc
 	/* All functions are removed, so just disable ASPM for the link */
 	__pcie_aspm_config_one_dev(parent, 0);
 	list_del(&link_state->sibiling);
+	list_del(&link_state->link);
 	/* Clock PM is for endpoint device */
 
 	free_link_state(parent);


  reply	other threads:[~2009-01-23  1:15 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20090123010651.683741823@mini.kroah.org>
2009-01-23  1:11 ` [patch 00/46] 2.6.28-stable review Greg KH
2009-01-23  1:11   ` Greg KH [this message]
2009-01-23  1:11   ` [patch 02/46] security: introduce missing kfree Greg KH
2009-01-23  1:11   ` [patch 03/46] rt2x00: add USB ID for the Linksys WUSB200 Greg KH
2009-01-23  1:11   ` [patch 04/46] p54usb: Add USB ID for Thomson Speedtouch 121g Greg KH
2009-01-23  1:11   ` [patch 05/46] lib/idr.c: use kmem_cache_zalloc() for the idr_layer cache Greg KH
2009-01-23  1:11   ` [patch 06/46] sgi-xp: eliminate false detection of no heartbeat Greg KH
2009-01-23  1:11   ` [patch 07/46] sched: fix update_min_vruntime Greg KH
2009-01-23  1:11   ` [patch 08/46] IA64: Turn on CONFIG_HAVE_UNSTABLE_CLOCK Greg KH
2009-01-23  1:11   ` [patch 09/46] sound: virtuoso: do not overwrite EEPROM on Xonar D2/D2X Greg KH
2009-01-23  1:11   ` [patch 10/46] ALSA: hda - Add quirk for another HP dv5 Greg KH
2009-01-23  1:11   ` [patch 11/46] ALSA: hda - Fix HP dv5 mic input Greg KH
2009-01-23  1:11   ` [patch 12/46] ALSA: hda - Add automatic model setting for Samsung Q45 Greg KH
2009-01-23  1:11   ` [patch 13/46] ALSA: hda - Dont reset HP pinctl in patch_sigmatel.c Greg KH
2009-01-23  1:11   ` [patch 14/46] ALSA: hda - make laptop-eapd model back for AD1986A Greg KH
2009-01-23  1:11   ` [patch 15/46] drivers/net/irda/irda-usb.c: fix buffer overflow Greg KH
2009-01-23  1:12   ` [patch 16/46] usb-storage: add last-sector hacks Greg KH
2009-01-23  1:12   ` [patch 17/46] usb-storage: set CAPACITY_HEURISTICS flag for bad vendors Greg KH
2009-01-23  1:12   ` [patch 18/46] pkt_sched: sch_htb: Fix deadlock in hrtimers triggered by HTB Greg KH
2009-01-23  1:12   ` [patch 19/46] ipv6: Fix fib6_dump_table walker leak Greg KH
2009-01-23  1:12   ` [patch 20/46] sctp: Avoid memory overflow while FWD-TSN chunk is received with bad stream ID Greg KH
2009-01-23  1:12   ` [patch 21/46] pkt_sched: cls_u32: Fix locking in u32_change() Greg KH
2009-01-23  1:12   ` [patch 22/46] r6040: fix wrong logic in mdio code Greg KH
2009-01-23  1:12   ` [patch 23/46] r6040: save and restore MIER correctly in the interrupt routine Greg KH
2009-01-23  1:12   ` [patch 24/46] r6040: bump release number to 0.19 Greg KH
2009-01-23  1:31     ` Jesper Juhl
2009-01-23  2:04       ` [stable] " Greg KH
2009-01-23  7:53         ` Willy Tarreau
2009-01-23  7:49       ` David Miller
2009-01-23  1:12   ` [patch 25/46] tcp: dont mask EOF and socket errors on nonblocking splice receive Greg KH
2009-01-23  1:12   ` [patch 26/46] USB: re-enable interface after driver unbinds Greg KH
2009-01-23  1:12   ` [patch 27/46] p54usb: fix traffic stalls / packet drop Greg KH
2009-01-23  1:12   ` [patch 28/46] netfilter: x_tables: fix match/target revision lookup Greg KH
2009-01-23  1:12   ` [patch 29/46] netfilter: ebtables: fix inversion in match code Greg KH
2009-01-23  1:12   ` [patch 30/46] netfilter: nf_conntrack: fix ICMP/ICMPv6 timeout sysctls on big-endian Greg KH
2009-01-23  1:12   ` [patch 31/46] dell_rbu: use scnprintf() instead of less secure sprintf() Greg KH
2009-01-23  1:12   ` [patch 32/46] powerpc: is_hugepage_only_range() must account for both 4kB and 64kB slices Greg KH
2009-01-23  1:12   ` [patch 33/46] hwmon: (abituguru3) Fix CONFIG_DMI=n fallback to probe Greg KH
2009-01-23  1:12   ` [patch 34/46] mm: write_cache_pages cyclic fix Greg KH
2009-01-23  1:12   ` [patch 35/46] mm: write_cache_pages early loop termination Greg KH
2009-01-23  1:12   ` [patch 36/46] mm: write_cache_pages writepage error fix Greg KH
2009-01-23  1:12   ` [patch 38/46] mm: write_cache_pages cleanups Greg KH
2009-01-23  1:12   ` [patch 37/46] mm: write_cache_pages integrity fix Greg KH
2009-01-23  1:12   ` [patch 39/46] mm: write_cache_pages optimise page cleaning Greg KH
2009-01-23  1:13   ` [patch 40/46] mm: write_cache_pages terminate quickly Greg KH
2009-01-23  1:13   ` [patch 41/46] mm: write_cache_pages more " Greg KH
2009-01-23  1:13   ` [patch 42/46] mm: do_sync_mapping_range integrity fix Greg KH
2009-01-23  1:13   ` [patch 43/46] mm: direct IO starvation improvement Greg KH
2009-01-23  1:13   ` [patch 44/46] fs: remove WB_SYNC_HOLD Greg KH
2009-01-23  1:13   ` [patch 45/46] fs: sync_sb_inodes fix Greg KH
2009-01-23  1:13   ` [patch 46/46] fs: sys_sync fix Greg KH
2009-01-23  1:50   ` [patch 00/46] 2.6.28-stable review Stefan Lippers-Hollmann
2009-01-23  2:02     ` Greg KH

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=20090123011126.GB19756@kroah.com \
    --to=gregkh@suse.de \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=cavokz@gmail.com \
    --cc=cebbert@redhat.com \
    --cc=chuckw@quantumlinux.com \
    --cc=davej@redhat.com \
    --cc=eteo@redhat.com \
    --cc=jake@lwn.net \
    --cc=jbarnes@virtuousgeek.org \
    --cc=jmforbes@linuxtx.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mkrufky@linuxtv.org \
    --cc=rbranco@la.checkpoint.com \
    --cc=rdunlap@xenotime.net \
    --cc=reviews@ml.cw.f00f.org \
    --cc=shaohua.li@intel.com \
    --cc=stable@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=tytso@mit.edu \
    --cc=w@1wt.eu \
    --cc=zwane@arm.linux.org.uk \
    /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