From 8e822df700694ca6850d1e0c122fd7004b2778d8 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 8 Jun 2009 09:27:25 +0800 Subject: PCI: disable ASPM on VIA root-port-under-bridge configurations VIA has a strange chipset, it has root port under a bridge. Disable ASPM for such strange chipset. Cc: stable@kernel.org Tested-by: Wolfgang Denk Signed-off-by: Shaohua Li Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b0367f168af..777b2c76caf 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -638,6 +638,10 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + /* VIA has a strange chipset, root port is under a bridge */ + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && + pdev->bus->self) + return; down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) goto out; -- cgit v1.2.3-70-g09d2 From dc64cd1131a3b5762e26bd8b01dc79030dd0c555 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:11:33 +0900 Subject: PCI ASPM: fix typo in struct pcie_link_state Fix a typo in struct pcie_link_state. The "sibiling" field in the struct pcie_link_state should be "sibling". Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 777b2c76caf..419f1f3697c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -32,7 +32,7 @@ struct endpoint_state { }; struct pcie_link_state { - struct list_head sibiling; + struct list_head sibling; struct pci_dev *pdev; bool downstream_has_switch; @@ -541,7 +541,7 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; /* check all links who have specific root port link */ - list_for_each_entry(leaf, &link_list, sibiling) { + list_for_each_entry(leaf, &link_list, sibling) { if (!list_empty(&leaf->children) || get_root_port_link(leaf) != root_port_link) continue; @@ -558,12 +558,12 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, * __pcie_aspm_config_link for the order **/ if (state & PCIE_LINK_STATE_L1) { - list_for_each_entry(leaf, &link_list, sibiling) { + list_for_each_entry(leaf, &link_list, sibling) { 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) { + list_for_each_entry_reverse(leaf, &link_list, sibling) { if (get_root_port_link(leaf) == root_port_link) __pcie_aspm_config_link(leaf->pdev, state); } @@ -682,7 +682,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) } link_state->pdev = pdev; - list_add(&link_state->sibiling, &link_list); + list_add(&link_state->sibling, &link_list); if (link_state->downstream_has_switch) { /* @@ -729,7 +729,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) /* 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->sibling); list_del(&link_state->link); /* Clock PM is for endpoint device */ @@ -806,7 +806,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); aspm_policy = i; - list_for_each_entry(link_state, &link_list, sibiling) { + list_for_each_entry(link_state, &link_list, sibling) { pdev = link_state->pdev; __pcie_aspm_configure_link_state(pdev, policy_to_aspm_state(pdev)); -- cgit v1.2.3-70-g09d2 From 80bfdbe370d56a1448c7078cd6d286b89241a72e Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:12:43 +0900 Subject: PCI ASPM: cleanup aspm state field in struct pcie_link_state The "support_state", "enabled_state" and "bios_aspm_state" fields in the struct pcie_link_state take 2-bit value. So those fields don't need to be defined as unsigned int. This patch makes those fields 2-bit, and cleans up some related code. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 71 ++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 33 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 419f1f3697c..fdb3b7da738 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -41,9 +41,10 @@ struct pcie_link_state { struct list_head link; /* ASPM state */ - unsigned int support_state; - unsigned int enabled_state; - unsigned int bios_aspm_state; + u32 aspm_support:2; /* Supported ASPM state */ + u32 aspm_enabled:2; /* Enabled ASPM state */ + u32 aspm_default:2; /* Default ASPM state by BIOS */ + /* upstream component */ unsigned int l0s_upper_latency; unsigned int l1_upper_latency; @@ -88,9 +89,9 @@ static int policy_to_aspm_state(struct pci_dev *pdev) return 0; case POLICY_POWERSAVE: /* Enable ASPM L0s/L1 */ - return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_DEFAULT: - return link_state->bios_aspm_state; + return link_state->aspm_default; } return 0; } @@ -311,6 +312,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, u32 reg32; unsigned int latency; + *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; @@ -333,26 +335,29 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, static void pcie_aspm_cap_init(struct pci_dev *pdev) { struct pci_dev *child_dev; - u32 state, tmp; + u32 support, l0s, l1, enabled; struct pcie_link_state *link_state = pdev->link_state; /* upstream component states */ - pcie_aspm_get_cap_device(pdev, &link_state->support_state, - &link_state->l0s_upper_latency, - &link_state->l1_upper_latency, - &link_state->enabled_state); + pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); + link_state->aspm_support = support; + link_state->l0s_upper_latency = l0s; + link_state->l1_upper_latency = l1; + link_state->aspm_enabled = enabled; + /* downstream component states, all functions have the same setting */ child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, bus_list); - pcie_aspm_get_cap_device(child_dev, &state, - &link_state->l0s_down_latency, - &link_state->l1_down_latency, - &tmp); - link_state->support_state &= state; - if (!link_state->support_state) + pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); + link_state->aspm_support &= support; + link_state->l0s_down_latency = l0s; + link_state->l1_down_latency = l1; + + if (!link_state->aspm_support) return; - link_state->enabled_state &= link_state->support_state; - link_state->bios_aspm_state = link_state->enabled_state; + + link_state->aspm_enabled &= link_state->aspm_support; + link_state->aspm_default = link_state->aspm_enabled; /* ENDPOINT states*/ list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { @@ -371,7 +376,7 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); ep_state->l0s_acceptable_latency = latency; - if (link_state->support_state & PCIE_LINK_STATE_L1) { + if (link_state->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); ep_state->l1_acceptable_latency = latency; @@ -389,7 +394,7 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, parent_dev = pdev->bus->self; link_state = parent_dev->link_state; - state &= link_state->support_state; + state &= link_state->aspm_support; if (state == 0) return 0; ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; @@ -519,7 +524,7 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) if (!(state & PCIE_LINK_STATE_L1)) __pcie_aspm_config_one_dev(pdev, state); - link_state->enabled_state = state; + link_state->aspm_enabled = state; } static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) @@ -550,7 +555,7 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, /* 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) + if (link_state->aspm_enabled == state) return; /* @@ -675,10 +680,11 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) 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; + link_state->aspm_enabled = + (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + link_state->aspm_default = 0; /* Set support state to 0, so we will disable ASPM later */ - link_state->support_state = 0; + link_state->aspm_support = 0; } link_state->pdev = pdev; @@ -690,7 +696,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * 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); + state = pcie_aspm_check_state(pdev, link_state->aspm_default); __pcie_aspm_config_link(pdev, state); } else __pcie_aspm_configure_link_state(pdev, @@ -753,7 +759,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) * devices changed PM state, we should recheck if latency meets all * functions' requirement */ - pcie_aspm_configure_link_state(pdev, link_state->enabled_state); + pcie_aspm_configure_link_state(pdev, link_state->aspm_enabled); } /* @@ -776,12 +782,11 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); link_state = parent->link_state; - link_state->support_state &= - ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); + link_state->aspm_support &= ~state; if (state & PCIE_LINK_STATE_CLKPM) link_state->clk_pm_capable = 0; - __pcie_aspm_configure_link_state(parent, link_state->enabled_state); + __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) pcie_set_clock_pm(parent, 0); mutex_unlock(&aspm_lock); @@ -842,7 +847,7 @@ static ssize_t link_state_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->enabled_state); + return sprintf(buf, "%d\n", link_state->aspm_enabled); } static ssize_t link_state_store(struct device *dev, @@ -908,7 +913,7 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); if (link_state->clk_pm_capable) @@ -924,7 +929,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); if (link_state->clk_pm_capable) -- cgit v1.2.3-70-g09d2 From b6c2e54d3ea27719b920faf15db92dfe0260f0d2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:14:58 +0900 Subject: PCI ASPM: cleanup latency field in struct pcie_link_state Clean up latency related data structures for ASPM. - Introduce struct acpi_latency for exit latency and acceptable latency management. With this change, struct endpoint_state is no longer needed. - We don't need to hold both upstream latency and downstream latency in the current implementation. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 66 +++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index fdb3b7da738..88351c242a4 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -26,9 +26,9 @@ #endif #define MODULE_PARAM_PREFIX "pcie_aspm." -struct endpoint_state { - unsigned int l0s_acceptable_latency; - unsigned int l1_acceptable_latency; +struct aspm_latency { + u32 l0s; /* L0s latency (nsec) */ + u32 l1; /* L1 latency (nsec) */ }; struct pcie_link_state { @@ -45,22 +45,19 @@ struct pcie_link_state { u32 aspm_enabled:2; /* Enabled ASPM state */ u32 aspm_default:2; /* Default ASPM state by BIOS */ - /* upstream component */ - unsigned int l0s_upper_latency; - unsigned int l1_upper_latency; - /* downstream component */ - unsigned int l0s_down_latency; - unsigned int l1_down_latency; + /* Latencies */ + struct aspm_latency latency; /* Exit latency */ + /* Clock PM state*/ unsigned int clk_pm_capable; unsigned int clk_pm_enabled; unsigned int bios_clk_state; /* - * A pcie downstream port only has one slot under it, so at most there - * are 8 functions + * Endpoint acceptable latencies. A pcie downstream port only + * has one slot under it, so at most there are 8 functions. */ - struct endpoint_state endpoints[8]; + struct aspm_latency acceptable[8]; }; static int aspm_disabled, aspm_force; @@ -341,8 +338,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) /* upstream component states */ pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); link_state->aspm_support = support; - link_state->l0s_upper_latency = l0s; - link_state->l1_upper_latency = l1; + link_state->latency.l0s = l0s; + link_state->latency.l1 = l1; link_state->aspm_enabled = enabled; /* downstream component states, all functions have the same setting */ @@ -350,8 +347,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) bus_list); pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); link_state->aspm_support &= support; - link_state->l0s_down_latency = l0s; - link_state->l1_down_latency = l1; + link_state->latency.l0s = max_t(u32, link_state->latency.l0s, l0s); + link_state->latency.l1 = max_t(u32, link_state->latency.l1, l1); if (!link_state->aspm_support) return; @@ -364,8 +361,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) int pos; u32 reg32; unsigned int latency; - struct endpoint_state *ep_state = - &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + struct aspm_latency *acceptable = + &link_state->acceptable[PCI_FUNC(child_dev->devfn)]; if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) @@ -375,11 +372,11 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); - ep_state->l0s_acceptable_latency = latency; + acceptable->l0s = latency; if (link_state->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); - ep_state->l1_acceptable_latency = latency; + acceptable->l1 = latency; } } } @@ -388,16 +385,16 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, unsigned int state) { struct pci_dev *parent_dev, *tmp_dev; - unsigned int latency, l1_latency = 0; + unsigned int l1_latency = 0; struct pcie_link_state *link_state; - struct endpoint_state *ep_state; + struct aspm_latency *acceptable; parent_dev = pdev->bus->self; link_state = parent_dev->link_state; state &= link_state->aspm_support; if (state == 0) return 0; - ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)]; /* * Check latency for endpoint device. @@ -411,21 +408,14 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { parent_dev = tmp_dev->bus->self; link_state = parent_dev->link_state; - if (state & PCIE_LINK_STATE_L0S) { - latency = max_t(unsigned int, - link_state->l0s_upper_latency, - link_state->l0s_down_latency); - if (latency > ep_state->l0s_acceptable_latency) - state &= ~PCIE_LINK_STATE_L0S; - } - if (state & PCIE_LINK_STATE_L1) { - latency = max_t(unsigned int, - link_state->l1_upper_latency, - link_state->l1_down_latency); - if (latency + l1_latency > - ep_state->l1_acceptable_latency) - state &= ~PCIE_LINK_STATE_L1; - } + if ((state & PCIE_LINK_STATE_L0S) && + (link_state->latency.l0s > acceptable->l0s)) + state &= ~PCIE_LINK_STATE_L0S; + + if ((state & PCIE_LINK_STATE_L1) && + (link_state->latency.l1 + l1_latency > acceptable->l1)) + state &= ~PCIE_LINK_STATE_L1; + if (!parent_dev->bus->self) /* parent_dev is a root port */ break; else { -- cgit v1.2.3-70-g09d2 From 4d246e458918d469ad645fd5f937ac22982e0466 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:15:38 +0900 Subject: PCI ASPM: cleanup clkpm state in struct pcie_link_state The "clk_pm_capable", "clk_pm_enable" and "bios_clk_state" fields in the struct pcie_link_state only take 1-bit value. So those fields don't need to be defined as unsigned int. This patch makes those fields 1-bit, and cleans up some related code. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 88351c242a4..2d7e695b758 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -45,14 +45,13 @@ struct pcie_link_state { u32 aspm_enabled:2; /* Enabled ASPM state */ u32 aspm_default:2; /* Default ASPM state by BIOS */ + /* Clock PM state */ + u32 clkpm_capable:1; /* Clock PM capable? */ + u32 clkpm_enabled:1; /* Current Clock PM state */ + u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + /* Latencies */ struct aspm_latency latency; /* Exit latency */ - - /* Clock PM state*/ - unsigned int clk_pm_capable; - unsigned int clk_pm_enabled; - unsigned int bios_clk_state; - /* * Endpoint acceptable latencies. A pcie downstream port only * has one slot under it, so at most there are 8 functions. @@ -105,7 +104,7 @@ static int policy_to_clkpm_state(struct pci_dev *pdev) /* Disable Clock PM */ return 1; case POLICY_DEFAULT: - return link_state->bios_clk_state; + return link_state->clkpm_default; } return 0; } @@ -128,7 +127,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); } - link_state->clk_pm_enabled = !!enable; + link_state->clkpm_enabled = !!enable; } static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) @@ -155,13 +154,13 @@ static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clk_pm_enabled = enabled; - link_state->bios_clk_state = enabled; + link_state->clkpm_enabled = enabled; + link_state->clkpm_default = enabled; if (!blacklist) { - link_state->clk_pm_capable = capable; + link_state->clkpm_capable = capable; pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); } else { - link_state->clk_pm_capable = 0; + link_state->clkpm_capable = 0; pcie_set_clock_pm(pdev, 0); } } @@ -774,10 +773,10 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) link_state = parent->link_state; link_state->aspm_support &= ~state; if (state & PCIE_LINK_STATE_CLKPM) - link_state->clk_pm_capable = 0; + link_state->clkpm_capable = 0; __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); - if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) + if (!link_state->clkpm_capable && link_state->clkpm_enabled) pcie_set_clock_pm(parent, 0); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -805,8 +804,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) pdev = link_state->pdev; __pcie_aspm_configure_link_state(pdev, policy_to_aspm_state(pdev)); - if (link_state->clk_pm_capable && - link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) + if (link_state->clkpm_capable && + link_state->clkpm_enabled != policy_to_clkpm_state(pdev)) pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); } @@ -867,7 +866,7 @@ static ssize_t clk_ctl_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->clk_pm_enabled); + return sprintf(buf, "%d\n", link_state->clkpm_enabled); } static ssize_t clk_ctl_store(struct device *dev, @@ -906,7 +905,7 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) if (link_state->aspm_support) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } @@ -922,7 +921,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) if (link_state->aspm_support) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } -- cgit v1.2.3-70-g09d2 From 5cde89d80172a393e49077d2450545b97ac8d972 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:17:04 +0900 Subject: PCI ASPM: cleanup misc in struct pcie_link_state Cleanup for some fields in pcie_link_state. - Add comments. - make "downstream_has_switch" field 1-bit. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 2d7e695b758..a1ae9b6f399 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -32,13 +32,11 @@ struct aspm_latency { }; struct pcie_link_state { - struct list_head sibling; - struct pci_dev *pdev; - bool downstream_has_switch; - - struct pcie_link_state *parent; - struct list_head children; - struct list_head link; + struct pci_dev *pdev; /* Upstream component of the Link */ + struct pcie_link_state *parent; /* pointer to the parent Link state */ + struct list_head sibling; /* node in link_list */ + struct list_head children; /* list of child link states */ + struct list_head link; /* node in parent's children list */ /* ASPM state */ u32 aspm_support:2; /* Supported ASPM state */ @@ -50,6 +48,8 @@ struct pcie_link_state { u32 clkpm_enabled:1; /* Current Clock PM state */ u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + u32 has_switch:1; /* Downstream has switches? */ + /* Latencies */ struct aspm_latency latency; /* Exit latency */ /* @@ -648,7 +648,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (!link_state) goto unlock_out; - link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev); + link_state->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 */ @@ -679,7 +679,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) link_state->pdev = pdev; list_add(&link_state->sibling, &link_list); - if (link_state->downstream_has_switch) { + if (link_state->has_switch) { /* * If link has switch, delay the link config. The leaf link * initialization will config the whole hierarchy. but we must -- cgit v1.2.3-70-g09d2 From 5aa63583cbec27482c6f1d761a0509f59b7969a8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:17:44 +0900 Subject: PCI ASPM: cleanup change input argument of aspm functions In the current ASPM implementation, there are many functions that take a pointer to struct pci_dev corresponding to the upstream component of the link as a parameter. But, since those functions handle PCI express link state, a pointer to struct pcie_link_state is more suitable than a pointer to struct pci_dev. Changing a parameter to a pointer to struct pcie_link_state makes ASPM code much simpler and easier to read. This patch also contains some minor cleanups. This patch doesn't have any functional change. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 372 ++++++++++++++++++++++-------------------------- 1 file changed, 173 insertions(+), 199 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index a1ae9b6f399..9eaaf95f65a 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -75,10 +75,8 @@ static const char *policy_str[] = { #define LINK_RETRAIN_TIMEOUT HZ -static int policy_to_aspm_state(struct pci_dev *pdev) +static int policy_to_aspm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ @@ -87,15 +85,13 @@ static int policy_to_aspm_state(struct pci_dev *pdev) /* Enable ASPM L0s/L1 */ return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_DEFAULT: - return link_state->aspm_default; + return link->aspm_default; } return 0; } -static int policy_to_clkpm_state(struct pci_dev *pdev) +static int policy_to_clkpm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ @@ -104,73 +100,73 @@ static int policy_to_clkpm_state(struct pci_dev *pdev) /* Disable Clock PM */ return 1; case POLICY_DEFAULT: - return link_state->clkpm_default; + return link->clkpm_default; } return 0; } -static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) { - struct pci_dev *child_dev; int pos; u16 reg16; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (enable) reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; else reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(child, pos + PCI_EXP_LNKCTL, reg16); } - link_state->clkpm_enabled = !!enable; + link->clkpm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) +static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) { - int pos; + int pos, capable = 1, enabled = 1; u32 reg32; u16 reg16; - int capable = 1, enabled = 1; - struct pci_dev *child_dev; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* All functions should have the same cap and state, take the worst */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { capable = 0; enabled = 0; break; } - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clkpm_enabled = enabled; - link_state->clkpm_default = enabled; + link->clkpm_enabled = enabled; + link->clkpm_default = enabled; if (!blacklist) { - link_state->clkpm_capable = capable; - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + link->clkpm_capable = capable; + pcie_set_clock_pm(link, policy_to_clkpm_state(link)); } else { - link_state->clkpm_capable = 0; - pcie_set_clock_pm(pdev, 0); + link->clkpm_capable = 0; + pcie_set_clock_pm(link, 0); } } -static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) +static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) { - struct pci_dev *child_dev; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_UPSTREAM) return true; } return false; @@ -181,89 +177,79 @@ static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) * could use common clock. If they are, configure them to use the * common clock. That will reduce the ASPM state exit latency. */ -static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) { - int pos, child_pos, i = 0; - u16 reg16 = 0; - struct pci_dev *child_dev; - int same_clock = 1; + int ppos, cpos, same_clock = 1; + u16 reg16, parent_reg, child_reg[8]; unsigned long start_jiffies; - u16 child_regs[8], parent_reg; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* - * all functions of a slot should have the same Slot Clock + * All functions of a slot should have the same Slot Clock * Configuration, so just check one function - * */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - BUG_ON(!child_dev->is_pcie); + */ + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + BUG_ON(!child->is_pcie); /* Check downstream component if bit Slot Clock Configuration is 1 */ - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Check upstream component if bit Slot Clock Configuration is 1 */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Configure downstream component, all functions */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - ®16); - child_regs[i] = reg16; + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); + child_reg[PCI_FUNC(child->devfn)] = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - reg16); - i++; + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, reg16); } /* Configure upstream component */ - pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKCTL, ®16); parent_reg = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* retrain link */ + /* Retrain link */ reg16 |= PCI_EXP_LNKCTL_RL; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* Wait for link training end */ - /* break out after waiting for timeout */ + /* Wait for link training end. Break out after waiting for timeout */ start_jiffies = jiffies; for (;;) { - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) break; msleep(1); } - /* training failed -> recover */ - if (reg16 & PCI_EXP_LNKSTA_LT) { - dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" - " common clock\n"); - i = 0; - list_for_each_entry(child_dev, &pdev->subordinate->devices, - bus_list) { - child_pos = pci_find_capability(child_dev, - PCI_CAP_ID_EXP); - pci_write_config_word(child_dev, - child_pos + PCI_EXP_LNKCTL, - child_regs[i]); - i++; - } - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + return; + + /* Training failed. Restore common clock configurations */ + dev_printk(KERN_ERR, &parent->dev, + "ASPM: Could not configure common clock\n"); + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, + child_reg[PCI_FUNC(child->devfn)]); } + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg); } /* @@ -328,51 +314,50 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); } -static void pcie_aspm_cap_init(struct pci_dev *pdev) +static void pcie_aspm_cap_init(struct pcie_link_state *link) { - struct pci_dev *child_dev; u32 support, l0s, l1, enabled; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* upstream component states */ - pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); - link_state->aspm_support = support; - link_state->latency.l0s = l0s; - link_state->latency.l1 = l1; - link_state->aspm_enabled = enabled; + pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); + link->aspm_support = support; + link->latency.l0s = l0s; + link->latency.l1 = l1; + link->aspm_enabled = enabled; /* downstream component states, all functions have the same setting */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); - link_state->aspm_support &= support; - link_state->latency.l0s = max_t(u32, link_state->latency.l0s, l0s); - link_state->latency.l1 = max_t(u32, link_state->latency.l1, l1); - - if (!link_state->aspm_support) + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled); + link->aspm_support &= support; + link->latency.l0s = max_t(u32, link->latency.l0s, l0s); + link->latency.l1 = max_t(u32, link->latency.l1, l1); + + if (!link->aspm_support) return; - link_state->aspm_enabled &= link_state->aspm_support; - link_state->aspm_default = link_state->aspm_enabled; + link->aspm_enabled &= link->aspm_support; + link->aspm_default = link->aspm_enabled; /* ENDPOINT states*/ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + list_for_each_entry(child, &linkbus->devices, bus_list) { int pos; u32 reg32; unsigned int latency; struct aspm_latency *acceptable = - &link_state->acceptable[PCI_FUNC(child_dev->devfn)]; + &link->acceptable[PCI_FUNC(child->devfn)]; - if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + if (child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END) continue; - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); acceptable->l0s = latency; - if (link_state->aspm_support & PCIE_LINK_STATE_L1) { + if (link->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); acceptable->l1 = latency; @@ -434,33 +419,33 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, return state; } -static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, - unsigned int state) +static u32 pcie_aspm_check_state(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; + pci_power_t power_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* If no child, ignore the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) return state; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - /* - * If downstream component of a link is pci bridge, we - * disable ASPM for now for the link - * */ - state = 0; - break; - } - if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + + list_for_each_entry(child, &linkbus->devices, bus_list) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + */ + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return 0; + + if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END)) continue; /* Device not in D0 doesn't need check latency */ - if (child_dev->current_state == PCI_D1 || - child_dev->current_state == PCI_D2 || - child_dev->current_state == PCI_D3hot || - child_dev->current_state == PCI_D3cold) + power_state = child->current_state; + if (power_state == PCI_D1 || power_state == PCI_D2 || + power_state == PCI_D3hot || power_state == PCI_D3cold) continue; - state = __pcie_aspm_check_state_one(child_dev, state); + state = __pcie_aspm_check_state_one(child, state); } return state; } @@ -476,44 +461,38 @@ static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); } -static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; - int valid = 1; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* If no child, disable the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) state = 0; /* - * if the downstream component has pci bridge function, don't do ASPM - * now + * If the downstream component has pci bridge function, don't + * do ASPM now. */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - valid = 0; - break; - } + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return; } - if (!valid) - return; - /* - * spec 2.0 suggests all functions should be configured the same - * setting for ASPM. Enabling ASPM L1 should be done in upstream - * component first and then downstream, and vice versa for disabling - * ASPM L1. Spec doesn't mention L0S. + * Spec 2.0 suggests all functions should be configured the + * same setting for ASPM. Enabling ASPM L1 should be done in + * upstream component first and then downstream, and vice + * versa for disabling ASPM L1. Spec doesn't mention L0S. */ if (state & PCIE_LINK_STATE_L1) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) - __pcie_aspm_config_one_dev(child_dev, state); + list_for_each_entry(child, &linkbus->devices, bus_list) + __pcie_aspm_config_one_dev(child, state); if (!(state & PCIE_LINK_STATE_L1)) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - link_state->aspm_enabled = state; + link->aspm_enabled = state; } static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) @@ -524,42 +503,38 @@ static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) 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) +/* Check the whole hierarchy, and configure each link in the hierarchy */ +static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 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; + struct pcie_link_state *leaf, *root = get_root_port_link(link); - state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - /* check all links who have specific root port link */ + /* Check all links who have specific root port link */ list_for_each_entry(leaf, &link_list, sibling) { if (!list_empty(&leaf->children) || - get_root_port_link(leaf) != root_port_link) + get_root_port_link(leaf) != root) continue; - state = pcie_aspm_check_state(leaf->pdev, state); + state = pcie_aspm_check_state(leaf, 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->aspm_enabled == state) + /* Check root port link too in case it hasn't children */ + state = pcie_aspm_check_state(root, state); + if (link->aspm_enabled == state) return; - /* - * we must change the hierarchy. See comments in + * 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, sibling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + if (get_root_port_link(leaf) == root) + __pcie_aspm_config_link(leaf, state); } } else { list_for_each_entry_reverse(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + if (get_root_port_link(leaf) == root) + __pcie_aspm_config_link(leaf, state); } } } @@ -568,20 +543,20 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, * pcie_aspm_configure_link_state: enable/disable PCI express link state * @pdev: the root port or switch downstream port */ -static void pcie_aspm_configure_link_state(struct pci_dev *pdev, - unsigned int state) +static void pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 state) { down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - __pcie_aspm_configure_link_state(pdev, state); + __pcie_aspm_configure_link_state(link, state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } -static void free_link_state(struct pci_dev *pdev) +static void free_link_state(struct pcie_link_state *link) { - kfree(pdev->link_state); - pdev->link_state = NULL; + link->pdev->link_state = NULL; + kfree(link); } static int pcie_aspm_sanity_check(struct pci_dev *pdev) @@ -648,7 +623,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (!link_state) goto unlock_out; - link_state->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 */ @@ -662,12 +636,13 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) list_add(&link_state->link, &parent_link_state->children); link_state->parent = parent_link_state; } - + link_state->pdev = pdev; + link_state->has_switch = pcie_aspm_downstream_has_switch(link_state); pdev->link_state = link_state; if (!blacklist) { - pcie_aspm_configure_common_clock(pdev); - pcie_aspm_cap_init(pdev); + pcie_aspm_configure_common_clock(link_state); + pcie_aspm_cap_init(link_state); } else { link_state->aspm_enabled = (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); @@ -676,7 +651,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) link_state->aspm_support = 0; } - link_state->pdev = pdev; list_add(&link_state->sibling, &link_list); if (link_state->has_switch) { @@ -685,17 +659,18 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * 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->aspm_default); - __pcie_aspm_config_link(pdev, state); + state = pcie_aspm_check_state(link_state, + link_state->aspm_default); + __pcie_aspm_config_link(link_state, state); } else - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); + __pcie_aspm_configure_link_state(link_state, + policy_to_aspm_state(link_state)); - pcie_check_clock_pm(pdev, blacklist); + pcie_check_clock_pm(link_state, blacklist); unlock_out: if (error) - free_link_state(pdev); + free_link_state(link_state); mutex_unlock(&aspm_lock); out: up_read(&pci_bus_sem); @@ -728,7 +703,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) list_del(&link_state->link); /* Clock PM is for endpoint device */ - free_link_state(parent); + free_link_state(link_state); out: mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -748,7 +723,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) * devices changed PM state, we should recheck if latency meets all * functions' requirement */ - pcie_aspm_configure_link_state(pdev, link_state->aspm_enabled); + pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); } /* @@ -775,9 +750,9 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) if (state & PCIE_LINK_STATE_CLKPM) link_state->clkpm_capable = 0; - __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); + __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); if (!link_state->clkpm_capable && link_state->clkpm_enabled) - pcie_set_clock_pm(parent, 0); + pcie_set_clock_pm(link_state, 0); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } @@ -786,7 +761,6 @@ EXPORT_SYMBOL(pci_disable_link_state); static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) { int i; - struct pci_dev *pdev; struct pcie_link_state *link_state; for (i = 0; i < ARRAY_SIZE(policy_str); i++) @@ -801,12 +775,12 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) mutex_lock(&aspm_lock); aspm_policy = i; list_for_each_entry(link_state, &link_list, sibling) { - pdev = link_state->pdev; - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); + __pcie_aspm_configure_link_state(link_state, + policy_to_aspm_state(link_state)); if (link_state->clkpm_capable && - link_state->clkpm_enabled != policy_to_clkpm_state(pdev)) - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + link_state->clkpm_enabled != policy_to_clkpm_state(link_state)) + pcie_set_clock_pm(link_state, + policy_to_clkpm_state(link_state)); } mutex_unlock(&aspm_lock); @@ -844,7 +818,7 @@ static ssize_t link_state_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -852,7 +826,7 @@ static ssize_t link_state_store(struct device *dev, state = buf[0]-'0'; if (state >= 0 && state <= 3) { /* setup link aspm state */ - pcie_aspm_configure_link_state(pci_device, state); + pcie_aspm_configure_link_state(pdev->link_state, state); return n; } @@ -883,7 +857,7 @@ static ssize_t clk_ctl_store(struct device *dev, down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clock_pm(pci_device, !!state); + pcie_set_clock_pm(pci_device->link_state, !!state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); -- cgit v1.2.3-70-g09d2 From 8d349ace9a5c2a8404bcf4a371fe170480ffbebb Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:18:22 +0900 Subject: PCI ASPM: cleanup initialization Clean up ASPM initialization by refactoring some functionality, renaming functions, and moving things around. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 142 +++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 67 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 9eaaf95f65a..68a4d4b15f9 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -126,7 +126,7 @@ static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) link->clkpm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) +static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) { int pos, capable = 1, enabled = 1; u32 reg32; @@ -151,13 +151,7 @@ static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) } link->clkpm_enabled = enabled; link->clkpm_default = enabled; - if (!blacklist) { - link->clkpm_capable = capable; - pcie_set_clock_pm(link, policy_to_clkpm_state(link)); - } else { - link->clkpm_capable = 0; - pcie_set_clock_pm(link, 0); - } + link->clkpm_capable = (blacklist) ? 0 : capable; } static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) @@ -314,12 +308,23 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); } -static void pcie_aspm_cap_init(struct pcie_link_state *link) +static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) { u32 support, l0s, l1, enabled; struct pci_dev *child, *parent = link->pdev; struct pci_bus *linkbus = parent->subordinate; + if (blacklist) { + /* Set support state to 0, so we will disable ASPM later */ + link->aspm_support = 0; + link->aspm_default = 0; + link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; + return; + } + + /* Configure common clock before checking latencies */ + pcie_aspm_configure_common_clock(link); + /* upstream component states */ pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); link->aspm_support = support; @@ -590,6 +595,42 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) return 0; } +static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link; + int blacklist = !!pcie_aspm_sanity_check(pdev); + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return NULL; + INIT_LIST_HEAD(&link->sibling); + INIT_LIST_HEAD(&link->children); + INIT_LIST_HEAD(&link->link); + link->pdev = pdev; + link->has_switch = pcie_aspm_downstream_has_switch(link); + if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { + struct pcie_link_state *parent; + parent = pdev->bus->parent->self->link_state; + if (!parent) { + kfree(link); + return NULL; + } + link->parent = parent; + list_add(&link->link, &parent->children); + } + list_add(&link->sibling, &link_list); + + pdev->link_state = link; + + /* Check ASPM capability */ + pcie_aspm_cap_init(link, blacklist); + + /* Check Clock PM capability */ + pcie_clkpm_cap_init(link, blacklist); + + return link; +} + /* * pcie_aspm_init_link_state: Initiate PCI express link state. * It is called after the pcie and its children devices are scaned. @@ -597,80 +638,47 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) */ void pcie_aspm_init_link_state(struct pci_dev *pdev) { - unsigned int state; - struct pcie_link_state *link_state; - int error = 0; - int blacklist; + u32 state; + struct pcie_link_state *link; if (aspm_disabled || !pdev->is_pcie || pdev->link_state) return; if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && - pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + /* VIA has a strange chipset, root port is under a bridge */ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && - pdev->bus->self) + pdev->bus->self) return; + down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) 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; - - 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; - } - link_state->pdev = pdev; - link_state->has_switch = pcie_aspm_downstream_has_switch(link_state); - pdev->link_state = link_state; - - if (!blacklist) { - pcie_aspm_configure_common_clock(link_state); - pcie_aspm_cap_init(link_state); + link = pcie_aspm_setup_link_state(pdev); + if (!link) + goto unlock; + /* + * Setup initial ASPM state + * + * 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. + */ + if (link->has_switch) { + state = pcie_aspm_check_state(link, link->aspm_default); + __pcie_aspm_config_link(link, state); } else { - link_state->aspm_enabled = - (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - link_state->aspm_default = 0; - /* Set support state to 0, so we will disable ASPM later */ - link_state->aspm_support = 0; + state = policy_to_aspm_state(link); + __pcie_aspm_configure_link_state(link, state); } - list_add(&link_state->sibling, &link_list); - - if (link_state->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(link_state, - link_state->aspm_default); - __pcie_aspm_config_link(link_state, state); - } else - __pcie_aspm_configure_link_state(link_state, - policy_to_aspm_state(link_state)); - - pcie_check_clock_pm(link_state, blacklist); - -unlock_out: - if (error) - free_link_state(link_state); + /* Setup initial Clock PM state */ + state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; + pcie_set_clock_pm(link, state); +unlock: mutex_unlock(&aspm_lock); out: up_read(&pci_bus_sem); -- cgit v1.2.3-70-g09d2 From f7ea3d7fc03753b08e267fece19c56383e6b856f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:19:00 +0900 Subject: PCI ASPM: cleanup __pcie_aspm_check_state_one Clean up and simplify __pcie_aspm_check_state_one(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 67 ++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 68a4d4b15f9..694ba565775 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -370,56 +370,39 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) } } -static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, - unsigned int state) +/** + * __pcie_aspm_check_state_one - check latency for endpoint device. + * @endpoint: pointer to the struct pci_dev of endpoint device + * + * TBD: The latency from the endpoint to root complex vary per switch's + * upstream link state above the device. Here we just do a simple check + * which assumes all links above the device can be in L1 state, that + * is we just consider the worst case. If switch's upstream link can't + * be put into L0S/L1, then our check is too strictly. + */ +static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state) { - struct pci_dev *parent_dev, *tmp_dev; - unsigned int l1_latency = 0; - struct pcie_link_state *link_state; + u32 l1_switch_latency = 0; struct aspm_latency *acceptable; + struct pcie_link_state *link; - parent_dev = pdev->bus->self; - link_state = parent_dev->link_state; - state &= link_state->aspm_support; - if (state == 0) - return 0; - acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)]; + link = endpoint->bus->self->link_state; + state &= link->aspm_support; + acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; - /* - * Check latency for endpoint device. - * TBD: The latency from the endpoint to root complex vary per - * switch's upstream link state above the device. Here we just do a - * simple check which assumes all links above the device can be in L1 - * state, that is we just consider the worst case. If switch's upstream - * link can't be put into L0S/L1, then our check is too strictly. - */ - tmp_dev = pdev; - while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { - parent_dev = tmp_dev->bus->self; - link_state = parent_dev->link_state; + while (link && state) { if ((state & PCIE_LINK_STATE_L0S) && - (link_state->latency.l0s > acceptable->l0s)) + (link->latency.l0s > acceptable->l0s)) state &= ~PCIE_LINK_STATE_L0S; - if ((state & PCIE_LINK_STATE_L1) && - (link_state->latency.l1 + l1_latency > acceptable->l1)) + (link->latency.l1 + l1_switch_latency > acceptable->l1)) state &= ~PCIE_LINK_STATE_L1; - - if (!parent_dev->bus->self) /* parent_dev is a root port */ - break; - else { - /* - * parent_dev is the downstream port of a switch, make - * tmp_dev the upstream port of the switch - */ - tmp_dev = parent_dev->bus->self; - /* - * every switch on the path to root complex need 1 more - * microsecond for L1. Spec doesn't mention L0S. - */ - if (state & PCIE_LINK_STATE_L1) - l1_latency += 1000; - } + link = link->parent; + /* + * Every switch on the path to root complex need 1 + * more microsecond for L1. Spec doesn't mention L0s. + */ + l1_switch_latency += 1000; } return state; } -- cgit v1.2.3-70-g09d2 From 430842e29d396928989c0a45e05025e988004d79 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:20:10 +0900 Subject: PCI ASPM: cleanup clkpm checks In the current ASPM implementation, callers of pcie_set_clock_pm() check Clock PM capability of the link or current Clock PM state of the link. This check should be done in pcie_set_clock_pm() itself. This patch moves those checks into pcie_set_clock_pm(). It also introduces pcie_set_clkpm_nocheck() that is equivalent to old pcie_set_clock_pm(), for the caller who wants to change Clocl PM state regardless of the Clock PM capability or current Clock PM state. In addition, this patch changes the function name from pcie_set_clock_pm() to pcie_set_clkpm() for consistency. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 694ba565775..0d0d3e63092 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -105,7 +105,7 @@ static int policy_to_clkpm_state(struct pcie_link_state *link) return 0; } -static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) +static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) { int pos; u16 reg16; @@ -126,6 +126,17 @@ static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) link->clkpm_enabled = !!enable; } +static void pcie_set_clkpm(struct pcie_link_state *link, int enable) +{ + /* Don't enable Clock PM if the link is not Clock PM capable */ + if (!link->clkpm_capable && enable) + return; + /* Need nothing if the specified equals to current state */ + if (link->clkpm_enabled == enable) + return; + pcie_set_clkpm_nocheck(link, enable); +} + static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) { int pos, capable = 1, enabled = 1; @@ -660,7 +671,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) /* Setup initial Clock PM state */ state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; - pcie_set_clock_pm(link, state); + pcie_set_clkpm(link, state); unlock: mutex_unlock(&aspm_lock); out: @@ -738,12 +749,11 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) mutex_lock(&aspm_lock); link_state = parent->link_state; link_state->aspm_support &= ~state; - if (state & PCIE_LINK_STATE_CLKPM) - link_state->clkpm_capable = 0; - __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); - if (!link_state->clkpm_capable && link_state->clkpm_enabled) - pcie_set_clock_pm(link_state, 0); + if (state & PCIE_LINK_STATE_CLKPM) { + link_state->clkpm_capable = 0; + pcie_set_clkpm(link_state, 0); + } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } @@ -768,11 +778,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) list_for_each_entry(link_state, &link_list, sibling) { __pcie_aspm_configure_link_state(link_state, policy_to_aspm_state(link_state)); - if (link_state->clkpm_capable && - link_state->clkpm_enabled != policy_to_clkpm_state(link_state)) - pcie_set_clock_pm(link_state, - policy_to_clkpm_state(link_state)); - + pcie_set_clkpm(link_state, policy_to_clkpm_state(link_state)); } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -839,7 +845,7 @@ static ssize_t clk_ctl_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -848,7 +854,7 @@ static ssize_t clk_ctl_store(struct device *dev, down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clock_pm(pci_device->link_state, !!state); + pcie_set_clkpm_nocheck(pdev->link_state, !!state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); -- cgit v1.2.3-70-g09d2 From 7ab709910323a8af20722c066267516b3e7680a2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:20:48 +0900 Subject: PCI ASPM: cleanup pcie_aspm_get_cap_device Minor cleanup for pcie_aspm_get_cap_device(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 0d0d3e63092..d85f77ff150 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -292,19 +292,18 @@ static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) } static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, - unsigned int *l0s, unsigned int *l1, unsigned int *enabled) + u32 *l0s, u32 *l1, u32 *enabled) { int pos; u16 reg16; - u32 reg32; - unsigned int latency; + u32 reg32, latency; *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; if (*state != PCIE_LINK_STATE_L0S && - *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S)) *state = 0; if (*state == 0) return; @@ -316,7 +315,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *l1 = calc_L1_latency(latency, 0); } pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); - *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); + *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); } static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) -- cgit v1.2.3-70-g09d2 From 5e0eaa7d3679c3ef8618803bc9311270e5816641 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:21:48 +0900 Subject: PCI ASPM: cleanup calc_Lx_latency Cleanup for calc_L0S_latency() and calc_L1_latency(). - Separate exit latency and acceptable latency calculation. - Some minor cleanups. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 73 +++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index d85f77ff150..23fabb303e8 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -257,38 +257,36 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg); } -/* - * calc_L0S_latency: Convert L0s latency encoding to ns - */ -static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +/* Convert L0s latency encoding to ns */ +static u32 calc_l0s_latency(u32 encoding) { - unsigned int ns = 64; + if (encoding == 0x7) + return (5 * 1000); /* > 4us */ + return (64 << encoding); +} - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 5*1000; /* > 4us */ - } else - ns *= (1 << latency_encoding); - return ns; +/* Convert L0s acceptable latency encoding to ns */ +static u32 calc_l0s_acceptable(u32 encoding) +{ + if (encoding == 0x7) + return -1U; + return (64 << encoding); } -/* - * calc_L1_latency: Convert L1 latency encoding to ns - */ -static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +/* Convert L1 latency encoding to ns */ +static u32 calc_l1_latency(u32 encoding) { - unsigned int ns = 1000; + if (encoding == 0x7) + return (65 * 1000); /* > 64us */ + return (1000 << encoding); +} - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 65*1000; /* > 64us */ - } else - ns *= (1 << latency_encoding); - return ns; +/* Convert L1 acceptable latency encoding to ns */ +static u32 calc_l1_acceptable(u32 encoding) +{ + if (encoding == 0x7) + return -1U; + return (1000 << encoding); } static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, @@ -296,7 +294,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, { int pos; u16 reg16; - u32 reg32, latency; + u32 reg32, encoding; *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); @@ -308,11 +306,11 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, if (*state == 0) return; - latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; - *l0s = calc_L0S_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_l0s_latency(encoding); if (*state & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; - *l1 = calc_L1_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_l1_latency(encoding); } pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); @@ -358,8 +356,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) /* ENDPOINT states*/ list_for_each_entry(child, &linkbus->devices, bus_list) { int pos; - u32 reg32; - unsigned int latency; + u32 reg32, encoding; struct aspm_latency *acceptable = &link->acceptable[PCI_FUNC(child->devfn)]; @@ -369,13 +366,11 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) pos = pci_find_capability(child, PCI_CAP_ID_EXP); pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); - latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; - latency = calc_L0S_latency(latency, 1); - acceptable->l0s = latency; + encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + acceptable->l0s = calc_l0s_acceptable(encoding); if (link->aspm_support & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; - latency = calc_L1_latency(latency, 1); - acceptable->l1 = latency; + encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + acceptable->l1 = calc_l1_acceptable(encoding); } } } -- cgit v1.2.3-70-g09d2 From efdf8288819df67d608a186f9d17a7d4051f3c1f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:22:26 +0900 Subject: PCI ASPM: remove has_switch field We don't need the 'has_switch' field in the struct pcie_link_state. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 23fabb303e8..26fd39caebc 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -48,8 +48,6 @@ struct pcie_link_state { u32 clkpm_enabled:1; /* Current Clock PM state */ u32 clkpm_default:1; /* Default Clock PM state by BIOS */ - u32 has_switch:1; /* Downstream has switches? */ - /* Latencies */ struct aspm_latency latency; /* Exit latency */ /* @@ -595,7 +593,6 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) INIT_LIST_HEAD(&link->children); INIT_LIST_HEAD(&link->link); link->pdev = pdev; - link->has_switch = pcie_aspm_downstream_has_switch(link); if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { struct pcie_link_state *parent; parent = pdev->bus->parent->self->link_state; @@ -655,7 +652,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * initialization will config the whole hierarchy. But we must * make sure BIOS doesn't set unsupported link state. */ - if (link->has_switch) { + if (pcie_aspm_downstream_has_switch(link)) { state = pcie_aspm_check_state(link, link->aspm_default); __pcie_aspm_config_link(link, state); } else { -- cgit v1.2.3-70-g09d2 From 3647584d9ef35c9ec4abefdbea29959c26c54f13 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:23:09 +0900 Subject: PCI ASPM: cleanup pcie_aspm_sanity_check Minor cleanup for pcie_aspm_sanity_check(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 26fd39caebc..04b6a309850 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -552,27 +552,24 @@ static void free_link_state(struct pcie_link_state *link) static int pcie_aspm_sanity_check(struct pci_dev *pdev) { - struct pci_dev *child_dev; - int child_pos; + struct pci_dev *child; + int pos; u32 reg32; - /* - * Some functions in a slot might not all be PCIE functions, very - * strange. Disable ASPM for the whole slot + * Some functions in a slot might not all be PCIE functions, + * very strange. Disable ASPM for the whole slot */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - if (!child_pos) + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + if (!pos) return -EINVAL; - /* * Disable ASPM for pre-1.1 PCIe device, we follow MS to use * RBER bit to determine if a function is 1.1 version device */ - pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, - ®32); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) { - dev_printk(KERN_INFO, &child_dev->dev, "disabling ASPM" + dev_printk(KERN_INFO, &child->dev, "disabling ASPM" " on pre-1.1 PCIe device. You can enable it" " with 'pcie_aspm=force'\n"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From 5c92ffb1ecc7f13267cdef5dda8a838937912c93 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:23:57 +0900 Subject: PCI ASPM: remove get_root_port_link By having a pointer to the root port link, we can remove loops in get_root_port_link() to search the root port link. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/pci/pcie/aspm.c') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 04b6a309850..3d27c97e048 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -33,6 +33,7 @@ struct aspm_latency { struct pcie_link_state { struct pci_dev *pdev; /* Upstream component of the Link */ + struct pcie_link_state *root; /* pointer to the root port link */ struct pcie_link_state *parent; /* pointer to the parent Link state */ struct list_head sibling; /* node in link_list */ struct list_head children; /* list of child link states */ @@ -486,26 +487,17 @@ static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) link->aspm_enabled = 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 pcie_link_state *link, u32 state) { - struct pcie_link_state *leaf, *root = get_root_port_link(link); + struct pcie_link_state *leaf, *root = link->root; state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); /* Check all links who have specific root port link */ list_for_each_entry(leaf, &link_list, sibling) { - if (!list_empty(&leaf->children) || - get_root_port_link(leaf) != root) + if (!list_empty(&leaf->children) || (leaf->root != root)) continue; state = pcie_aspm_check_state(leaf, state); } @@ -519,12 +511,12 @@ static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, **/ if (state & PCIE_LINK_STATE_L1) { list_for_each_entry(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root) + if (leaf->root == root) __pcie_aspm_config_link(leaf, state); } } else { list_for_each_entry_reverse(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root) + if (leaf->root == root) __pcie_aspm_config_link(leaf, state); } } @@ -600,6 +592,12 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) link->parent = parent; list_add(&link->link, &parent->children); } + /* Setup a pointer to the root port link */ + if (!link->parent) + link->root = link; + else + link->root = link->parent->root; + list_add(&link->sibling, &link_list); pdev->link_state = link; -- cgit v1.2.3-70-g09d2