Index: 20090521/drivers/pci/pcie/aspm.c
===================================================================
--- 20090521.orig/drivers/pci/pcie/aspm.c
+++ 20090521/drivers/pci/pcie/aspm.c
@@ -19,6 +19,8 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/pci-aspm.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include "../pci.h"
 
 #ifdef MODULE_PARAM_PREFIX
@@ -859,6 +861,117 @@ void pcie_aspm_remove_sysfs_dev_files(st
 		sysfs_remove_file_from_group(&pdev->dev.kobj,
 			&dev_attr_clk_ctl.attr, power_group);
 }
+
+static void show_link(struct seq_file *p,
+		      struct pcie_link_state *link, int depth)
+{
+	struct pci_dev *child, *parent = link->pdev;
+	struct pci_bus *linkbus = parent->subordinate;
+	struct pcie_link_state *childlink;
+	int indent = depth * 4;
+
+	seq_printf(p,
+		   "%*sLINK (addr: %p, pdev: %p, name: %s)\n"
+		   "%*s  root: %p, parent %p\n"
+		   "%*s  ASPM enabled: L0sUP%c, L0sDW%c, L1%c\n"
+		   "%*s  ASPM capable: L0sUP%c, L0sDW%c, L1%c\n"
+		   "%*s  ASPM support: L0sUP%c, L0sDW%c, L1%c\n"
+		   "%*s  ASPM disable: L0sUP%c, L0sDW%c, L1%c\n"
+		   "%*s  ASPM default: L0sUP%c, L0sDW%c, L1%c\n"
+		   "%*s  ASPM latency: L0sUP %u, L0sDW %u, L1 %u\n"
+		   "%*s  ClockPM: capable %u, enabled %u, default %u\n",
+		   indent, "", link, parent, pci_name(parent),
+		   indent, "", link->root, link->parent,
+		   indent, "",
+		   (link->aspm_enabled & ASPM_STATE_L0S_UP) ? '+' : '-',
+		   (link->aspm_enabled & ASPM_STATE_L0S_DW) ? '+' : '-',
+		   (link->aspm_enabled & ASPM_STATE_L1)     ? '+' : '-',
+		   indent, "",
+		   (link->aspm_capable & ASPM_STATE_L0S_UP) ? '+' : '-',
+		   (link->aspm_capable & ASPM_STATE_L0S_DW) ? '+' : '-',
+		   (link->aspm_capable & ASPM_STATE_L1)     ? '+' : '-',
+		   indent, "",
+		   (link->aspm_support & ASPM_STATE_L0S_UP) ? '+' : '-',
+		   (link->aspm_support & ASPM_STATE_L0S_DW) ? '+' : '-',
+		   (link->aspm_support & ASPM_STATE_L1)     ? '+' : '-',
+		   indent, "",
+		   (link->aspm_disable & ASPM_STATE_L0S_UP) ? '+' : '-',
+		   (link->aspm_disable & ASPM_STATE_L0S_DW) ? '+' : '-',
+		   (link->aspm_disable & ASPM_STATE_L1)     ? '+' : '-',
+		   indent, "",
+		   (link->aspm_default & ASPM_STATE_L0S_UP) ? '+' : '-',
+		   (link->aspm_default & ASPM_STATE_L0S_DW) ? '+' : '-',
+		   (link->aspm_default & ASPM_STATE_L1)     ? '+' : '-',
+		   indent, "",
+		   link->latency_up.l0s, link->latency_dw.l0s,
+		   max_t(u32, link->latency_up.l1, link->latency_dw.l1),
+		   indent, "", link->clkpm_capable,
+		   link->clkpm_enabled, link->clkpm_default);
+	list_for_each_entry(child, &linkbus->devices, bus_list) {
+		int func = PCI_FUNC(child->devfn);
+		if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT) &&
+		    (child->pcie_type != PCI_EXP_TYPE_LEG_END))
+			continue;
+		seq_printf(p, "%*s  EP[%s] accept l0s %u, l1 %u\n",
+			   indent, "", pci_name(child),
+			   link->acceptable[func].l0s,
+			   link->acceptable[func].l1);
+	}
+	seq_printf(p, "\n");
+
+	list_for_each_entry(childlink, &link->children, link)
+		show_link(p, childlink, (depth + 1));
+}
+
+static int show_pcie_link_state(struct seq_file *p, void *v)
+{
+	struct pcie_link_state *link;
+
+	mutex_lock(&aspm_lock);
+	list_for_each_entry(link, &link_list, sibling) {
+		if (!link->parent)
+			show_link(p, link, 0);
+	}
+	mutex_unlock(&aspm_lock);
+	return 0;
+}
+
+static int pcie_link_state_open(struct inode *inode, struct file *file)
+{
+	size_t size = 128 * 1024;
+	char *buf;
+	int res;
+	struct seq_file *m;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	res = single_open(file, show_pcie_link_state, NULL);
+	if (!res) {
+		m = file->private_data;
+		m->buf = buf;
+		m->size = size;
+	} else
+		kfree(buf);
+	return res;
+}
+
+static const struct file_operations pcie_link_state_operations = {
+	.open		= pcie_link_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int pcie_aspm_init_proc(void)
+{
+	if (aspm_disabled)
+		return 0;
+	proc_create("pcie_link_state", 0, NULL, &pcie_link_state_operations);
+	return 0;
+}
+late_initcall(pcie_aspm_init_proc);
 #endif
 
 static int __init pcie_aspm_disable(char *str)
