diff options
author | Ray Jui <rjui@broadcom.com> | 2015-09-15 20:39:19 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-09-25 19:19:40 -0400 |
commit | aaf22ab4e916afa68a2e1aed4e913b76cbd58276 (patch) | |
tree | a8919fe24159c70010e73b7178bb23bd92438cac | |
parent | 199ff14100095d52cd1b232cc0f3b12f348b5b07 (diff) |
PCI: iproc: Improve link detection logic
Improve the link detection logic by explicitly querying the link status
register to ensure link is active.
Also force class to PCI_CLASS_BRIDGE_PCI (0x0604) through the host
configuration space register.
Signed-off-by: Ray Jui <rjui@broadcom.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Anup Patel <anup.patel@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
-rw-r--r-- | drivers/pci/host/pcie-iproc.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 80e0541548a1..62e80855aed1 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c | |||
@@ -60,6 +60,12 @@ | |||
60 | #define SYS_RC_INTX_EN 0x330 | 60 | #define SYS_RC_INTX_EN 0x330 |
61 | #define SYS_RC_INTX_MASK 0xf | 61 | #define SYS_RC_INTX_MASK 0xf |
62 | 62 | ||
63 | #define PCIE_LINK_STATUS_OFFSET 0xf0c | ||
64 | #define PCIE_PHYLINKUP_SHIFT 3 | ||
65 | #define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT) | ||
66 | #define PCIE_DL_ACTIVE_SHIFT 2 | ||
67 | #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT) | ||
68 | |||
63 | static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) | 69 | static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) |
64 | { | 70 | { |
65 | struct iproc_pcie *pcie; | 71 | struct iproc_pcie *pcie; |
@@ -138,9 +144,15 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) | |||
138 | static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) | 144 | static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) |
139 | { | 145 | { |
140 | u8 hdr_type; | 146 | u8 hdr_type; |
141 | u32 link_ctrl; | 147 | u32 link_ctrl, class, val; |
142 | u16 pos, link_status; | 148 | u16 pos, link_status; |
143 | int link_is_active = 0; | 149 | bool link_is_active = false; |
150 | |||
151 | val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET); | ||
152 | if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { | ||
153 | dev_err(pcie->dev, "PHY or data link is INACTIVE!\n"); | ||
154 | return -ENODEV; | ||
155 | } | ||
144 | 156 | ||
145 | /* make sure we are not in EP mode */ | 157 | /* make sure we are not in EP mode */ |
146 | pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type); | 158 | pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type); |
@@ -150,14 +162,19 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) | |||
150 | } | 162 | } |
151 | 163 | ||
152 | /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */ | 164 | /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */ |
153 | pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE, | 165 | #define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c |
154 | PCI_CLASS_BRIDGE_PCI); | 166 | #define PCI_CLASS_BRIDGE_MASK 0xffff00 |
167 | #define PCI_CLASS_BRIDGE_SHIFT 8 | ||
168 | pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class); | ||
169 | class &= ~PCI_CLASS_BRIDGE_MASK; | ||
170 | class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT); | ||
171 | pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class); | ||
155 | 172 | ||
156 | /* check link status to see if link is active */ | 173 | /* check link status to see if link is active */ |
157 | pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); | 174 | pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); |
158 | pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); | 175 | pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); |
159 | if (link_status & PCI_EXP_LNKSTA_NLW) | 176 | if (link_status & PCI_EXP_LNKSTA_NLW) |
160 | link_is_active = 1; | 177 | link_is_active = true; |
161 | 178 | ||
162 | if (!link_is_active) { | 179 | if (!link_is_active) { |
163 | /* try GEN 1 link speed */ | 180 | /* try GEN 1 link speed */ |
@@ -181,7 +198,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) | |||
181 | pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, | 198 | pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, |
182 | &link_status); | 199 | &link_status); |
183 | if (link_status & PCI_EXP_LNKSTA_NLW) | 200 | if (link_status & PCI_EXP_LNKSTA_NLW) |
184 | link_is_active = 1; | 201 | link_is_active = true; |
185 | } | 202 | } |
186 | } | 203 | } |
187 | 204 | ||