]>
Commit | Line | Data |
---|---|---|
736759ef | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1da177e4 LT |
2 | /* |
3 | * PCI Express PCI Hot Plug Driver | |
4 | * | |
5 | * Copyright (C) 1995,2001 Compaq Computer Corporation | |
6 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | |
7 | * Copyright (C) 2001 IBM Corp. | |
8 | * Copyright (C) 2003-2004 Intel Corporation | |
9 | * | |
10 | * All rights reserved. | |
11 | * | |
8cf4c195 | 12 | * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> |
1da177e4 LT |
13 | */ |
14 | ||
1da177e4 | 15 | #include <linux/kernel.h> |
1da177e4 | 16 | #include <linux/types.h> |
de25968c | 17 | #include <linux/jiffies.h> |
ec07a447 | 18 | #include <linux/kthread.h> |
1da177e4 | 19 | #include <linux/pci.h> |
6b08c385 | 20 | #include <linux/pm_runtime.h> |
5d1b8c9e | 21 | #include <linux/interrupt.h> |
5a0e3ad6 | 22 | #include <linux/slab.h> |
5d1b8c9e | 23 | |
1da177e4 LT |
24 | #include "../pci.h" |
25 | #include "pciehp.h" | |
1da177e4 | 26 | |
cd84d340 | 27 | static inline struct pci_dev *ctrl_dev(struct controller *ctrl) |
a0f018da | 28 | { |
cd84d340 | 29 | return ctrl->pcie->port; |
a0f018da | 30 | } |
1da177e4 | 31 | |
7b4ce26b LW |
32 | static irqreturn_t pciehp_isr(int irq, void *dev_id); |
33 | static irqreturn_t pciehp_ist(int irq, void *dev_id); | |
ec07a447 | 34 | static int pciehp_poll(void *data); |
1da177e4 | 35 | |
2aeeef11 KK |
36 | static inline int pciehp_request_irq(struct controller *ctrl) |
37 | { | |
f7a10e32 | 38 | int retval, irq = ctrl->pcie->irq; |
2aeeef11 | 39 | |
2aeeef11 | 40 | if (pciehp_poll_mode) { |
ec07a447 LW |
41 | ctrl->poll_thread = kthread_run(&pciehp_poll, ctrl, |
42 | "pciehp_poll-%s", | |
43 | slot_name(ctrl->slot)); | |
44 | return PTR_ERR_OR_ZERO(ctrl->poll_thread); | |
2aeeef11 KK |
45 | } |
46 | ||
47 | /* Installs the interrupt handler */ | |
7b4ce26b LW |
48 | retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist, |
49 | IRQF_SHARED, MY_NAME, ctrl); | |
2aeeef11 | 50 | if (retval) |
7f2feec1 TI |
51 | ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", |
52 | irq); | |
2aeeef11 KK |
53 | return retval; |
54 | } | |
55 | ||
56 | static inline void pciehp_free_irq(struct controller *ctrl) | |
57 | { | |
58 | if (pciehp_poll_mode) | |
ec07a447 | 59 | kthread_stop(ctrl->poll_thread); |
2aeeef11 | 60 | else |
f7a10e32 | 61 | free_irq(ctrl->pcie->irq, ctrl); |
2aeeef11 KK |
62 | } |
63 | ||
40b96083 | 64 | static int pcie_poll_cmd(struct controller *ctrl, int timeout) |
6592e02a | 65 | { |
cd84d340 | 66 | struct pci_dev *pdev = ctrl_dev(ctrl); |
6592e02a | 67 | u16 slot_status; |
6592e02a | 68 | |
ac10836b | 69 | while (true) { |
1a84b99c | 70 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
1469d17d JW |
71 | if (slot_status == (u16) ~0) { |
72 | ctrl_info(ctrl, "%s: no response from device\n", | |
73 | __func__); | |
74 | return 0; | |
75 | } | |
76 | ||
1a84b99c | 77 | if (slot_status & PCI_EXP_SLTSTA_CC) { |
cd84d340 BH |
78 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
79 | PCI_EXP_SLTSTA_CC); | |
322162a7 | 80 | return 1; |
820943b6 | 81 | } |
ac10836b YW |
82 | if (timeout < 0) |
83 | break; | |
84 | msleep(10); | |
85 | timeout -= 10; | |
6592e02a KK |
86 | } |
87 | return 0; /* timeout */ | |
6592e02a KK |
88 | } |
89 | ||
4283c70e | 90 | static void pcie_wait_cmd(struct controller *ctrl) |
44ef4cef | 91 | { |
262303fe | 92 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; |
40b96083 BH |
93 | unsigned long duration = msecs_to_jiffies(msecs); |
94 | unsigned long cmd_timeout = ctrl->cmd_started + duration; | |
95 | unsigned long now, timeout; | |
262303fe KK |
96 | int rc; |
97 | ||
4283c70e BH |
98 | /* |
99 | * If the controller does not generate notifications for command | |
100 | * completions, we never need to wait between writes. | |
101 | */ | |
6c1a32e0 | 102 | if (NO_CMD_CMPL(ctrl)) |
4283c70e BH |
103 | return; |
104 | ||
105 | if (!ctrl->cmd_busy) | |
106 | return; | |
107 | ||
40b96083 BH |
108 | /* |
109 | * Even if the command has already timed out, we want to call | |
110 | * pcie_poll_cmd() so it can clear PCI_EXP_SLTSTA_CC. | |
111 | */ | |
112 | now = jiffies; | |
113 | if (time_before_eq(cmd_timeout, now)) | |
114 | timeout = 1; | |
115 | else | |
116 | timeout = cmd_timeout - now; | |
117 | ||
4283c70e BH |
118 | if (ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE && |
119 | ctrl->slot_ctrl & PCI_EXP_SLTCTL_CCIE) | |
d737bdc1 | 120 | rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); |
4283c70e | 121 | else |
7cbeb9f9 | 122 | rc = pcie_poll_cmd(ctrl, jiffies_to_msecs(timeout)); |
40b96083 | 123 | |
262303fe | 124 | if (!rc) |
d537a3ab | 125 | ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n", |
40b96083 | 126 | ctrl->slot_ctrl, |
d433889c | 127 | jiffies_to_msecs(jiffies - ctrl->cmd_started)); |
44ef4cef KK |
128 | } |
129 | ||
d22b3621 BH |
130 | #define CC_ERRATUM_MASK (PCI_EXP_SLTCTL_PCC | \ |
131 | PCI_EXP_SLTCTL_PIC | \ | |
132 | PCI_EXP_SLTCTL_AIC | \ | |
133 | PCI_EXP_SLTCTL_EIC) | |
134 | ||
a5dd4b4b AW |
135 | static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, |
136 | u16 mask, bool wait) | |
1da177e4 | 137 | { |
cd84d340 | 138 | struct pci_dev *pdev = ctrl_dev(ctrl); |
d22b3621 | 139 | u16 slot_ctrl_orig, slot_ctrl; |
1da177e4 | 140 | |
44ef4cef KK |
141 | mutex_lock(&ctrl->ctrl_lock); |
142 | ||
a5dd4b4b AW |
143 | /* |
144 | * Always wait for any previous command that might still be in progress | |
145 | */ | |
3461a068 BH |
146 | pcie_wait_cmd(ctrl); |
147 | ||
1a84b99c | 148 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
1469d17d JW |
149 | if (slot_ctrl == (u16) ~0) { |
150 | ctrl_info(ctrl, "%s: no response from device\n", __func__); | |
151 | goto out; | |
152 | } | |
153 | ||
d22b3621 | 154 | slot_ctrl_orig = slot_ctrl; |
f4778364 | 155 | slot_ctrl &= ~mask; |
b7aa1f16 | 156 | slot_ctrl |= (cmd & mask); |
f4778364 | 157 | ctrl->cmd_busy = 1; |
2d32a9ae | 158 | smp_mb(); |
1a84b99c | 159 | pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); |
40b96083 | 160 | ctrl->cmd_started = jiffies; |
4283c70e | 161 | ctrl->slot_ctrl = slot_ctrl; |
f4778364 | 162 | |
d22b3621 BH |
163 | /* |
164 | * Controllers with the Intel CF118 and similar errata advertise | |
165 | * Command Completed support, but they only set Command Completed | |
166 | * if we change the "Control" bits for power, power indicator, | |
167 | * attention indicator, or interlock. If we only change the | |
168 | * "Enable" bits, they never set the Command Completed bit. | |
169 | */ | |
170 | if (pdev->broken_cmd_compl && | |
171 | (slot_ctrl_orig & CC_ERRATUM_MASK) == (slot_ctrl & CC_ERRATUM_MASK)) | |
172 | ctrl->cmd_busy = 0; | |
173 | ||
a5dd4b4b AW |
174 | /* |
175 | * Optionally wait for the hardware to be ready for a new command, | |
176 | * indicating completion of the above issued command. | |
177 | */ | |
178 | if (wait) | |
179 | pcie_wait_cmd(ctrl); | |
180 | ||
1469d17d | 181 | out: |
44ef4cef | 182 | mutex_unlock(&ctrl->ctrl_lock); |
1da177e4 LT |
183 | } |
184 | ||
a5dd4b4b AW |
185 | /** |
186 | * pcie_write_cmd - Issue controller command | |
187 | * @ctrl: controller to which the command is issued | |
188 | * @cmd: command value written to slot control register | |
189 | * @mask: bitmask of slot control register to be modified | |
190 | */ | |
191 | static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |
192 | { | |
193 | pcie_do_write_cmd(ctrl, cmd, mask, true); | |
194 | } | |
195 | ||
196 | /* Same as above without waiting for the hardware to latch */ | |
197 | static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask) | |
198 | { | |
199 | pcie_do_write_cmd(ctrl, cmd, mask, false); | |
200 | } | |
201 | ||
4703389f | 202 | bool pciehp_check_link_active(struct controller *ctrl) |
f18e9625 | 203 | { |
cd84d340 | 204 | struct pci_dev *pdev = ctrl_dev(ctrl); |
4e2ce405 | 205 | u16 lnk_status; |
1a84b99c | 206 | bool ret; |
f18e9625 | 207 | |
1a84b99c | 208 | pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); |
4e2ce405 YL |
209 | ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); |
210 | ||
211 | if (ret) | |
212 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); | |
213 | ||
214 | return ret; | |
f18e9625 KK |
215 | } |
216 | ||
bffe4f72 YL |
217 | static void pcie_wait_link_active(struct controller *ctrl) |
218 | { | |
9f5a70f1 OP |
219 | struct pci_dev *pdev = ctrl_dev(ctrl); |
220 | ||
221 | pcie_wait_for_link(pdev, true); | |
bffe4f72 YL |
222 | } |
223 | ||
2f5d8e4f YL |
224 | static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) |
225 | { | |
226 | u32 l; | |
227 | int count = 0; | |
228 | int delay = 1000, step = 20; | |
229 | bool found = false; | |
230 | ||
231 | do { | |
232 | found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0); | |
233 | count++; | |
234 | ||
235 | if (found) | |
236 | break; | |
237 | ||
238 | msleep(step); | |
239 | delay -= step; | |
240 | } while (delay > 0); | |
241 | ||
242 | if (count > 1 && pciehp_debug) | |
243 | printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", | |
244 | pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), | |
245 | PCI_FUNC(devfn), count, step, l); | |
246 | ||
247 | return found; | |
248 | } | |
249 | ||
82a9e79e | 250 | int pciehp_check_link_status(struct controller *ctrl) |
1da177e4 | 251 | { |
cd84d340 | 252 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1a84b99c | 253 | bool found; |
1da177e4 | 254 | u16 lnk_status; |
1da177e4 | 255 | |
3c78bc61 RD |
256 | /* |
257 | * Data Link Layer Link Active Reporting must be capable for | |
258 | * hot-plug capable downstream port. But old controller might | |
259 | * not implement it. In this case, we wait for 1000 ms. | |
260 | */ | |
261 | if (ctrl->link_active_reporting) | |
262 | pcie_wait_link_active(ctrl); | |
263 | else | |
264 | msleep(1000); | |
f18e9625 | 265 | |
2f5d8e4f YL |
266 | /* wait 100ms before read pci conf, and try in 1s */ |
267 | msleep(100); | |
268 | found = pci_bus_check_dev(ctrl->pcie->port->subordinate, | |
269 | PCI_DEVFN(0, 0)); | |
0027cb3e | 270 | |
6c35a1ac LW |
271 | /* ignore link or presence changes up to this point */ |
272 | if (found) | |
273 | atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC), | |
274 | &ctrl->pending_events); | |
275 | ||
1a84b99c | 276 | pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); |
7f2feec1 | 277 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
322162a7 KK |
278 | if ((lnk_status & PCI_EXP_LNKSTA_LT) || |
279 | !(lnk_status & PCI_EXP_LNKSTA_NLW)) { | |
3784e0c6 BH |
280 | ctrl_err(ctrl, "link training error: status %#06x\n", |
281 | lnk_status); | |
1a84b99c | 282 | return -1; |
1da177e4 LT |
283 | } |
284 | ||
fdbd3ce9 YL |
285 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); |
286 | ||
1a84b99c BH |
287 | if (!found) |
288 | return -1; | |
2f5d8e4f | 289 | |
1a84b99c | 290 | return 0; |
1da177e4 LT |
291 | } |
292 | ||
7f822999 YL |
293 | static int __pciehp_link_set(struct controller *ctrl, bool enable) |
294 | { | |
cd84d340 | 295 | struct pci_dev *pdev = ctrl_dev(ctrl); |
7f822999 | 296 | u16 lnk_ctrl; |
7f822999 | 297 | |
1a84b99c | 298 | pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); |
7f822999 YL |
299 | |
300 | if (enable) | |
301 | lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; | |
302 | else | |
303 | lnk_ctrl |= PCI_EXP_LNKCTL_LD; | |
304 | ||
1a84b99c | 305 | pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); |
7f822999 | 306 | ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); |
1a84b99c | 307 | return 0; |
7f822999 YL |
308 | } |
309 | ||
310 | static int pciehp_link_enable(struct controller *ctrl) | |
311 | { | |
312 | return __pciehp_link_set(ctrl, true); | |
313 | } | |
314 | ||
576243b3 KB |
315 | int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
316 | u8 *status) | |
317 | { | |
318 | struct slot *slot = hotplug_slot->private; | |
319 | struct pci_dev *pdev = ctrl_dev(slot->ctrl); | |
320 | u16 slot_ctrl; | |
321 | ||
4417aa45 | 322 | pci_config_pm_runtime_get(pdev); |
576243b3 | 323 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
4417aa45 | 324 | pci_config_pm_runtime_put(pdev); |
576243b3 KB |
325 | *status = (slot_ctrl & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6; |
326 | return 0; | |
327 | } | |
328 | ||
eee6e273 | 329 | int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) |
1da177e4 | 330 | { |
eee6e273 | 331 | struct slot *slot = hotplug_slot->private; |
48fe3915 | 332 | struct controller *ctrl = slot->ctrl; |
cd84d340 | 333 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 334 | u16 slot_ctrl; |
1da177e4 | 335 | |
4417aa45 | 336 | pci_config_pm_runtime_get(pdev); |
1a84b99c | 337 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
4417aa45 | 338 | pci_config_pm_runtime_put(pdev); |
1518c17a KK |
339 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, |
340 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); | |
1da177e4 | 341 | |
e7b4f0d7 BH |
342 | switch (slot_ctrl & PCI_EXP_SLTCTL_AIC) { |
343 | case PCI_EXP_SLTCTL_ATTN_IND_ON: | |
1da177e4 LT |
344 | *status = 1; /* On */ |
345 | break; | |
e7b4f0d7 | 346 | case PCI_EXP_SLTCTL_ATTN_IND_BLINK: |
1da177e4 LT |
347 | *status = 2; /* Blink */ |
348 | break; | |
e7b4f0d7 | 349 | case PCI_EXP_SLTCTL_ATTN_IND_OFF: |
1da177e4 LT |
350 | *status = 0; /* Off */ |
351 | break; | |
352 | default: | |
353 | *status = 0xFF; | |
354 | break; | |
355 | } | |
eee6e273 LW |
356 | |
357 | return 0; | |
1da177e4 LT |
358 | } |
359 | ||
6dae6202 | 360 | void pciehp_get_power_status(struct slot *slot, u8 *status) |
1da177e4 | 361 | { |
48fe3915 | 362 | struct controller *ctrl = slot->ctrl; |
cd84d340 | 363 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 364 | u16 slot_ctrl; |
1da177e4 | 365 | |
1a84b99c | 366 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
1518c17a KK |
367 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, |
368 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); | |
1da177e4 | 369 | |
e7b4f0d7 BH |
370 | switch (slot_ctrl & PCI_EXP_SLTCTL_PCC) { |
371 | case PCI_EXP_SLTCTL_PWR_ON: | |
372 | *status = 1; /* On */ | |
1da177e4 | 373 | break; |
e7b4f0d7 BH |
374 | case PCI_EXP_SLTCTL_PWR_OFF: |
375 | *status = 0; /* Off */ | |
1da177e4 LT |
376 | break; |
377 | default: | |
378 | *status = 0xFF; | |
379 | break; | |
380 | } | |
1da177e4 LT |
381 | } |
382 | ||
6dae6202 | 383 | void pciehp_get_latch_status(struct slot *slot, u8 *status) |
1da177e4 | 384 | { |
1a84b99c | 385 | struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
1da177e4 | 386 | u16 slot_status; |
1da177e4 | 387 | |
1a84b99c | 388 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
322162a7 | 389 | *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); |
1da177e4 LT |
390 | } |
391 | ||
6dae6202 | 392 | void pciehp_get_adapter_status(struct slot *slot, u8 *status) |
1da177e4 | 393 | { |
1a84b99c | 394 | struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
1da177e4 | 395 | u16 slot_status; |
1da177e4 | 396 | |
1a84b99c | 397 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
322162a7 | 398 | *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); |
1da177e4 LT |
399 | } |
400 | ||
82a9e79e | 401 | int pciehp_query_power_fault(struct slot *slot) |
1da177e4 | 402 | { |
1a84b99c | 403 | struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
1da177e4 | 404 | u16 slot_status; |
1da177e4 | 405 | |
1a84b99c | 406 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
322162a7 | 407 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); |
1da177e4 LT |
408 | } |
409 | ||
576243b3 KB |
410 | int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
411 | u8 status) | |
412 | { | |
413 | struct slot *slot = hotplug_slot->private; | |
414 | struct controller *ctrl = slot->ctrl; | |
4417aa45 | 415 | struct pci_dev *pdev = ctrl_dev(ctrl); |
576243b3 | 416 | |
4417aa45 | 417 | pci_config_pm_runtime_get(pdev); |
576243b3 KB |
418 | pcie_write_cmd_nowait(ctrl, status << 6, |
419 | PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC); | |
4417aa45 | 420 | pci_config_pm_runtime_put(pdev); |
576243b3 KB |
421 | return 0; |
422 | } | |
423 | ||
6dae6202 | 424 | void pciehp_set_attention_status(struct slot *slot, u8 value) |
1da177e4 | 425 | { |
48fe3915 | 426 | struct controller *ctrl = slot->ctrl; |
f4778364 | 427 | u16 slot_cmd; |
1da177e4 | 428 | |
af9ab791 BH |
429 | if (!ATTN_LED(ctrl)) |
430 | return; | |
431 | ||
1da177e4 | 432 | switch (value) { |
3c78bc61 | 433 | case 0: /* turn off */ |
e7b4f0d7 | 434 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF; |
445f7985 KK |
435 | break; |
436 | case 1: /* turn on */ | |
e7b4f0d7 | 437 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON; |
445f7985 KK |
438 | break; |
439 | case 2: /* turn blink */ | |
e7b4f0d7 | 440 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK; |
445f7985 KK |
441 | break; |
442 | default: | |
6dae6202 | 443 | return; |
1da177e4 | 444 | } |
a5dd4b4b | 445 | pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); |
1518c17a KK |
446 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
447 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); | |
1da177e4 LT |
448 | } |
449 | ||
82a9e79e | 450 | void pciehp_green_led_on(struct slot *slot) |
1da177e4 | 451 | { |
48fe3915 | 452 | struct controller *ctrl = slot->ctrl; |
71ad556d | 453 | |
af9ab791 BH |
454 | if (!PWR_LED(ctrl)) |
455 | return; | |
456 | ||
a5dd4b4b AW |
457 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, |
458 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 459 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
460 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
461 | PCI_EXP_SLTCTL_PWR_IND_ON); | |
1da177e4 LT |
462 | } |
463 | ||
82a9e79e | 464 | void pciehp_green_led_off(struct slot *slot) |
1da177e4 | 465 | { |
48fe3915 | 466 | struct controller *ctrl = slot->ctrl; |
1da177e4 | 467 | |
af9ab791 BH |
468 | if (!PWR_LED(ctrl)) |
469 | return; | |
470 | ||
a5dd4b4b AW |
471 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, |
472 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 473 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
474 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
475 | PCI_EXP_SLTCTL_PWR_IND_OFF); | |
1da177e4 LT |
476 | } |
477 | ||
82a9e79e | 478 | void pciehp_green_led_blink(struct slot *slot) |
1da177e4 | 479 | { |
48fe3915 | 480 | struct controller *ctrl = slot->ctrl; |
71ad556d | 481 | |
af9ab791 BH |
482 | if (!PWR_LED(ctrl)) |
483 | return; | |
484 | ||
a5dd4b4b AW |
485 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, |
486 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 487 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
488 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
489 | PCI_EXP_SLTCTL_PWR_IND_BLINK); | |
1da177e4 LT |
490 | } |
491 | ||
3c78bc61 | 492 | int pciehp_power_on_slot(struct slot *slot) |
1da177e4 | 493 | { |
48fe3915 | 494 | struct controller *ctrl = slot->ctrl; |
cd84d340 | 495 | struct pci_dev *pdev = ctrl_dev(ctrl); |
f4778364 | 496 | u16 slot_status; |
1a84b99c | 497 | int retval; |
1da177e4 | 498 | |
34fb6bf9 | 499 | /* Clear power-fault bit from previous power failures */ |
1a84b99c | 500 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
2f2ed41c BH |
501 | if (slot_status & PCI_EXP_SLTSTA_PFD) |
502 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, | |
503 | PCI_EXP_SLTSTA_PFD); | |
5651c48c | 504 | ctrl->power_fault_detected = 0; |
1da177e4 | 505 | |
e7b4f0d7 | 506 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC); |
1518c17a | 507 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
508 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
509 | PCI_EXP_SLTCTL_PWR_ON); | |
1da177e4 | 510 | |
2debd928 YL |
511 | retval = pciehp_link_enable(ctrl); |
512 | if (retval) | |
513 | ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__); | |
514 | ||
1da177e4 LT |
515 | return retval; |
516 | } | |
517 | ||
3c78bc61 | 518 | void pciehp_power_off_slot(struct slot *slot) |
1da177e4 | 519 | { |
48fe3915 | 520 | struct controller *ctrl = slot->ctrl; |
f1050a35 | 521 | |
e7b4f0d7 | 522 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); |
1518c17a | 523 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
524 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
525 | PCI_EXP_SLTCTL_PWR_OFF); | |
1da177e4 LT |
526 | } |
527 | ||
fad214b0 | 528 | static irqreturn_t pciehp_isr(int irq, void *dev_id) |
1da177e4 | 529 | { |
48fe3915 | 530 | struct controller *ctrl = (struct controller *)dev_id; |
cd84d340 | 531 | struct pci_dev *pdev = ctrl_dev(ctrl); |
6b08c385 | 532 | struct device *parent = pdev->dev.parent; |
a8499f20 | 533 | u16 status, events; |
1da177e4 | 534 | |
7b4ce26b LW |
535 | /* |
536 | * Interrupts only occur in D3hot or shallower (PCIe r4.0, sec 6.7.3.4). | |
537 | */ | |
ed91de7e LW |
538 | if (pdev->current_state == PCI_D3cold) |
539 | return IRQ_NONE; | |
540 | ||
6b08c385 LW |
541 | /* |
542 | * Keep the port accessible by holding a runtime PM ref on its parent. | |
543 | * Defer resume of the parent to the IRQ thread if it's suspended. | |
544 | * Mask the interrupt until then. | |
545 | */ | |
546 | if (parent) { | |
547 | pm_runtime_get_noresume(parent); | |
548 | if (!pm_runtime_active(parent)) { | |
549 | pm_runtime_put(parent); | |
550 | disable_irq_nosync(irq); | |
551 | atomic_or(RERUN_ISR, &ctrl->pending_events); | |
552 | return IRQ_WAKE_THREAD; | |
553 | } | |
554 | } | |
555 | ||
fad214b0 MP |
556 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status); |
557 | if (status == (u16) ~0) { | |
558 | ctrl_info(ctrl, "%s: no response from device\n", __func__); | |
6b08c385 LW |
559 | if (parent) |
560 | pm_runtime_put(parent); | |
fad214b0 MP |
561 | return IRQ_NONE; |
562 | } | |
563 | ||
c6b069e9 | 564 | /* |
fad214b0 MP |
565 | * Slot Status contains plain status bits as well as event |
566 | * notification bits; right now we only want the event bits. | |
c6b069e9 | 567 | */ |
fad214b0 | 568 | events = status & (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | |
a8499f20 BH |
569 | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC | |
570 | PCI_EXP_SLTSTA_DLLSC); | |
7612b3b2 KB |
571 | |
572 | /* | |
573 | * If we've already reported a power fault, don't report it again | |
574 | * until we've done something to handle it. | |
575 | */ | |
576 | if (ctrl->power_fault_detected) | |
577 | events &= ~PCI_EXP_SLTSTA_PFD; | |
578 | ||
6b08c385 LW |
579 | if (!events) { |
580 | if (parent) | |
581 | pm_runtime_put(parent); | |
fad214b0 | 582 | return IRQ_NONE; |
6b08c385 | 583 | } |
71ad556d | 584 | |
fad214b0 | 585 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events); |
a8499f20 | 586 | ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events); |
6b08c385 LW |
587 | if (parent) |
588 | pm_runtime_put(parent); | |
71ad556d | 589 | |
7b4ce26b LW |
590 | /* |
591 | * Command Completed notifications are not deferred to the | |
592 | * IRQ thread because it may be waiting for their arrival. | |
593 | */ | |
a8499f20 | 594 | if (events & PCI_EXP_SLTSTA_CC) { |
262303fe | 595 | ctrl->cmd_busy = 0; |
2d32a9ae | 596 | smp_mb(); |
d737bdc1 | 597 | wake_up(&ctrl->queue); |
7b4ce26b LW |
598 | |
599 | if (events == PCI_EXP_SLTSTA_CC) | |
600 | return IRQ_HANDLED; | |
601 | ||
602 | events &= ~PCI_EXP_SLTSTA_CC; | |
1da177e4 LT |
603 | } |
604 | ||
1204e35b LW |
605 | if (pdev->ignore_hotplug) { |
606 | ctrl_dbg(ctrl, "ignoring hotplug event %#06x\n", events); | |
607 | return IRQ_HANDLED; | |
b440bde7 BH |
608 | } |
609 | ||
7b4ce26b LW |
610 | /* Save pending events for consumption by IRQ thread. */ |
611 | atomic_or(events, &ctrl->pending_events); | |
612 | return IRQ_WAKE_THREAD; | |
613 | } | |
614 | ||
615 | static irqreturn_t pciehp_ist(int irq, void *dev_id) | |
616 | { | |
617 | struct controller *ctrl = (struct controller *)dev_id; | |
6b08c385 | 618 | struct pci_dev *pdev = ctrl_dev(ctrl); |
7b4ce26b | 619 | struct slot *slot = ctrl->slot; |
6b08c385 | 620 | irqreturn_t ret; |
7b4ce26b | 621 | u32 events; |
7b4ce26b | 622 | |
6b08c385 LW |
623 | pci_config_pm_runtime_get(pdev); |
624 | ||
625 | /* rerun pciehp_isr() if the port was inaccessible on interrupt */ | |
626 | if (atomic_fetch_and(~RERUN_ISR, &ctrl->pending_events) & RERUN_ISR) { | |
627 | ret = pciehp_isr(irq, dev_id); | |
628 | enable_irq(irq); | |
629 | if (ret != IRQ_WAKE_THREAD) { | |
630 | pci_config_pm_runtime_put(pdev); | |
631 | return ret; | |
632 | } | |
633 | } | |
634 | ||
7b4ce26b LW |
635 | synchronize_hardirq(irq); |
636 | events = atomic_xchg(&ctrl->pending_events, 0); | |
6b08c385 LW |
637 | if (!events) { |
638 | pci_config_pm_runtime_put(pdev); | |
7b4ce26b | 639 | return IRQ_NONE; |
6b08c385 | 640 | } |
7b4ce26b | 641 | |
c6b069e9 | 642 | /* Check Attention Button Pressed */ |
a8499f20 | 643 | if (events & PCI_EXP_SLTSTA_ABP) { |
6e49b304 | 644 | ctrl_info(ctrl, "Slot(%s): Attention button pressed\n", |
4f092fec | 645 | slot_name(slot)); |
0e94916e | 646 | pciehp_handle_button_press(slot); |
4f092fec | 647 | } |
48fe3915 | 648 | |
34fb6bf9 KB |
649 | /* Check Power Fault Detected */ |
650 | if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { | |
651 | ctrl->power_fault_detected = 1; | |
652 | ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(slot)); | |
653 | pciehp_set_attention_status(slot, 1); | |
654 | pciehp_green_led_off(slot); | |
655 | } | |
656 | ||
385895fe | 657 | /* |
32a8cef2 LW |
658 | * Disable requests have higher priority than Presence Detect Changed |
659 | * or Data Link Layer State Changed events. | |
385895fe | 660 | */ |
5b3f7b7d | 661 | down_read(&ctrl->reset_lock); |
32a8cef2 LW |
662 | if (events & DISABLE_SLOT) |
663 | pciehp_handle_disable_request(slot); | |
d331710e LW |
664 | else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) |
665 | pciehp_handle_presence_or_link_change(slot, events); | |
5b3f7b7d | 666 | up_read(&ctrl->reset_lock); |
48fe3915 | 667 | |
6b08c385 | 668 | pci_config_pm_runtime_put(pdev); |
32a8cef2 | 669 | wake_up(&ctrl->requester); |
1da177e4 LT |
670 | return IRQ_HANDLED; |
671 | } | |
672 | ||
ec07a447 LW |
673 | static int pciehp_poll(void *data) |
674 | { | |
675 | struct controller *ctrl = data; | |
676 | ||
677 | schedule_timeout_idle(10 * HZ); /* start with 10 sec delay */ | |
678 | ||
679 | while (!kthread_should_stop()) { | |
32a8cef2 LW |
680 | /* poll for interrupt events or user requests */ |
681 | while (pciehp_isr(IRQ_NOTCONNECTED, ctrl) == IRQ_WAKE_THREAD || | |
682 | atomic_read(&ctrl->pending_events)) | |
ec07a447 LW |
683 | pciehp_ist(IRQ_NOTCONNECTED, ctrl); |
684 | ||
685 | if (pciehp_poll_time <= 0 || pciehp_poll_time > 60) | |
686 | pciehp_poll_time = 2; /* clamp to sane value */ | |
687 | ||
688 | schedule_timeout_idle(pciehp_poll_time * HZ); | |
689 | } | |
690 | ||
691 | return 0; | |
692 | } | |
693 | ||
13c65840 | 694 | static void pcie_enable_notification(struct controller *ctrl) |
ecdde939 | 695 | { |
c27fb883 | 696 | u16 cmd, mask; |
1da177e4 | 697 | |
5651c48c KK |
698 | /* |
699 | * TBD: Power fault detected software notification support. | |
700 | * | |
701 | * Power fault detected software notification is not enabled | |
702 | * now, because it caused power fault detected interrupt storm | |
703 | * on some machines. On those machines, power fault detected | |
704 | * bit in the slot status register was set again immediately | |
705 | * when it is cleared in the interrupt service routine, and | |
706 | * next power fault detected interrupt was notified again. | |
707 | */ | |
4f854f2a RJ |
708 | |
709 | /* | |
710 | * Always enable link events: thus link-up and link-down shall | |
711 | * always be treated as hotplug and unplug respectively. Enable | |
712 | * presence detect only if Attention Button is not present. | |
713 | */ | |
714 | cmd = PCI_EXP_SLTCTL_DLLSCE; | |
ae416e6b | 715 | if (ATTN_BUTTN(ctrl)) |
322162a7 | 716 | cmd |= PCI_EXP_SLTCTL_ABPE; |
4f854f2a RJ |
717 | else |
718 | cmd |= PCI_EXP_SLTCTL_PDCE; | |
c27fb883 | 719 | if (!pciehp_poll_mode) |
322162a7 | 720 | cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; |
c27fb883 | 721 | |
322162a7 | 722 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
2db0f71f | 723 | PCI_EXP_SLTCTL_PFDE | |
4f854f2a RJ |
724 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | |
725 | PCI_EXP_SLTCTL_DLLSCE); | |
c27fb883 | 726 | |
a5dd4b4b | 727 | pcie_write_cmd_nowait(ctrl, cmd, mask); |
cf8d7b58 YL |
728 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
729 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); | |
c4635eb0 KK |
730 | } |
731 | ||
732 | static void pcie_disable_notification(struct controller *ctrl) | |
733 | { | |
734 | u16 mask; | |
6dae6202 | 735 | |
322162a7 KK |
736 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
737 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | | |
f22daf1f KK |
738 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | |
739 | PCI_EXP_SLTCTL_DLLSCE); | |
6dae6202 | 740 | pcie_write_cmd(ctrl, 0, mask); |
cf8d7b58 YL |
741 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
742 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0); | |
c4635eb0 KK |
743 | } |
744 | ||
79037824 LW |
745 | void pcie_clear_hotplug_events(struct controller *ctrl) |
746 | { | |
747 | pcie_capability_write_word(ctrl_dev(ctrl), PCI_EXP_SLTSTA, | |
748 | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); | |
749 | } | |
750 | ||
2e35afae AW |
751 | /* |
752 | * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary | |
2b3940b6 RJ |
753 | * bus reset of the bridge, but at the same time we want to ensure that it is |
754 | * not seen as a hot-unplug, followed by the hot-plug of the device. Thus, | |
755 | * disable link state notification and presence detection change notification | |
756 | * momentarily, if we see that they could interfere. Also, clear any spurious | |
2e35afae AW |
757 | * events after. |
758 | */ | |
eee6e273 | 759 | int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) |
2e35afae | 760 | { |
eee6e273 | 761 | struct slot *slot = hotplug_slot->private; |
2e35afae | 762 | struct controller *ctrl = slot->ctrl; |
cd84d340 | 763 | struct pci_dev *pdev = ctrl_dev(ctrl); |
06a8d89a | 764 | u16 stat_mask = 0, ctrl_mask = 0; |
18426238 | 765 | int rc; |
2e35afae AW |
766 | |
767 | if (probe) | |
768 | return 0; | |
769 | ||
5b3f7b7d LW |
770 | down_write(&ctrl->reset_lock); |
771 | ||
2b3940b6 | 772 | if (!ATTN_BUTTN(ctrl)) { |
06a8d89a RJ |
773 | ctrl_mask |= PCI_EXP_SLTCTL_PDCE; |
774 | stat_mask |= PCI_EXP_SLTSTA_PDC; | |
2e35afae | 775 | } |
06a8d89a RJ |
776 | ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE; |
777 | stat_mask |= PCI_EXP_SLTSTA_DLLSC; | |
778 | ||
779 | pcie_write_cmd(ctrl, 0, ctrl_mask); | |
cf8d7b58 YL |
780 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
781 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0); | |
2e35afae | 782 | |
381634ca | 783 | rc = pci_bridge_secondary_bus_reset(ctrl->pcie->port); |
2e35afae | 784 | |
06a8d89a | 785 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); |
a5dd4b4b | 786 | pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); |
cf8d7b58 YL |
787 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
788 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); | |
5b3f7b7d LW |
789 | |
790 | up_write(&ctrl->reset_lock); | |
18426238 | 791 | return rc; |
2e35afae AW |
792 | } |
793 | ||
dbc7e1e5 | 794 | int pcie_init_notification(struct controller *ctrl) |
c4635eb0 KK |
795 | { |
796 | if (pciehp_request_irq(ctrl)) | |
797 | return -1; | |
6dae6202 | 798 | pcie_enable_notification(ctrl); |
dbc7e1e5 | 799 | ctrl->notification_enabled = 1; |
c4635eb0 KK |
800 | return 0; |
801 | } | |
802 | ||
281e878e | 803 | void pcie_shutdown_notification(struct controller *ctrl) |
c4635eb0 | 804 | { |
dbc7e1e5 EB |
805 | if (ctrl->notification_enabled) { |
806 | pcie_disable_notification(ctrl); | |
807 | pciehp_free_irq(ctrl); | |
808 | ctrl->notification_enabled = 0; | |
809 | } | |
c4635eb0 KK |
810 | } |
811 | ||
c4635eb0 KK |
812 | static int pcie_init_slot(struct controller *ctrl) |
813 | { | |
9590192f | 814 | struct pci_bus *subordinate = ctrl_dev(ctrl)->subordinate; |
c4635eb0 KK |
815 | struct slot *slot; |
816 | ||
817 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | |
818 | if (!slot) | |
819 | return -ENOMEM; | |
820 | ||
9590192f LW |
821 | down_read(&pci_bus_sem); |
822 | slot->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; | |
823 | up_read(&pci_bus_sem); | |
824 | ||
c4635eb0 | 825 | slot->ctrl = ctrl; |
c4635eb0 KK |
826 | mutex_init(&slot->lock); |
827 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | |
8720d27d | 828 | ctrl->slot = slot; |
1da177e4 | 829 | return 0; |
1da177e4 | 830 | } |
08e7a7d2 | 831 | |
c4635eb0 KK |
832 | static void pcie_cleanup_slot(struct controller *ctrl) |
833 | { | |
8720d27d | 834 | struct slot *slot = ctrl->slot; |
281e878e | 835 | |
55a6b7a6 | 836 | cancel_delayed_work_sync(&slot->work); |
c4635eb0 KK |
837 | kfree(slot); |
838 | } | |
839 | ||
2aeeef11 | 840 | static inline void dbg_ctrl(struct controller *ctrl) |
08e7a7d2 | 841 | { |
385e2491 | 842 | struct pci_dev *pdev = ctrl->pcie->port; |
3784e0c6 | 843 | u16 reg16; |
08e7a7d2 | 844 | |
2aeeef11 KK |
845 | if (!pciehp_debug) |
846 | return; | |
08e7a7d2 | 847 | |
7f2feec1 | 848 | ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); |
cd84d340 | 849 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); |
7f2feec1 | 850 | ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); |
cd84d340 | 851 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); |
7f2feec1 | 852 | ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); |
2aeeef11 | 853 | } |
08e7a7d2 | 854 | |
3c78bc61 | 855 | #define FLAG(x, y) (((x) & (y)) ? '+' : '-') |
afe2478f | 856 | |
c4635eb0 | 857 | struct controller *pcie_init(struct pcie_device *dev) |
2aeeef11 | 858 | { |
c4635eb0 | 859 | struct controller *ctrl; |
f18e9625 | 860 | u32 slot_cap, link_cap; |
4e6a1335 | 861 | u8 occupied, poweron; |
2aeeef11 | 862 | struct pci_dev *pdev = dev->port; |
08e7a7d2 | 863 | |
c4635eb0 | 864 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); |
c7abb235 | 865 | if (!ctrl) |
c4635eb0 | 866 | goto abort; |
c7abb235 | 867 | |
f7a10e32 | 868 | ctrl->pcie = dev; |
1a84b99c | 869 | pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); |
576243b3 KB |
870 | |
871 | if (pdev->hotplug_user_indicators) | |
872 | slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); | |
873 | ||
493fb50e LW |
874 | /* |
875 | * We assume no Thunderbolt controllers support Command Complete events, | |
876 | * but some controllers falsely claim they do. | |
877 | */ | |
878 | if (pdev->is_thunderbolt) | |
879 | slot_cap |= PCI_EXP_SLTCAP_NCCS; | |
880 | ||
2aeeef11 | 881 | ctrl->slot_cap = slot_cap; |
08e7a7d2 | 882 | mutex_init(&ctrl->ctrl_lock); |
5b3f7b7d | 883 | init_rwsem(&ctrl->reset_lock); |
32a8cef2 | 884 | init_waitqueue_head(&ctrl->requester); |
08e7a7d2 | 885 | init_waitqueue_head(&ctrl->queue); |
2aeeef11 | 886 | dbg_ctrl(ctrl); |
2cc56f30 | 887 | |
3c78bc61 RD |
888 | /* Check if Data Link Layer Link Active Reporting is implemented */ |
889 | pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); | |
3784e0c6 | 890 | if (link_cap & PCI_EXP_LNKCAP_DLLLARC) |
3c78bc61 | 891 | ctrl->link_active_reporting = 1; |
f18e9625 | 892 | |
cdf6b736 | 893 | /* Clear all remaining event bits in Slot Status register. */ |
df72648c BH |
894 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
895 | PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | | |
db63d400 | 896 | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC | |
cdf6b736 | 897 | PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC); |
08e7a7d2 | 898 | |
d22b3621 | 899 | ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c%s\n", |
afe2478f BH |
900 | (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19, |
901 | FLAG(slot_cap, PCI_EXP_SLTCAP_ABP), | |
afe2478f BH |
902 | FLAG(slot_cap, PCI_EXP_SLTCAP_PCP), |
903 | FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP), | |
3784e0c6 BH |
904 | FLAG(slot_cap, PCI_EXP_SLTCAP_AIP), |
905 | FLAG(slot_cap, PCI_EXP_SLTCAP_PIP), | |
906 | FLAG(slot_cap, PCI_EXP_SLTCAP_HPC), | |
907 | FLAG(slot_cap, PCI_EXP_SLTCAP_HPS), | |
afe2478f BH |
908 | FLAG(slot_cap, PCI_EXP_SLTCAP_EIP), |
909 | FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS), | |
d22b3621 BH |
910 | FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC), |
911 | pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : ""); | |
c4635eb0 KK |
912 | |
913 | if (pcie_init_slot(ctrl)) | |
914 | goto abort_ctrl; | |
2aeeef11 | 915 | |
4e6a1335 LW |
916 | /* |
917 | * If empty slot's power status is on, turn power off. The IRQ isn't | |
918 | * requested yet, so avoid triggering a notification with this command. | |
919 | */ | |
920 | if (POWER_CTRL(ctrl)) { | |
921 | pciehp_get_adapter_status(ctrl->slot, &occupied); | |
922 | pciehp_get_power_status(ctrl->slot, &poweron); | |
923 | if (!occupied && poweron) { | |
924 | pcie_disable_notification(ctrl); | |
925 | pciehp_power_off_slot(ctrl->slot); | |
926 | } | |
927 | } | |
928 | ||
c4635eb0 KK |
929 | return ctrl; |
930 | ||
c4635eb0 KK |
931 | abort_ctrl: |
932 | kfree(ctrl); | |
08e7a7d2 | 933 | abort: |
c4635eb0 KK |
934 | return NULL; |
935 | } | |
936 | ||
82a9e79e | 937 | void pciehp_release_ctrl(struct controller *ctrl) |
c4635eb0 | 938 | { |
c4635eb0 | 939 | pcie_cleanup_slot(ctrl); |
c4635eb0 | 940 | kfree(ctrl); |
08e7a7d2 | 941 | } |
d22b3621 BH |
942 | |
943 | static void quirk_cmd_compl(struct pci_dev *pdev) | |
944 | { | |
945 | u32 slot_cap; | |
946 | ||
947 | if (pci_is_pcie(pdev)) { | |
948 | pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); | |
949 | if (slot_cap & PCI_EXP_SLTCAP_HPC && | |
950 | !(slot_cap & PCI_EXP_SLTCAP_NCCS)) | |
951 | pdev->broken_cmd_compl = 1; | |
952 | } | |
953 | } | |
954 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, | |
955 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); | |
956 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400, | |
957 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); | |
958 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0401, | |
959 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |