diff options
| author | Paul Mackerras <paulus@samba.org> | 2008-12-15 22:38:58 -0500 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2008-12-15 22:38:58 -0500 |
| commit | 1e1c568d6c66d1e2e345fd15e2a1ceafc5d7e33a (patch) | |
| tree | 0cf88547108a750d6eb910564ef5bf0ffb5ceef3 /drivers/pci/pcie/aspm.c | |
| parent | 91cac623262c1c0cd298c5c648a8bd2b647c264d (diff) | |
| parent | 23e0e8afafd9ac065d81506524adf3339584044b (diff) | |
Merge branch 'merge' into next
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 8f63f4c6b85f..9aad608bcf3f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/jiffies.h> | ||
| 19 | #include <linux/pci-aspm.h> | 20 | #include <linux/pci-aspm.h> |
| 20 | #include "../pci.h" | 21 | #include "../pci.h" |
| 21 | 22 | ||
| @@ -161,11 +162,12 @@ static void pcie_check_clock_pm(struct pci_dev *pdev) | |||
| 161 | */ | 162 | */ |
| 162 | static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) | 163 | static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) |
| 163 | { | 164 | { |
| 164 | int pos, child_pos; | 165 | int pos, child_pos, i = 0; |
| 165 | u16 reg16 = 0; | 166 | u16 reg16 = 0; |
| 166 | struct pci_dev *child_dev; | 167 | struct pci_dev *child_dev; |
| 167 | int same_clock = 1; | 168 | int same_clock = 1; |
| 168 | 169 | unsigned long start_jiffies; | |
| 170 | u16 child_regs[8], parent_reg; | ||
| 169 | /* | 171 | /* |
| 170 | * all functions of a slot should have the same Slot Clock | 172 | * all functions of a slot should have the same Slot Clock |
| 171 | * Configuration, so just check one function | 173 | * Configuration, so just check one function |
| @@ -191,16 +193,19 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) | |||
| 191 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); | 193 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); |
| 192 | pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, | 194 | pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, |
| 193 | ®16); | 195 | ®16); |
| 196 | child_regs[i] = reg16; | ||
| 194 | if (same_clock) | 197 | if (same_clock) |
| 195 | reg16 |= PCI_EXP_LNKCTL_CCC; | 198 | reg16 |= PCI_EXP_LNKCTL_CCC; |
| 196 | else | 199 | else |
| 197 | reg16 &= ~PCI_EXP_LNKCTL_CCC; | 200 | reg16 &= ~PCI_EXP_LNKCTL_CCC; |
| 198 | pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, | 201 | pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, |
| 199 | reg16); | 202 | reg16); |
| 203 | i++; | ||
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | /* Configure upstream component */ | 206 | /* Configure upstream component */ |
| 203 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); | 207 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); |
| 208 | parent_reg = reg16; | ||
| 204 | if (same_clock) | 209 | if (same_clock) |
| 205 | reg16 |= PCI_EXP_LNKCTL_CCC; | 210 | reg16 |= PCI_EXP_LNKCTL_CCC; |
| 206 | else | 211 | else |
| @@ -212,12 +217,30 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) | |||
| 212 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); | 217 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); |
| 213 | 218 | ||
| 214 | /* Wait for link training end */ | 219 | /* Wait for link training end */ |
| 215 | while (1) { | 220 | /* break out after waiting for 1 second */ |
| 221 | start_jiffies = jiffies; | ||
| 222 | while ((jiffies - start_jiffies) < HZ) { | ||
| 216 | pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); | 223 | pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); |
| 217 | if (!(reg16 & PCI_EXP_LNKSTA_LT)) | 224 | if (!(reg16 & PCI_EXP_LNKSTA_LT)) |
| 218 | break; | 225 | break; |
| 219 | cpu_relax(); | 226 | cpu_relax(); |
| 220 | } | 227 | } |
| 228 | /* training failed -> recover */ | ||
| 229 | if ((jiffies - start_jiffies) >= HZ) { | ||
| 230 | dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" | ||
| 231 | " common clock\n"); | ||
| 232 | i = 0; | ||
| 233 | list_for_each_entry(child_dev, &pdev->subordinate->devices, | ||
| 234 | bus_list) { | ||
| 235 | child_pos = pci_find_capability(child_dev, | ||
| 236 | PCI_CAP_ID_EXP); | ||
| 237 | pci_write_config_word(child_dev, | ||
| 238 | child_pos + PCI_EXP_LNKCTL, | ||
| 239 | child_regs[i]); | ||
| 240 | i++; | ||
| 241 | } | ||
| 242 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); | ||
| 243 | } | ||
| 221 | } | 244 | } |
| 222 | 245 | ||
| 223 | /* | 246 | /* |
