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", | |
5790a9c7 | 43 | slot_name(ctrl)); |
ec07a447 | 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 | ||
2f5d8e4f YL |
217 | static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) |
218 | { | |
219 | u32 l; | |
220 | int count = 0; | |
221 | int delay = 1000, step = 20; | |
222 | bool found = false; | |
223 | ||
224 | do { | |
225 | found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0); | |
226 | count++; | |
227 | ||
228 | if (found) | |
229 | break; | |
230 | ||
231 | msleep(step); | |
232 | delay -= step; | |
233 | } while (delay > 0); | |
234 | ||
235 | if (count > 1 && pciehp_debug) | |
236 | printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", | |
237 | pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), | |
238 | PCI_FUNC(devfn), count, step, l); | |
239 | ||
240 | return found; | |
241 | } | |
242 | ||
82a9e79e | 243 | int pciehp_check_link_status(struct controller *ctrl) |
1da177e4 | 244 | { |
cd84d340 | 245 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1a84b99c | 246 | bool found; |
1da177e4 | 247 | u16 lnk_status; |
1da177e4 | 248 | |
f0157160 KB |
249 | if (!pcie_wait_for_link(pdev, true)) |
250 | return -1; | |
f18e9625 | 251 | |
2f5d8e4f YL |
252 | found = pci_bus_check_dev(ctrl->pcie->port->subordinate, |
253 | PCI_DEVFN(0, 0)); | |
0027cb3e | 254 | |
6c35a1ac LW |
255 | /* ignore link or presence changes up to this point */ |
256 | if (found) | |
257 | atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC), | |
258 | &ctrl->pending_events); | |
259 | ||
1a84b99c | 260 | pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); |
7f2feec1 | 261 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
322162a7 KK |
262 | if ((lnk_status & PCI_EXP_LNKSTA_LT) || |
263 | !(lnk_status & PCI_EXP_LNKSTA_NLW)) { | |
3784e0c6 BH |
264 | ctrl_err(ctrl, "link training error: status %#06x\n", |
265 | lnk_status); | |
1a84b99c | 266 | return -1; |
1da177e4 LT |
267 | } |
268 | ||
fdbd3ce9 YL |
269 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); |
270 | ||
1a84b99c BH |
271 | if (!found) |
272 | return -1; | |
2f5d8e4f | 273 | |
1a84b99c | 274 | return 0; |
1da177e4 LT |
275 | } |
276 | ||
7f822999 YL |
277 | static int __pciehp_link_set(struct controller *ctrl, bool enable) |
278 | { | |
cd84d340 | 279 | struct pci_dev *pdev = ctrl_dev(ctrl); |
7f822999 | 280 | u16 lnk_ctrl; |
7f822999 | 281 | |
1a84b99c | 282 | pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); |
7f822999 YL |
283 | |
284 | if (enable) | |
285 | lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; | |
286 | else | |
287 | lnk_ctrl |= PCI_EXP_LNKCTL_LD; | |
288 | ||
1a84b99c | 289 | pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); |
7f822999 | 290 | ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); |
1a84b99c | 291 | return 0; |
7f822999 YL |
292 | } |
293 | ||
294 | static int pciehp_link_enable(struct controller *ctrl) | |
295 | { | |
296 | return __pciehp_link_set(ctrl, true); | |
297 | } | |
298 | ||
576243b3 KB |
299 | int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
300 | u8 *status) | |
301 | { | |
125450f8 | 302 | struct controller *ctrl = to_ctrl(hotplug_slot); |
5790a9c7 | 303 | struct pci_dev *pdev = ctrl_dev(ctrl); |
576243b3 KB |
304 | u16 slot_ctrl; |
305 | ||
4417aa45 | 306 | pci_config_pm_runtime_get(pdev); |
576243b3 | 307 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
4417aa45 | 308 | pci_config_pm_runtime_put(pdev); |
576243b3 KB |
309 | *status = (slot_ctrl & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6; |
310 | return 0; | |
311 | } | |
312 | ||
eee6e273 | 313 | int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) |
1da177e4 | 314 | { |
125450f8 | 315 | struct controller *ctrl = to_ctrl(hotplug_slot); |
cd84d340 | 316 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 317 | u16 slot_ctrl; |
1da177e4 | 318 | |
4417aa45 | 319 | pci_config_pm_runtime_get(pdev); |
1a84b99c | 320 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
4417aa45 | 321 | pci_config_pm_runtime_put(pdev); |
1518c17a KK |
322 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, |
323 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); | |
1da177e4 | 324 | |
e7b4f0d7 BH |
325 | switch (slot_ctrl & PCI_EXP_SLTCTL_AIC) { |
326 | case PCI_EXP_SLTCTL_ATTN_IND_ON: | |
1da177e4 LT |
327 | *status = 1; /* On */ |
328 | break; | |
e7b4f0d7 | 329 | case PCI_EXP_SLTCTL_ATTN_IND_BLINK: |
1da177e4 LT |
330 | *status = 2; /* Blink */ |
331 | break; | |
e7b4f0d7 | 332 | case PCI_EXP_SLTCTL_ATTN_IND_OFF: |
1da177e4 LT |
333 | *status = 0; /* Off */ |
334 | break; | |
335 | default: | |
336 | *status = 0xFF; | |
337 | break; | |
338 | } | |
eee6e273 LW |
339 | |
340 | return 0; | |
1da177e4 LT |
341 | } |
342 | ||
5790a9c7 | 343 | void pciehp_get_power_status(struct controller *ctrl, u8 *status) |
1da177e4 | 344 | { |
cd84d340 | 345 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 346 | u16 slot_ctrl; |
1da177e4 | 347 | |
1a84b99c | 348 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); |
1518c17a KK |
349 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, |
350 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); | |
1da177e4 | 351 | |
e7b4f0d7 BH |
352 | switch (slot_ctrl & PCI_EXP_SLTCTL_PCC) { |
353 | case PCI_EXP_SLTCTL_PWR_ON: | |
354 | *status = 1; /* On */ | |
1da177e4 | 355 | break; |
e7b4f0d7 BH |
356 | case PCI_EXP_SLTCTL_PWR_OFF: |
357 | *status = 0; /* Off */ | |
1da177e4 LT |
358 | break; |
359 | default: | |
360 | *status = 0xFF; | |
361 | break; | |
362 | } | |
1da177e4 LT |
363 | } |
364 | ||
5790a9c7 | 365 | void pciehp_get_latch_status(struct controller *ctrl, u8 *status) |
1da177e4 | 366 | { |
5790a9c7 | 367 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 368 | u16 slot_status; |
1da177e4 | 369 | |
1a84b99c | 370 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
322162a7 | 371 | *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); |
1da177e4 LT |
372 | } |
373 | ||
80696f99 | 374 | bool pciehp_card_present(struct controller *ctrl) |
1da177e4 | 375 | { |
80696f99 | 376 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 377 | u16 slot_status; |
1da177e4 | 378 | |
1a84b99c | 379 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
80696f99 LW |
380 | return slot_status & PCI_EXP_SLTSTA_PDS; |
381 | } | |
382 | ||
383 | /** | |
384 | * pciehp_card_present_or_link_active() - whether given slot is occupied | |
385 | * @ctrl: PCIe hotplug controller | |
386 | * | |
387 | * Unlike pciehp_card_present(), which determines presence solely from the | |
388 | * Presence Detect State bit, this helper also returns true if the Link Active | |
389 | * bit is set. This is a concession to broken hotplug ports which hardwire | |
390 | * Presence Detect State to zero, such as Wilocity's [1ae9:0200]. | |
391 | */ | |
392 | bool pciehp_card_present_or_link_active(struct controller *ctrl) | |
393 | { | |
394 | return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl); | |
1da177e4 LT |
395 | } |
396 | ||
5790a9c7 | 397 | int pciehp_query_power_fault(struct controller *ctrl) |
1da177e4 | 398 | { |
5790a9c7 | 399 | struct pci_dev *pdev = ctrl_dev(ctrl); |
1da177e4 | 400 | u16 slot_status; |
1da177e4 | 401 | |
1a84b99c | 402 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
322162a7 | 403 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); |
1da177e4 LT |
404 | } |
405 | ||
576243b3 KB |
406 | int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
407 | u8 status) | |
408 | { | |
125450f8 | 409 | struct controller *ctrl = to_ctrl(hotplug_slot); |
4417aa45 | 410 | struct pci_dev *pdev = ctrl_dev(ctrl); |
576243b3 | 411 | |
4417aa45 | 412 | pci_config_pm_runtime_get(pdev); |
576243b3 KB |
413 | pcie_write_cmd_nowait(ctrl, status << 6, |
414 | PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC); | |
4417aa45 | 415 | pci_config_pm_runtime_put(pdev); |
576243b3 KB |
416 | return 0; |
417 | } | |
418 | ||
5790a9c7 | 419 | void pciehp_set_attention_status(struct controller *ctrl, u8 value) |
1da177e4 | 420 | { |
f4778364 | 421 | u16 slot_cmd; |
1da177e4 | 422 | |
af9ab791 BH |
423 | if (!ATTN_LED(ctrl)) |
424 | return; | |
425 | ||
1da177e4 | 426 | switch (value) { |
3c78bc61 | 427 | case 0: /* turn off */ |
e7b4f0d7 | 428 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF; |
445f7985 KK |
429 | break; |
430 | case 1: /* turn on */ | |
e7b4f0d7 | 431 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON; |
445f7985 KK |
432 | break; |
433 | case 2: /* turn blink */ | |
e7b4f0d7 | 434 | slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK; |
445f7985 KK |
435 | break; |
436 | default: | |
6dae6202 | 437 | return; |
1da177e4 | 438 | } |
a5dd4b4b | 439 | pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); |
1518c17a KK |
440 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
441 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); | |
1da177e4 LT |
442 | } |
443 | ||
5790a9c7 | 444 | void pciehp_green_led_on(struct controller *ctrl) |
1da177e4 | 445 | { |
af9ab791 BH |
446 | if (!PWR_LED(ctrl)) |
447 | return; | |
448 | ||
a5dd4b4b AW |
449 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, |
450 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 451 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
452 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
453 | PCI_EXP_SLTCTL_PWR_IND_ON); | |
1da177e4 LT |
454 | } |
455 | ||
5790a9c7 | 456 | void pciehp_green_led_off(struct controller *ctrl) |
1da177e4 | 457 | { |
af9ab791 BH |
458 | if (!PWR_LED(ctrl)) |
459 | return; | |
460 | ||
a5dd4b4b AW |
461 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, |
462 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 463 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
464 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
465 | PCI_EXP_SLTCTL_PWR_IND_OFF); | |
1da177e4 LT |
466 | } |
467 | ||
5790a9c7 | 468 | void pciehp_green_led_blink(struct controller *ctrl) |
1da177e4 | 469 | { |
af9ab791 BH |
470 | if (!PWR_LED(ctrl)) |
471 | return; | |
472 | ||
a5dd4b4b AW |
473 | pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, |
474 | PCI_EXP_SLTCTL_PIC); | |
1518c17a | 475 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
476 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
477 | PCI_EXP_SLTCTL_PWR_IND_BLINK); | |
1da177e4 LT |
478 | } |
479 | ||
5790a9c7 | 480 | int pciehp_power_on_slot(struct controller *ctrl) |
1da177e4 | 481 | { |
cd84d340 | 482 | struct pci_dev *pdev = ctrl_dev(ctrl); |
f4778364 | 483 | u16 slot_status; |
1a84b99c | 484 | int retval; |
1da177e4 | 485 | |
34fb6bf9 | 486 | /* Clear power-fault bit from previous power failures */ |
1a84b99c | 487 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
2f2ed41c BH |
488 | if (slot_status & PCI_EXP_SLTSTA_PFD) |
489 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, | |
490 | PCI_EXP_SLTSTA_PFD); | |
5651c48c | 491 | ctrl->power_fault_detected = 0; |
1da177e4 | 492 | |
e7b4f0d7 | 493 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC); |
1518c17a | 494 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
495 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
496 | PCI_EXP_SLTCTL_PWR_ON); | |
1da177e4 | 497 | |
2debd928 YL |
498 | retval = pciehp_link_enable(ctrl); |
499 | if (retval) | |
500 | ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__); | |
501 | ||
1da177e4 LT |
502 | return retval; |
503 | } | |
504 | ||
5790a9c7 | 505 | void pciehp_power_off_slot(struct controller *ctrl) |
1da177e4 | 506 | { |
e7b4f0d7 | 507 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); |
1518c17a | 508 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
e7b4f0d7 BH |
509 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
510 | PCI_EXP_SLTCTL_PWR_OFF); | |
1da177e4 LT |
511 | } |
512 | ||
fad214b0 | 513 | static irqreturn_t pciehp_isr(int irq, void *dev_id) |
1da177e4 | 514 | { |
48fe3915 | 515 | struct controller *ctrl = (struct controller *)dev_id; |
cd84d340 | 516 | struct pci_dev *pdev = ctrl_dev(ctrl); |
6b08c385 | 517 | struct device *parent = pdev->dev.parent; |
a8499f20 | 518 | u16 status, events; |
1da177e4 | 519 | |
7b4ce26b | 520 | /* |
720d6a67 MW |
521 | * Interrupts only occur in D3hot or shallower and only if enabled |
522 | * in the Slot Control register (PCIe r4.0, sec 6.7.3.4). | |
7b4ce26b | 523 | */ |
720d6a67 MW |
524 | if (pdev->current_state == PCI_D3cold || |
525 | (!(ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE) && !pciehp_poll_mode)) | |
ed91de7e LW |
526 | return IRQ_NONE; |
527 | ||
6b08c385 LW |
528 | /* |
529 | * Keep the port accessible by holding a runtime PM ref on its parent. | |
530 | * Defer resume of the parent to the IRQ thread if it's suspended. | |
531 | * Mask the interrupt until then. | |
532 | */ | |
533 | if (parent) { | |
534 | pm_runtime_get_noresume(parent); | |
535 | if (!pm_runtime_active(parent)) { | |
536 | pm_runtime_put(parent); | |
537 | disable_irq_nosync(irq); | |
538 | atomic_or(RERUN_ISR, &ctrl->pending_events); | |
539 | return IRQ_WAKE_THREAD; | |
540 | } | |
541 | } | |
542 | ||
fad214b0 MP |
543 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status); |
544 | if (status == (u16) ~0) { | |
545 | ctrl_info(ctrl, "%s: no response from device\n", __func__); | |
6b08c385 LW |
546 | if (parent) |
547 | pm_runtime_put(parent); | |
fad214b0 MP |
548 | return IRQ_NONE; |
549 | } | |
550 | ||
c6b069e9 | 551 | /* |
fad214b0 MP |
552 | * Slot Status contains plain status bits as well as event |
553 | * notification bits; right now we only want the event bits. | |
c6b069e9 | 554 | */ |
fad214b0 | 555 | events = status & (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | |
a8499f20 BH |
556 | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC | |
557 | PCI_EXP_SLTSTA_DLLSC); | |
7612b3b2 KB |
558 | |
559 | /* | |
560 | * If we've already reported a power fault, don't report it again | |
561 | * until we've done something to handle it. | |
562 | */ | |
563 | if (ctrl->power_fault_detected) | |
564 | events &= ~PCI_EXP_SLTSTA_PFD; | |
565 | ||
6b08c385 LW |
566 | if (!events) { |
567 | if (parent) | |
568 | pm_runtime_put(parent); | |
fad214b0 | 569 | return IRQ_NONE; |
6b08c385 | 570 | } |
71ad556d | 571 | |
fad214b0 | 572 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events); |
a8499f20 | 573 | ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events); |
6b08c385 LW |
574 | if (parent) |
575 | pm_runtime_put(parent); | |
71ad556d | 576 | |
7b4ce26b LW |
577 | /* |
578 | * Command Completed notifications are not deferred to the | |
579 | * IRQ thread because it may be waiting for their arrival. | |
580 | */ | |
a8499f20 | 581 | if (events & PCI_EXP_SLTSTA_CC) { |
262303fe | 582 | ctrl->cmd_busy = 0; |
2d32a9ae | 583 | smp_mb(); |
d737bdc1 | 584 | wake_up(&ctrl->queue); |
7b4ce26b LW |
585 | |
586 | if (events == PCI_EXP_SLTSTA_CC) | |
587 | return IRQ_HANDLED; | |
588 | ||
589 | events &= ~PCI_EXP_SLTSTA_CC; | |
1da177e4 LT |
590 | } |
591 | ||
1204e35b LW |
592 | if (pdev->ignore_hotplug) { |
593 | ctrl_dbg(ctrl, "ignoring hotplug event %#06x\n", events); | |
594 | return IRQ_HANDLED; | |
b440bde7 BH |
595 | } |
596 | ||
7b4ce26b LW |
597 | /* Save pending events for consumption by IRQ thread. */ |
598 | atomic_or(events, &ctrl->pending_events); | |
599 | return IRQ_WAKE_THREAD; | |
600 | } | |
601 | ||
602 | static irqreturn_t pciehp_ist(int irq, void *dev_id) | |
603 | { | |
604 | struct controller *ctrl = (struct controller *)dev_id; | |
6b08c385 | 605 | struct pci_dev *pdev = ctrl_dev(ctrl); |
6b08c385 | 606 | irqreturn_t ret; |
7b4ce26b | 607 | u32 events; |
7b4ce26b | 608 | |
6b08c385 LW |
609 | pci_config_pm_runtime_get(pdev); |
610 | ||
611 | /* rerun pciehp_isr() if the port was inaccessible on interrupt */ | |
612 | if (atomic_fetch_and(~RERUN_ISR, &ctrl->pending_events) & RERUN_ISR) { | |
613 | ret = pciehp_isr(irq, dev_id); | |
614 | enable_irq(irq); | |
615 | if (ret != IRQ_WAKE_THREAD) { | |
616 | pci_config_pm_runtime_put(pdev); | |
617 | return ret; | |
618 | } | |
619 | } | |
620 | ||
7b4ce26b LW |
621 | synchronize_hardirq(irq); |
622 | events = atomic_xchg(&ctrl->pending_events, 0); | |
6b08c385 LW |
623 | if (!events) { |
624 | pci_config_pm_runtime_put(pdev); | |
7b4ce26b | 625 | return IRQ_NONE; |
6b08c385 | 626 | } |
7b4ce26b | 627 | |
c6b069e9 | 628 | /* Check Attention Button Pressed */ |
a8499f20 | 629 | if (events & PCI_EXP_SLTSTA_ABP) { |
6e49b304 | 630 | ctrl_info(ctrl, "Slot(%s): Attention button pressed\n", |
5790a9c7 LW |
631 | slot_name(ctrl)); |
632 | pciehp_handle_button_press(ctrl); | |
4f092fec | 633 | } |
48fe3915 | 634 | |
34fb6bf9 KB |
635 | /* Check Power Fault Detected */ |
636 | if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { | |
637 | ctrl->power_fault_detected = 1; | |
5790a9c7 LW |
638 | ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl)); |
639 | pciehp_set_attention_status(ctrl, 1); | |
640 | pciehp_green_led_off(ctrl); | |
34fb6bf9 KB |
641 | } |
642 | ||
385895fe | 643 | /* |
32a8cef2 LW |
644 | * Disable requests have higher priority than Presence Detect Changed |
645 | * or Data Link Layer State Changed events. | |
385895fe | 646 | */ |
5b3f7b7d | 647 | down_read(&ctrl->reset_lock); |
32a8cef2 | 648 | if (events & DISABLE_SLOT) |
5790a9c7 | 649 | pciehp_handle_disable_request(ctrl); |
d331710e | 650 | else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) |
5790a9c7 | 651 | pciehp_handle_presence_or_link_change(ctrl, events); |
5b3f7b7d | 652 | up_read(&ctrl->reset_lock); |
48fe3915 | 653 | |
6b08c385 | 654 | pci_config_pm_runtime_put(pdev); |
32a8cef2 | 655 | wake_up(&ctrl->requester); |
1da177e4 LT |
656 | return IRQ_HANDLED; |
657 | } | |
658 | ||
ec07a447 LW |
659 | static int pciehp_poll(void *data) |
660 | { | |
661 | struct controller *ctrl = data; | |
662 | ||
663 | schedule_timeout_idle(10 * HZ); /* start with 10 sec delay */ | |
664 | ||
665 | while (!kthread_should_stop()) { | |
32a8cef2 LW |
666 | /* poll for interrupt events or user requests */ |
667 | while (pciehp_isr(IRQ_NOTCONNECTED, ctrl) == IRQ_WAKE_THREAD || | |
668 | atomic_read(&ctrl->pending_events)) | |
ec07a447 LW |
669 | pciehp_ist(IRQ_NOTCONNECTED, ctrl); |
670 | ||
671 | if (pciehp_poll_time <= 0 || pciehp_poll_time > 60) | |
672 | pciehp_poll_time = 2; /* clamp to sane value */ | |
673 | ||
674 | schedule_timeout_idle(pciehp_poll_time * HZ); | |
675 | } | |
676 | ||
677 | return 0; | |
678 | } | |
679 | ||
13c65840 | 680 | static void pcie_enable_notification(struct controller *ctrl) |
ecdde939 | 681 | { |
c27fb883 | 682 | u16 cmd, mask; |
1da177e4 | 683 | |
5651c48c KK |
684 | /* |
685 | * TBD: Power fault detected software notification support. | |
686 | * | |
687 | * Power fault detected software notification is not enabled | |
688 | * now, because it caused power fault detected interrupt storm | |
689 | * on some machines. On those machines, power fault detected | |
690 | * bit in the slot status register was set again immediately | |
691 | * when it is cleared in the interrupt service routine, and | |
692 | * next power fault detected interrupt was notified again. | |
693 | */ | |
4f854f2a RJ |
694 | |
695 | /* | |
696 | * Always enable link events: thus link-up and link-down shall | |
697 | * always be treated as hotplug and unplug respectively. Enable | |
698 | * presence detect only if Attention Button is not present. | |
699 | */ | |
700 | cmd = PCI_EXP_SLTCTL_DLLSCE; | |
ae416e6b | 701 | if (ATTN_BUTTN(ctrl)) |
322162a7 | 702 | cmd |= PCI_EXP_SLTCTL_ABPE; |
4f854f2a RJ |
703 | else |
704 | cmd |= PCI_EXP_SLTCTL_PDCE; | |
c27fb883 | 705 | if (!pciehp_poll_mode) |
322162a7 | 706 | cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; |
c27fb883 | 707 | |
322162a7 | 708 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
2db0f71f | 709 | PCI_EXP_SLTCTL_PFDE | |
4f854f2a RJ |
710 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | |
711 | PCI_EXP_SLTCTL_DLLSCE); | |
c27fb883 | 712 | |
a5dd4b4b | 713 | pcie_write_cmd_nowait(ctrl, cmd, mask); |
cf8d7b58 YL |
714 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
715 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); | |
c4635eb0 KK |
716 | } |
717 | ||
718 | static void pcie_disable_notification(struct controller *ctrl) | |
719 | { | |
720 | u16 mask; | |
6dae6202 | 721 | |
322162a7 KK |
722 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
723 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | | |
f22daf1f KK |
724 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | |
725 | PCI_EXP_SLTCTL_DLLSCE); | |
6dae6202 | 726 | pcie_write_cmd(ctrl, 0, mask); |
cf8d7b58 YL |
727 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
728 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0); | |
c4635eb0 KK |
729 | } |
730 | ||
79037824 LW |
731 | void pcie_clear_hotplug_events(struct controller *ctrl) |
732 | { | |
733 | pcie_capability_write_word(ctrl_dev(ctrl), PCI_EXP_SLTSTA, | |
734 | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); | |
735 | } | |
736 | ||
eb34da60 MW |
737 | void pcie_enable_interrupt(struct controller *ctrl) |
738 | { | |
739 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_HPIE, PCI_EXP_SLTCTL_HPIE); | |
740 | } | |
741 | ||
742 | void pcie_disable_interrupt(struct controller *ctrl) | |
743 | { | |
744 | pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_HPIE); | |
745 | } | |
746 | ||
2e35afae AW |
747 | /* |
748 | * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary | |
2b3940b6 RJ |
749 | * bus reset of the bridge, but at the same time we want to ensure that it is |
750 | * not seen as a hot-unplug, followed by the hot-plug of the device. Thus, | |
751 | * disable link state notification and presence detection change notification | |
752 | * momentarily, if we see that they could interfere. Also, clear any spurious | |
2e35afae AW |
753 | * events after. |
754 | */ | |
eee6e273 | 755 | int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) |
2e35afae | 756 | { |
125450f8 | 757 | struct controller *ctrl = to_ctrl(hotplug_slot); |
cd84d340 | 758 | struct pci_dev *pdev = ctrl_dev(ctrl); |
06a8d89a | 759 | u16 stat_mask = 0, ctrl_mask = 0; |
18426238 | 760 | int rc; |
2e35afae AW |
761 | |
762 | if (probe) | |
763 | return 0; | |
764 | ||
5b3f7b7d LW |
765 | down_write(&ctrl->reset_lock); |
766 | ||
2b3940b6 | 767 | if (!ATTN_BUTTN(ctrl)) { |
06a8d89a RJ |
768 | ctrl_mask |= PCI_EXP_SLTCTL_PDCE; |
769 | stat_mask |= PCI_EXP_SLTSTA_PDC; | |
2e35afae | 770 | } |
06a8d89a RJ |
771 | ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE; |
772 | stat_mask |= PCI_EXP_SLTSTA_DLLSC; | |
773 | ||
774 | pcie_write_cmd(ctrl, 0, ctrl_mask); | |
cf8d7b58 YL |
775 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
776 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0); | |
2e35afae | 777 | |
381634ca | 778 | rc = pci_bridge_secondary_bus_reset(ctrl->pcie->port); |
2e35afae | 779 | |
06a8d89a | 780 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); |
a5dd4b4b | 781 | pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); |
cf8d7b58 YL |
782 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
783 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); | |
5b3f7b7d LW |
784 | |
785 | up_write(&ctrl->reset_lock); | |
18426238 | 786 | return rc; |
2e35afae AW |
787 | } |
788 | ||
dbc7e1e5 | 789 | int pcie_init_notification(struct controller *ctrl) |
c4635eb0 KK |
790 | { |
791 | if (pciehp_request_irq(ctrl)) | |
792 | return -1; | |
6dae6202 | 793 | pcie_enable_notification(ctrl); |
dbc7e1e5 | 794 | ctrl->notification_enabled = 1; |
c4635eb0 KK |
795 | return 0; |
796 | } | |
797 | ||
281e878e | 798 | void pcie_shutdown_notification(struct controller *ctrl) |
c4635eb0 | 799 | { |
dbc7e1e5 EB |
800 | if (ctrl->notification_enabled) { |
801 | pcie_disable_notification(ctrl); | |
802 | pciehp_free_irq(ctrl); | |
803 | ctrl->notification_enabled = 0; | |
804 | } | |
c4635eb0 KK |
805 | } |
806 | ||
2aeeef11 | 807 | static inline void dbg_ctrl(struct controller *ctrl) |
08e7a7d2 | 808 | { |
385e2491 | 809 | struct pci_dev *pdev = ctrl->pcie->port; |
3784e0c6 | 810 | u16 reg16; |
08e7a7d2 | 811 | |
2aeeef11 KK |
812 | if (!pciehp_debug) |
813 | return; | |
08e7a7d2 | 814 | |
7f2feec1 | 815 | ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); |
cd84d340 | 816 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); |
7f2feec1 | 817 | ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); |
cd84d340 | 818 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); |
7f2feec1 | 819 | ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); |
2aeeef11 | 820 | } |
08e7a7d2 | 821 | |
3c78bc61 | 822 | #define FLAG(x, y) (((x) & (y)) ? '+' : '-') |
afe2478f | 823 | |
c4635eb0 | 824 | struct controller *pcie_init(struct pcie_device *dev) |
2aeeef11 | 825 | { |
c4635eb0 | 826 | struct controller *ctrl; |
f18e9625 | 827 | u32 slot_cap, link_cap; |
80696f99 | 828 | u8 poweron; |
2aeeef11 | 829 | struct pci_dev *pdev = dev->port; |
5790a9c7 | 830 | struct pci_bus *subordinate = pdev->subordinate; |
08e7a7d2 | 831 | |
c4635eb0 | 832 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); |
c7abb235 | 833 | if (!ctrl) |
5790a9c7 | 834 | return NULL; |
c7abb235 | 835 | |
f7a10e32 | 836 | ctrl->pcie = dev; |
1a84b99c | 837 | pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); |
576243b3 KB |
838 | |
839 | if (pdev->hotplug_user_indicators) | |
840 | slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); | |
841 | ||
493fb50e LW |
842 | /* |
843 | * We assume no Thunderbolt controllers support Command Complete events, | |
844 | * but some controllers falsely claim they do. | |
845 | */ | |
846 | if (pdev->is_thunderbolt) | |
847 | slot_cap |= PCI_EXP_SLTCAP_NCCS; | |
848 | ||
2aeeef11 | 849 | ctrl->slot_cap = slot_cap; |
08e7a7d2 | 850 | mutex_init(&ctrl->ctrl_lock); |
4ff3126e | 851 | mutex_init(&ctrl->state_lock); |
5b3f7b7d | 852 | init_rwsem(&ctrl->reset_lock); |
32a8cef2 | 853 | init_waitqueue_head(&ctrl->requester); |
08e7a7d2 | 854 | init_waitqueue_head(&ctrl->queue); |
4ff3126e | 855 | INIT_DELAYED_WORK(&ctrl->button_work, pciehp_queue_pushbutton_work); |
2aeeef11 | 856 | dbg_ctrl(ctrl); |
2cc56f30 | 857 | |
5790a9c7 LW |
858 | down_read(&pci_bus_sem); |
859 | ctrl->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; | |
860 | up_read(&pci_bus_sem); | |
861 | ||
3c78bc61 RD |
862 | /* Check if Data Link Layer Link Active Reporting is implemented */ |
863 | pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); | |
f18e9625 | 864 | |
cdf6b736 | 865 | /* Clear all remaining event bits in Slot Status register. */ |
df72648c BH |
866 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
867 | PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | | |
db63d400 | 868 | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC | |
cdf6b736 | 869 | PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC); |
08e7a7d2 | 870 | |
d22b3621 | 871 | 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 |
872 | (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19, |
873 | FLAG(slot_cap, PCI_EXP_SLTCAP_ABP), | |
afe2478f BH |
874 | FLAG(slot_cap, PCI_EXP_SLTCAP_PCP), |
875 | FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP), | |
3784e0c6 BH |
876 | FLAG(slot_cap, PCI_EXP_SLTCAP_AIP), |
877 | FLAG(slot_cap, PCI_EXP_SLTCAP_PIP), | |
878 | FLAG(slot_cap, PCI_EXP_SLTCAP_HPC), | |
879 | FLAG(slot_cap, PCI_EXP_SLTCAP_HPS), | |
afe2478f BH |
880 | FLAG(slot_cap, PCI_EXP_SLTCAP_EIP), |
881 | FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS), | |
d22b3621 BH |
882 | FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC), |
883 | pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : ""); | |
c4635eb0 | 884 | |
4e6a1335 LW |
885 | /* |
886 | * If empty slot's power status is on, turn power off. The IRQ isn't | |
887 | * requested yet, so avoid triggering a notification with this command. | |
888 | */ | |
889 | if (POWER_CTRL(ctrl)) { | |
5790a9c7 | 890 | pciehp_get_power_status(ctrl, &poweron); |
80696f99 | 891 | if (!pciehp_card_present_or_link_active(ctrl) && poweron) { |
4e6a1335 | 892 | pcie_disable_notification(ctrl); |
5790a9c7 | 893 | pciehp_power_off_slot(ctrl); |
4e6a1335 LW |
894 | } |
895 | } | |
896 | ||
c4635eb0 | 897 | return ctrl; |
c4635eb0 KK |
898 | } |
899 | ||
82a9e79e | 900 | void pciehp_release_ctrl(struct controller *ctrl) |
c4635eb0 | 901 | { |
4ff3126e | 902 | cancel_delayed_work_sync(&ctrl->button_work); |
c4635eb0 | 903 | kfree(ctrl); |
08e7a7d2 | 904 | } |
d22b3621 BH |
905 | |
906 | static void quirk_cmd_compl(struct pci_dev *pdev) | |
907 | { | |
908 | u32 slot_cap; | |
909 | ||
910 | if (pci_is_pcie(pdev)) { | |
911 | pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); | |
912 | if (slot_cap & PCI_EXP_SLTCAP_HPC && | |
913 | !(slot_cap & PCI_EXP_SLTCAP_NCCS)) | |
914 | pdev->broken_cmd_compl = 1; | |
915 | } | |
916 | } | |
917 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, | |
918 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); | |
919 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400, | |
920 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); | |
921 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0401, | |
922 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |