.. | .. |
---|
12 | 12 | * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> |
---|
13 | 13 | */ |
---|
14 | 14 | |
---|
| 15 | +#define dev_fmt(fmt) "pciehp: " fmt |
---|
| 16 | + |
---|
| 17 | +#include <linux/dmi.h> |
---|
15 | 18 | #include <linux/kernel.h> |
---|
16 | | -#include <linux/module.h> |
---|
17 | 19 | #include <linux/types.h> |
---|
18 | | -#include <linux/signal.h> |
---|
19 | 20 | #include <linux/jiffies.h> |
---|
20 | 21 | #include <linux/kthread.h> |
---|
21 | 22 | #include <linux/pci.h> |
---|
22 | 23 | #include <linux/pm_runtime.h> |
---|
23 | 24 | #include <linux/interrupt.h> |
---|
24 | | -#include <linux/time.h> |
---|
25 | 25 | #include <linux/slab.h> |
---|
26 | 26 | |
---|
27 | 27 | #include "../pci.h" |
---|
28 | 28 | #include "pciehp.h" |
---|
| 29 | + |
---|
| 30 | +static const struct dmi_system_id inband_presence_disabled_dmi_table[] = { |
---|
| 31 | + /* |
---|
| 32 | + * Match all Dell systems, as some Dell systems have inband |
---|
| 33 | + * presence disabled on NVMe slots (but don't support the bit to |
---|
| 34 | + * report it). Setting inband presence disabled should have no |
---|
| 35 | + * negative effect, except on broken hotplug slots that never |
---|
| 36 | + * assert presence detect--and those will still work, they will |
---|
| 37 | + * just have a bit of extra delay before being probed. |
---|
| 38 | + */ |
---|
| 39 | + { |
---|
| 40 | + .ident = "Dell System", |
---|
| 41 | + .matches = { |
---|
| 42 | + DMI_MATCH(DMI_OEM_STRING, "Dell System"), |
---|
| 43 | + }, |
---|
| 44 | + }, |
---|
| 45 | + {} |
---|
| 46 | +}; |
---|
29 | 47 | |
---|
30 | 48 | static inline struct pci_dev *ctrl_dev(struct controller *ctrl) |
---|
31 | 49 | { |
---|
.. | .. |
---|
43 | 61 | if (pciehp_poll_mode) { |
---|
44 | 62 | ctrl->poll_thread = kthread_run(&pciehp_poll, ctrl, |
---|
45 | 63 | "pciehp_poll-%s", |
---|
46 | | - slot_name(ctrl->slot)); |
---|
| 64 | + slot_name(ctrl)); |
---|
47 | 65 | return PTR_ERR_OR_ZERO(ctrl->poll_thread); |
---|
48 | 66 | } |
---|
49 | 67 | |
---|
50 | 68 | /* Installs the interrupt handler */ |
---|
51 | 69 | retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist, |
---|
52 | | - IRQF_SHARED, MY_NAME, ctrl); |
---|
| 70 | + IRQF_SHARED, "pciehp", ctrl); |
---|
53 | 71 | if (retval) |
---|
54 | 72 | ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", |
---|
55 | 73 | irq); |
---|
.. | .. |
---|
69 | 87 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
70 | 88 | u16 slot_status; |
---|
71 | 89 | |
---|
72 | | - while (true) { |
---|
| 90 | + do { |
---|
73 | 91 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
74 | 92 | if (slot_status == (u16) ~0) { |
---|
75 | 93 | ctrl_info(ctrl, "%s: no response from device\n", |
---|
.. | .. |
---|
80 | 98 | if (slot_status & PCI_EXP_SLTSTA_CC) { |
---|
81 | 99 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
---|
82 | 100 | PCI_EXP_SLTSTA_CC); |
---|
| 101 | + ctrl->cmd_busy = 0; |
---|
| 102 | + smp_mb(); |
---|
83 | 103 | return 1; |
---|
84 | 104 | } |
---|
85 | | - if (timeout < 0) |
---|
86 | | - break; |
---|
87 | 105 | msleep(10); |
---|
88 | 106 | timeout -= 10; |
---|
89 | | - } |
---|
| 107 | + } while (timeout >= 0); |
---|
90 | 108 | return 0; /* timeout */ |
---|
91 | 109 | } |
---|
92 | 110 | |
---|
.. | .. |
---|
159 | 177 | slot_ctrl |= (cmd & mask); |
---|
160 | 178 | ctrl->cmd_busy = 1; |
---|
161 | 179 | smp_mb(); |
---|
| 180 | + ctrl->slot_ctrl = slot_ctrl; |
---|
162 | 181 | pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); |
---|
163 | 182 | ctrl->cmd_started = jiffies; |
---|
164 | | - ctrl->slot_ctrl = slot_ctrl; |
---|
165 | 183 | |
---|
166 | 184 | /* |
---|
167 | 185 | * Controllers with the Intel CF118 and similar errata advertise |
---|
.. | .. |
---|
202 | 220 | pcie_do_write_cmd(ctrl, cmd, mask, false); |
---|
203 | 221 | } |
---|
204 | 222 | |
---|
205 | | -bool pciehp_check_link_active(struct controller *ctrl) |
---|
| 223 | +/** |
---|
| 224 | + * pciehp_check_link_active() - Is the link active |
---|
| 225 | + * @ctrl: PCIe hotplug controller |
---|
| 226 | + * |
---|
| 227 | + * Check whether the downstream link is currently active. Note it is |
---|
| 228 | + * possible that the card is removed immediately after this so the |
---|
| 229 | + * caller may need to take it into account. |
---|
| 230 | + * |
---|
| 231 | + * If the hotplug controller itself is not available anymore returns |
---|
| 232 | + * %-ENODEV. |
---|
| 233 | + */ |
---|
| 234 | +int pciehp_check_link_active(struct controller *ctrl) |
---|
206 | 235 | { |
---|
207 | 236 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
208 | 237 | u16 lnk_status; |
---|
209 | | - bool ret; |
---|
| 238 | + int ret; |
---|
210 | 239 | |
---|
211 | | - pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); |
---|
| 240 | + ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); |
---|
| 241 | + if (ret == PCIBIOS_DEVICE_NOT_FOUND || lnk_status == (u16)~0) |
---|
| 242 | + return -ENODEV; |
---|
| 243 | + |
---|
212 | 244 | ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); |
---|
213 | | - |
---|
214 | | - if (ret) |
---|
215 | | - ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
---|
| 245 | + ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
---|
216 | 246 | |
---|
217 | 247 | return ret; |
---|
218 | | -} |
---|
219 | | - |
---|
220 | | -static void pcie_wait_link_active(struct controller *ctrl) |
---|
221 | | -{ |
---|
222 | | - struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
223 | | - |
---|
224 | | - pcie_wait_for_link(pdev, true); |
---|
225 | 248 | } |
---|
226 | 249 | |
---|
227 | 250 | static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) |
---|
.. | .. |
---|
242 | 265 | delay -= step; |
---|
243 | 266 | } while (delay > 0); |
---|
244 | 267 | |
---|
245 | | - if (count > 1 && pciehp_debug) |
---|
246 | | - printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", |
---|
| 268 | + if (count > 1) |
---|
| 269 | + pr_debug("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", |
---|
247 | 270 | pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), |
---|
248 | 271 | PCI_FUNC(devfn), count, step, l); |
---|
249 | 272 | |
---|
250 | 273 | return found; |
---|
| 274 | +} |
---|
| 275 | + |
---|
| 276 | +static void pcie_wait_for_presence(struct pci_dev *pdev) |
---|
| 277 | +{ |
---|
| 278 | + int timeout = 1250; |
---|
| 279 | + u16 slot_status; |
---|
| 280 | + |
---|
| 281 | + do { |
---|
| 282 | + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
| 283 | + if (slot_status & PCI_EXP_SLTSTA_PDS) |
---|
| 284 | + return; |
---|
| 285 | + msleep(10); |
---|
| 286 | + timeout -= 10; |
---|
| 287 | + } while (timeout > 0); |
---|
251 | 288 | } |
---|
252 | 289 | |
---|
253 | 290 | int pciehp_check_link_status(struct controller *ctrl) |
---|
.. | .. |
---|
256 | 293 | bool found; |
---|
257 | 294 | u16 lnk_status; |
---|
258 | 295 | |
---|
259 | | - /* |
---|
260 | | - * Data Link Layer Link Active Reporting must be capable for |
---|
261 | | - * hot-plug capable downstream port. But old controller might |
---|
262 | | - * not implement it. In this case, we wait for 1000 ms. |
---|
263 | | - */ |
---|
264 | | - if (ctrl->link_active_reporting) |
---|
265 | | - pcie_wait_link_active(ctrl); |
---|
266 | | - else |
---|
267 | | - msleep(1000); |
---|
| 296 | + if (!pcie_wait_for_link(pdev, true)) { |
---|
| 297 | + ctrl_info(ctrl, "Slot(%s): No link\n", slot_name(ctrl)); |
---|
| 298 | + return -1; |
---|
| 299 | + } |
---|
268 | 300 | |
---|
269 | | - /* wait 100ms before read pci conf, and try in 1s */ |
---|
270 | | - msleep(100); |
---|
| 301 | + if (ctrl->inband_presence_disabled) |
---|
| 302 | + pcie_wait_for_presence(pdev); |
---|
| 303 | + |
---|
271 | 304 | found = pci_bus_check_dev(ctrl->pcie->port->subordinate, |
---|
272 | 305 | PCI_DEVFN(0, 0)); |
---|
273 | 306 | |
---|
.. | .. |
---|
280 | 313 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
---|
281 | 314 | if ((lnk_status & PCI_EXP_LNKSTA_LT) || |
---|
282 | 315 | !(lnk_status & PCI_EXP_LNKSTA_NLW)) { |
---|
283 | | - ctrl_err(ctrl, "link training error: status %#06x\n", |
---|
284 | | - lnk_status); |
---|
| 316 | + ctrl_info(ctrl, "Slot(%s): Cannot train link: status %#06x\n", |
---|
| 317 | + slot_name(ctrl), lnk_status); |
---|
285 | 318 | return -1; |
---|
286 | 319 | } |
---|
287 | 320 | |
---|
288 | 321 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); |
---|
289 | 322 | |
---|
290 | | - if (!found) |
---|
| 323 | + if (!found) { |
---|
| 324 | + ctrl_info(ctrl, "Slot(%s): No device found\n", |
---|
| 325 | + slot_name(ctrl)); |
---|
291 | 326 | return -1; |
---|
| 327 | + } |
---|
292 | 328 | |
---|
293 | 329 | return 0; |
---|
294 | 330 | } |
---|
.. | .. |
---|
296 | 332 | static int __pciehp_link_set(struct controller *ctrl, bool enable) |
---|
297 | 333 | { |
---|
298 | 334 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
299 | | - u16 lnk_ctrl; |
---|
300 | 335 | |
---|
301 | | - pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); |
---|
| 336 | + pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, |
---|
| 337 | + PCI_EXP_LNKCTL_LD, |
---|
| 338 | + enable ? 0 : PCI_EXP_LNKCTL_LD); |
---|
302 | 339 | |
---|
303 | | - if (enable) |
---|
304 | | - lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; |
---|
305 | | - else |
---|
306 | | - lnk_ctrl |= PCI_EXP_LNKCTL_LD; |
---|
307 | | - |
---|
308 | | - pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); |
---|
309 | | - ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); |
---|
310 | 340 | return 0; |
---|
311 | 341 | } |
---|
312 | 342 | |
---|
.. | .. |
---|
318 | 348 | int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
---|
319 | 349 | u8 *status) |
---|
320 | 350 | { |
---|
321 | | - struct slot *slot = hotplug_slot->private; |
---|
322 | | - struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
---|
| 351 | + struct controller *ctrl = to_ctrl(hotplug_slot); |
---|
| 352 | + struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
323 | 353 | u16 slot_ctrl; |
---|
324 | 354 | |
---|
325 | 355 | pci_config_pm_runtime_get(pdev); |
---|
.. | .. |
---|
329 | 359 | return 0; |
---|
330 | 360 | } |
---|
331 | 361 | |
---|
332 | | -void pciehp_get_attention_status(struct slot *slot, u8 *status) |
---|
| 362 | +int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) |
---|
333 | 363 | { |
---|
334 | | - struct controller *ctrl = slot->ctrl; |
---|
| 364 | + struct controller *ctrl = to_ctrl(hotplug_slot); |
---|
335 | 365 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
336 | 366 | u16 slot_ctrl; |
---|
337 | 367 | |
---|
.. | .. |
---|
355 | 385 | *status = 0xFF; |
---|
356 | 386 | break; |
---|
357 | 387 | } |
---|
| 388 | + |
---|
| 389 | + return 0; |
---|
358 | 390 | } |
---|
359 | 391 | |
---|
360 | | -void pciehp_get_power_status(struct slot *slot, u8 *status) |
---|
| 392 | +void pciehp_get_power_status(struct controller *ctrl, u8 *status) |
---|
361 | 393 | { |
---|
362 | | - struct controller *ctrl = slot->ctrl; |
---|
363 | 394 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
364 | 395 | u16 slot_ctrl; |
---|
365 | 396 | |
---|
.. | .. |
---|
380 | 411 | } |
---|
381 | 412 | } |
---|
382 | 413 | |
---|
383 | | -void pciehp_get_latch_status(struct slot *slot, u8 *status) |
---|
| 414 | +void pciehp_get_latch_status(struct controller *ctrl, u8 *status) |
---|
384 | 415 | { |
---|
385 | | - struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
---|
| 416 | + struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
386 | 417 | u16 slot_status; |
---|
387 | 418 | |
---|
388 | 419 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
389 | 420 | *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); |
---|
390 | 421 | } |
---|
391 | 422 | |
---|
392 | | -void pciehp_get_adapter_status(struct slot *slot, u8 *status) |
---|
| 423 | +/** |
---|
| 424 | + * pciehp_card_present() - Is the card present |
---|
| 425 | + * @ctrl: PCIe hotplug controller |
---|
| 426 | + * |
---|
| 427 | + * Function checks whether the card is currently present in the slot and |
---|
| 428 | + * in that case returns true. Note it is possible that the card is |
---|
| 429 | + * removed immediately after the check so the caller may need to take |
---|
| 430 | + * this into account. |
---|
| 431 | + * |
---|
| 432 | + * It the hotplug controller itself is not available anymore returns |
---|
| 433 | + * %-ENODEV. |
---|
| 434 | + */ |
---|
| 435 | +int pciehp_card_present(struct controller *ctrl) |
---|
393 | 436 | { |
---|
394 | | - struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
---|
| 437 | + struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
395 | 438 | u16 slot_status; |
---|
| 439 | + int ret; |
---|
396 | 440 | |
---|
397 | | - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
398 | | - *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); |
---|
| 441 | + ret = pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
| 442 | + if (ret == PCIBIOS_DEVICE_NOT_FOUND || slot_status == (u16)~0) |
---|
| 443 | + return -ENODEV; |
---|
| 444 | + |
---|
| 445 | + return !!(slot_status & PCI_EXP_SLTSTA_PDS); |
---|
399 | 446 | } |
---|
400 | 447 | |
---|
401 | | -int pciehp_query_power_fault(struct slot *slot) |
---|
| 448 | +/** |
---|
| 449 | + * pciehp_card_present_or_link_active() - whether given slot is occupied |
---|
| 450 | + * @ctrl: PCIe hotplug controller |
---|
| 451 | + * |
---|
| 452 | + * Unlike pciehp_card_present(), which determines presence solely from the |
---|
| 453 | + * Presence Detect State bit, this helper also returns true if the Link Active |
---|
| 454 | + * bit is set. This is a concession to broken hotplug ports which hardwire |
---|
| 455 | + * Presence Detect State to zero, such as Wilocity's [1ae9:0200]. |
---|
| 456 | + * |
---|
| 457 | + * Returns: %1 if the slot is occupied and %0 if it is not. If the hotplug |
---|
| 458 | + * port is not present anymore returns %-ENODEV. |
---|
| 459 | + */ |
---|
| 460 | +int pciehp_card_present_or_link_active(struct controller *ctrl) |
---|
402 | 461 | { |
---|
403 | | - struct pci_dev *pdev = ctrl_dev(slot->ctrl); |
---|
| 462 | + int ret; |
---|
| 463 | + |
---|
| 464 | + ret = pciehp_card_present(ctrl); |
---|
| 465 | + if (ret) |
---|
| 466 | + return ret; |
---|
| 467 | + |
---|
| 468 | + return pciehp_check_link_active(ctrl); |
---|
| 469 | +} |
---|
| 470 | + |
---|
| 471 | +int pciehp_query_power_fault(struct controller *ctrl) |
---|
| 472 | +{ |
---|
| 473 | + struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
404 | 474 | u16 slot_status; |
---|
405 | 475 | |
---|
406 | 476 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); |
---|
.. | .. |
---|
410 | 480 | int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, |
---|
411 | 481 | u8 status) |
---|
412 | 482 | { |
---|
413 | | - struct slot *slot = hotplug_slot->private; |
---|
414 | | - struct controller *ctrl = slot->ctrl; |
---|
| 483 | + struct controller *ctrl = to_ctrl(hotplug_slot); |
---|
415 | 484 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
416 | 485 | |
---|
417 | 486 | pci_config_pm_runtime_get(pdev); |
---|
.. | .. |
---|
421 | 490 | return 0; |
---|
422 | 491 | } |
---|
423 | 492 | |
---|
424 | | -void pciehp_set_attention_status(struct slot *slot, u8 value) |
---|
| 493 | +/** |
---|
| 494 | + * pciehp_set_indicators() - set attention indicator, power indicator, or both |
---|
| 495 | + * @ctrl: PCIe hotplug controller |
---|
| 496 | + * @pwr: one of: |
---|
| 497 | + * PCI_EXP_SLTCTL_PWR_IND_ON |
---|
| 498 | + * PCI_EXP_SLTCTL_PWR_IND_BLINK |
---|
| 499 | + * PCI_EXP_SLTCTL_PWR_IND_OFF |
---|
| 500 | + * @attn: one of: |
---|
| 501 | + * PCI_EXP_SLTCTL_ATTN_IND_ON |
---|
| 502 | + * PCI_EXP_SLTCTL_ATTN_IND_BLINK |
---|
| 503 | + * PCI_EXP_SLTCTL_ATTN_IND_OFF |
---|
| 504 | + * |
---|
| 505 | + * Either @pwr or @attn can also be INDICATOR_NOOP to leave that indicator |
---|
| 506 | + * unchanged. |
---|
| 507 | + */ |
---|
| 508 | +void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn) |
---|
425 | 509 | { |
---|
426 | | - struct controller *ctrl = slot->ctrl; |
---|
427 | | - u16 slot_cmd; |
---|
| 510 | + u16 cmd = 0, mask = 0; |
---|
428 | 511 | |
---|
429 | | - if (!ATTN_LED(ctrl)) |
---|
430 | | - return; |
---|
431 | | - |
---|
432 | | - switch (value) { |
---|
433 | | - case 0: /* turn off */ |
---|
434 | | - slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF; |
---|
435 | | - break; |
---|
436 | | - case 1: /* turn on */ |
---|
437 | | - slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON; |
---|
438 | | - break; |
---|
439 | | - case 2: /* turn blink */ |
---|
440 | | - slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK; |
---|
441 | | - break; |
---|
442 | | - default: |
---|
443 | | - return; |
---|
| 512 | + if (PWR_LED(ctrl) && pwr != INDICATOR_NOOP) { |
---|
| 513 | + cmd |= (pwr & PCI_EXP_SLTCTL_PIC); |
---|
| 514 | + mask |= PCI_EXP_SLTCTL_PIC; |
---|
444 | 515 | } |
---|
445 | | - pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); |
---|
446 | | - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
447 | | - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
---|
| 516 | + |
---|
| 517 | + if (ATTN_LED(ctrl) && attn != INDICATOR_NOOP) { |
---|
| 518 | + cmd |= (attn & PCI_EXP_SLTCTL_AIC); |
---|
| 519 | + mask |= PCI_EXP_SLTCTL_AIC; |
---|
| 520 | + } |
---|
| 521 | + |
---|
| 522 | + if (cmd) { |
---|
| 523 | + pcie_write_cmd_nowait(ctrl, cmd, mask); |
---|
| 524 | + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
| 525 | + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); |
---|
| 526 | + } |
---|
448 | 527 | } |
---|
449 | 528 | |
---|
450 | | -void pciehp_green_led_on(struct slot *slot) |
---|
| 529 | +int pciehp_power_on_slot(struct controller *ctrl) |
---|
451 | 530 | { |
---|
452 | | - struct controller *ctrl = slot->ctrl; |
---|
453 | | - |
---|
454 | | - if (!PWR_LED(ctrl)) |
---|
455 | | - return; |
---|
456 | | - |
---|
457 | | - pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, |
---|
458 | | - PCI_EXP_SLTCTL_PIC); |
---|
459 | | - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
460 | | - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
---|
461 | | - PCI_EXP_SLTCTL_PWR_IND_ON); |
---|
462 | | -} |
---|
463 | | - |
---|
464 | | -void pciehp_green_led_off(struct slot *slot) |
---|
465 | | -{ |
---|
466 | | - struct controller *ctrl = slot->ctrl; |
---|
467 | | - |
---|
468 | | - if (!PWR_LED(ctrl)) |
---|
469 | | - return; |
---|
470 | | - |
---|
471 | | - pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, |
---|
472 | | - PCI_EXP_SLTCTL_PIC); |
---|
473 | | - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
474 | | - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
---|
475 | | - PCI_EXP_SLTCTL_PWR_IND_OFF); |
---|
476 | | -} |
---|
477 | | - |
---|
478 | | -void pciehp_green_led_blink(struct slot *slot) |
---|
479 | | -{ |
---|
480 | | - struct controller *ctrl = slot->ctrl; |
---|
481 | | - |
---|
482 | | - if (!PWR_LED(ctrl)) |
---|
483 | | - return; |
---|
484 | | - |
---|
485 | | - pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, |
---|
486 | | - PCI_EXP_SLTCTL_PIC); |
---|
487 | | - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
488 | | - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
---|
489 | | - PCI_EXP_SLTCTL_PWR_IND_BLINK); |
---|
490 | | -} |
---|
491 | | - |
---|
492 | | -int pciehp_power_on_slot(struct slot *slot) |
---|
493 | | -{ |
---|
494 | | - struct controller *ctrl = slot->ctrl; |
---|
495 | 531 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
496 | 532 | u16 slot_status; |
---|
497 | 533 | int retval; |
---|
.. | .. |
---|
515 | 551 | return retval; |
---|
516 | 552 | } |
---|
517 | 553 | |
---|
518 | | -void pciehp_power_off_slot(struct slot *slot) |
---|
| 554 | +void pciehp_power_off_slot(struct controller *ctrl) |
---|
519 | 555 | { |
---|
520 | | - struct controller *ctrl = slot->ctrl; |
---|
521 | | - |
---|
522 | 556 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); |
---|
523 | 557 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
---|
524 | 558 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, |
---|
525 | 559 | PCI_EXP_SLTCTL_PWR_OFF); |
---|
| 560 | +} |
---|
| 561 | + |
---|
| 562 | +static void pciehp_ignore_dpc_link_change(struct controller *ctrl, |
---|
| 563 | + struct pci_dev *pdev, int irq) |
---|
| 564 | +{ |
---|
| 565 | + /* |
---|
| 566 | + * Ignore link changes which occurred while waiting for DPC recovery. |
---|
| 567 | + * Could be several if DPC triggered multiple times consecutively. |
---|
| 568 | + */ |
---|
| 569 | + synchronize_hardirq(irq); |
---|
| 570 | + atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events); |
---|
| 571 | + if (pciehp_poll_mode) |
---|
| 572 | + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
---|
| 573 | + PCI_EXP_SLTSTA_DLLSC); |
---|
| 574 | + ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n", |
---|
| 575 | + slot_name(ctrl)); |
---|
| 576 | + |
---|
| 577 | + /* |
---|
| 578 | + * If the link is unexpectedly down after successful recovery, |
---|
| 579 | + * the corresponding link change may have been ignored above. |
---|
| 580 | + * Synthesize it to ensure that it is acted on. |
---|
| 581 | + */ |
---|
| 582 | + down_read_nested(&ctrl->reset_lock, ctrl->depth); |
---|
| 583 | + if (!pciehp_check_link_active(ctrl)) |
---|
| 584 | + pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); |
---|
| 585 | + up_read(&ctrl->reset_lock); |
---|
526 | 586 | } |
---|
527 | 587 | |
---|
528 | 588 | static irqreturn_t pciehp_isr(int irq, void *dev_id) |
---|
.. | .. |
---|
533 | 593 | u16 status, events = 0; |
---|
534 | 594 | |
---|
535 | 595 | /* |
---|
536 | | - * Interrupts only occur in D3hot or shallower (PCIe r4.0, sec 6.7.3.4). |
---|
| 596 | + * Interrupts only occur in D3hot or shallower and only if enabled |
---|
| 597 | + * in the Slot Control register (PCIe r4.0, sec 6.7.3.4). |
---|
537 | 598 | */ |
---|
538 | | - if (pdev->current_state == PCI_D3cold) |
---|
| 599 | + if (pdev->current_state == PCI_D3cold || |
---|
| 600 | + (!(ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE) && !pciehp_poll_mode)) |
---|
539 | 601 | return IRQ_NONE; |
---|
540 | 602 | |
---|
541 | 603 | /* |
---|
.. | .. |
---|
576 | 638 | */ |
---|
577 | 639 | if (ctrl->power_fault_detected) |
---|
578 | 640 | status &= ~PCI_EXP_SLTSTA_PFD; |
---|
| 641 | + else if (status & PCI_EXP_SLTSTA_PFD) |
---|
| 642 | + ctrl->power_fault_detected = true; |
---|
579 | 643 | |
---|
580 | 644 | events |= status; |
---|
581 | 645 | if (!events) { |
---|
.. | .. |
---|
585 | 649 | } |
---|
586 | 650 | |
---|
587 | 651 | if (status) { |
---|
588 | | - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events); |
---|
| 652 | + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, status); |
---|
589 | 653 | |
---|
590 | 654 | /* |
---|
591 | 655 | * In MSI mode, all event bits must be zero before the port |
---|
.. | .. |
---|
630 | 694 | { |
---|
631 | 695 | struct controller *ctrl = (struct controller *)dev_id; |
---|
632 | 696 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
633 | | - struct slot *slot = ctrl->slot; |
---|
634 | 697 | irqreturn_t ret; |
---|
635 | 698 | u32 events; |
---|
636 | 699 | |
---|
.. | .. |
---|
655 | 718 | /* Check Attention Button Pressed */ |
---|
656 | 719 | if (events & PCI_EXP_SLTSTA_ABP) { |
---|
657 | 720 | ctrl_info(ctrl, "Slot(%s): Attention button pressed\n", |
---|
658 | | - slot_name(slot)); |
---|
659 | | - pciehp_handle_button_press(slot); |
---|
| 721 | + slot_name(ctrl)); |
---|
| 722 | + pciehp_handle_button_press(ctrl); |
---|
660 | 723 | } |
---|
661 | 724 | |
---|
662 | 725 | /* Check Power Fault Detected */ |
---|
663 | | - if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { |
---|
664 | | - ctrl->power_fault_detected = 1; |
---|
665 | | - ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(slot)); |
---|
666 | | - pciehp_set_attention_status(slot, 1); |
---|
667 | | - pciehp_green_led_off(slot); |
---|
| 726 | + if (events & PCI_EXP_SLTSTA_PFD) { |
---|
| 727 | + ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl)); |
---|
| 728 | + pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, |
---|
| 729 | + PCI_EXP_SLTCTL_ATTN_IND_ON); |
---|
| 730 | + } |
---|
| 731 | + |
---|
| 732 | + /* |
---|
| 733 | + * Ignore Link Down/Up events caused by Downstream Port Containment |
---|
| 734 | + * if recovery from the error succeeded. |
---|
| 735 | + */ |
---|
| 736 | + if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) && |
---|
| 737 | + ctrl->state == ON_STATE) { |
---|
| 738 | + events &= ~PCI_EXP_SLTSTA_DLLSC; |
---|
| 739 | + pciehp_ignore_dpc_link_change(ctrl, pdev, irq); |
---|
668 | 740 | } |
---|
669 | 741 | |
---|
670 | 742 | /* |
---|
671 | 743 | * Disable requests have higher priority than Presence Detect Changed |
---|
672 | 744 | * or Data Link Layer State Changed events. |
---|
673 | 745 | */ |
---|
674 | | - down_read(&ctrl->reset_lock); |
---|
| 746 | + down_read_nested(&ctrl->reset_lock, ctrl->depth); |
---|
675 | 747 | if (events & DISABLE_SLOT) |
---|
676 | | - pciehp_handle_disable_request(slot); |
---|
| 748 | + pciehp_handle_disable_request(ctrl); |
---|
677 | 749 | else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) |
---|
678 | | - pciehp_handle_presence_or_link_change(slot, events); |
---|
| 750 | + pciehp_handle_presence_or_link_change(ctrl, events); |
---|
679 | 751 | up_read(&ctrl->reset_lock); |
---|
680 | 752 | |
---|
681 | 753 | ret = IRQ_HANDLED; |
---|
.. | .. |
---|
764 | 836 | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); |
---|
765 | 837 | } |
---|
766 | 838 | |
---|
| 839 | +void pcie_enable_interrupt(struct controller *ctrl) |
---|
| 840 | +{ |
---|
| 841 | + u16 mask; |
---|
| 842 | + |
---|
| 843 | + mask = PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE; |
---|
| 844 | + pcie_write_cmd(ctrl, mask, mask); |
---|
| 845 | +} |
---|
| 846 | + |
---|
| 847 | +void pcie_disable_interrupt(struct controller *ctrl) |
---|
| 848 | +{ |
---|
| 849 | + u16 mask; |
---|
| 850 | + |
---|
| 851 | + /* |
---|
| 852 | + * Mask hot-plug interrupt to prevent it triggering immediately |
---|
| 853 | + * when the link goes inactive (we still get PME when any of the |
---|
| 854 | + * enabled events is detected). Same goes with Link Layer State |
---|
| 855 | + * changed event which generates PME immediately when the link goes |
---|
| 856 | + * inactive so mask it as well. |
---|
| 857 | + */ |
---|
| 858 | + mask = PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE; |
---|
| 859 | + pcie_write_cmd(ctrl, 0, mask); |
---|
| 860 | +} |
---|
| 861 | + |
---|
767 | 862 | /* |
---|
768 | 863 | * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary |
---|
769 | 864 | * bus reset of the bridge, but at the same time we want to ensure that it is |
---|
.. | .. |
---|
772 | 867 | * momentarily, if we see that they could interfere. Also, clear any spurious |
---|
773 | 868 | * events after. |
---|
774 | 869 | */ |
---|
775 | | -int pciehp_reset_slot(struct slot *slot, int probe) |
---|
| 870 | +int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) |
---|
776 | 871 | { |
---|
777 | | - struct controller *ctrl = slot->ctrl; |
---|
| 872 | + struct controller *ctrl = to_ctrl(hotplug_slot); |
---|
778 | 873 | struct pci_dev *pdev = ctrl_dev(ctrl); |
---|
779 | 874 | u16 stat_mask = 0, ctrl_mask = 0; |
---|
780 | 875 | int rc; |
---|
.. | .. |
---|
782 | 877 | if (probe) |
---|
783 | 878 | return 0; |
---|
784 | 879 | |
---|
785 | | - down_write(&ctrl->reset_lock); |
---|
| 880 | + down_write_nested(&ctrl->reset_lock, ctrl->depth); |
---|
786 | 881 | |
---|
787 | 882 | if (!ATTN_BUTTN(ctrl)) { |
---|
788 | 883 | ctrl_mask |= PCI_EXP_SLTCTL_PDCE; |
---|
.. | .. |
---|
824 | 919 | } |
---|
825 | 920 | } |
---|
826 | 921 | |
---|
827 | | -static int pcie_init_slot(struct controller *ctrl) |
---|
828 | | -{ |
---|
829 | | - struct pci_bus *subordinate = ctrl_dev(ctrl)->subordinate; |
---|
830 | | - struct slot *slot; |
---|
831 | | - |
---|
832 | | - slot = kzalloc(sizeof(*slot), GFP_KERNEL); |
---|
833 | | - if (!slot) |
---|
834 | | - return -ENOMEM; |
---|
835 | | - |
---|
836 | | - down_read(&pci_bus_sem); |
---|
837 | | - slot->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; |
---|
838 | | - up_read(&pci_bus_sem); |
---|
839 | | - |
---|
840 | | - slot->ctrl = ctrl; |
---|
841 | | - mutex_init(&slot->lock); |
---|
842 | | - INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); |
---|
843 | | - ctrl->slot = slot; |
---|
844 | | - return 0; |
---|
845 | | -} |
---|
846 | | - |
---|
847 | | -static void pcie_cleanup_slot(struct controller *ctrl) |
---|
848 | | -{ |
---|
849 | | - struct slot *slot = ctrl->slot; |
---|
850 | | - |
---|
851 | | - cancel_delayed_work_sync(&slot->work); |
---|
852 | | - kfree(slot); |
---|
853 | | -} |
---|
854 | | - |
---|
855 | 922 | static inline void dbg_ctrl(struct controller *ctrl) |
---|
856 | 923 | { |
---|
857 | 924 | struct pci_dev *pdev = ctrl->pcie->port; |
---|
858 | 925 | u16 reg16; |
---|
859 | 926 | |
---|
860 | | - if (!pciehp_debug) |
---|
861 | | - return; |
---|
862 | | - |
---|
863 | | - ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); |
---|
| 927 | + ctrl_dbg(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); |
---|
864 | 928 | pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); |
---|
865 | | - ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); |
---|
| 929 | + ctrl_dbg(ctrl, "Slot Status : 0x%04x\n", reg16); |
---|
866 | 930 | pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); |
---|
867 | | - ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); |
---|
| 931 | + ctrl_dbg(ctrl, "Slot Control : 0x%04x\n", reg16); |
---|
868 | 932 | } |
---|
869 | 933 | |
---|
870 | 934 | #define FLAG(x, y) (((x) & (y)) ? '+' : '-') |
---|
871 | 935 | |
---|
| 936 | +static inline int pcie_hotplug_depth(struct pci_dev *dev) |
---|
| 937 | +{ |
---|
| 938 | + struct pci_bus *bus = dev->bus; |
---|
| 939 | + int depth = 0; |
---|
| 940 | + |
---|
| 941 | + while (bus->parent) { |
---|
| 942 | + bus = bus->parent; |
---|
| 943 | + if (bus->self && bus->self->is_hotplug_bridge) |
---|
| 944 | + depth++; |
---|
| 945 | + } |
---|
| 946 | + |
---|
| 947 | + return depth; |
---|
| 948 | +} |
---|
| 949 | + |
---|
872 | 950 | struct controller *pcie_init(struct pcie_device *dev) |
---|
873 | 951 | { |
---|
874 | 952 | struct controller *ctrl; |
---|
875 | | - u32 slot_cap, link_cap; |
---|
876 | | - u8 occupied, poweron; |
---|
| 953 | + u32 slot_cap, slot_cap2, link_cap; |
---|
| 954 | + u8 poweron; |
---|
877 | 955 | struct pci_dev *pdev = dev->port; |
---|
| 956 | + struct pci_bus *subordinate = pdev->subordinate; |
---|
878 | 957 | |
---|
879 | 958 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); |
---|
880 | 959 | if (!ctrl) |
---|
881 | | - goto abort; |
---|
| 960 | + return NULL; |
---|
882 | 961 | |
---|
883 | 962 | ctrl->pcie = dev; |
---|
| 963 | + ctrl->depth = pcie_hotplug_depth(dev->port); |
---|
884 | 964 | pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); |
---|
885 | 965 | |
---|
886 | 966 | if (pdev->hotplug_user_indicators) |
---|
.. | .. |
---|
895 | 975 | |
---|
896 | 976 | ctrl->slot_cap = slot_cap; |
---|
897 | 977 | mutex_init(&ctrl->ctrl_lock); |
---|
| 978 | + mutex_init(&ctrl->state_lock); |
---|
898 | 979 | init_rwsem(&ctrl->reset_lock); |
---|
899 | 980 | init_waitqueue_head(&ctrl->requester); |
---|
900 | 981 | init_waitqueue_head(&ctrl->queue); |
---|
| 982 | + INIT_DELAYED_WORK(&ctrl->button_work, pciehp_queue_pushbutton_work); |
---|
901 | 983 | dbg_ctrl(ctrl); |
---|
| 984 | + |
---|
| 985 | + down_read(&pci_bus_sem); |
---|
| 986 | + ctrl->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; |
---|
| 987 | + up_read(&pci_bus_sem); |
---|
| 988 | + |
---|
| 989 | + pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP2, &slot_cap2); |
---|
| 990 | + if (slot_cap2 & PCI_EXP_SLTCAP2_IBPD) { |
---|
| 991 | + pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_IBPD_DISABLE, |
---|
| 992 | + PCI_EXP_SLTCTL_IBPD_DISABLE); |
---|
| 993 | + ctrl->inband_presence_disabled = 1; |
---|
| 994 | + } |
---|
| 995 | + |
---|
| 996 | + if (dmi_first_match(inband_presence_disabled_dmi_table)) |
---|
| 997 | + ctrl->inband_presence_disabled = 1; |
---|
902 | 998 | |
---|
903 | 999 | /* Check if Data Link Layer Link Active Reporting is implemented */ |
---|
904 | 1000 | pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); |
---|
905 | | - if (link_cap & PCI_EXP_LNKCAP_DLLLARC) |
---|
906 | | - ctrl->link_active_reporting = 1; |
---|
907 | 1001 | |
---|
908 | 1002 | /* Clear all remaining event bits in Slot Status register. */ |
---|
909 | 1003 | pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, |
---|
.. | .. |
---|
911 | 1005 | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC | |
---|
912 | 1006 | PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC); |
---|
913 | 1007 | |
---|
914 | | - 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", |
---|
| 1008 | + ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c IbPresDis%c LLActRep%c%s\n", |
---|
915 | 1009 | (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19, |
---|
916 | 1010 | FLAG(slot_cap, PCI_EXP_SLTCAP_ABP), |
---|
917 | 1011 | FLAG(slot_cap, PCI_EXP_SLTCAP_PCP), |
---|
.. | .. |
---|
922 | 1016 | FLAG(slot_cap, PCI_EXP_SLTCAP_HPS), |
---|
923 | 1017 | FLAG(slot_cap, PCI_EXP_SLTCAP_EIP), |
---|
924 | 1018 | FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS), |
---|
| 1019 | + FLAG(slot_cap2, PCI_EXP_SLTCAP2_IBPD), |
---|
925 | 1020 | FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC), |
---|
926 | 1021 | pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : ""); |
---|
927 | | - |
---|
928 | | - if (pcie_init_slot(ctrl)) |
---|
929 | | - goto abort_ctrl; |
---|
930 | 1022 | |
---|
931 | 1023 | /* |
---|
932 | 1024 | * If empty slot's power status is on, turn power off. The IRQ isn't |
---|
933 | 1025 | * requested yet, so avoid triggering a notification with this command. |
---|
934 | 1026 | */ |
---|
935 | 1027 | if (POWER_CTRL(ctrl)) { |
---|
936 | | - pciehp_get_adapter_status(ctrl->slot, &occupied); |
---|
937 | | - pciehp_get_power_status(ctrl->slot, &poweron); |
---|
938 | | - if (!occupied && poweron) { |
---|
| 1028 | + pciehp_get_power_status(ctrl, &poweron); |
---|
| 1029 | + if (!pciehp_card_present_or_link_active(ctrl) && poweron) { |
---|
939 | 1030 | pcie_disable_notification(ctrl); |
---|
940 | | - pciehp_power_off_slot(ctrl->slot); |
---|
| 1031 | + pciehp_power_off_slot(ctrl); |
---|
941 | 1032 | } |
---|
942 | 1033 | } |
---|
943 | 1034 | |
---|
944 | 1035 | return ctrl; |
---|
945 | | - |
---|
946 | | -abort_ctrl: |
---|
947 | | - kfree(ctrl); |
---|
948 | | -abort: |
---|
949 | | - return NULL; |
---|
950 | 1036 | } |
---|
951 | 1037 | |
---|
952 | 1038 | void pciehp_release_ctrl(struct controller *ctrl) |
---|
953 | 1039 | { |
---|
954 | | - pcie_cleanup_slot(ctrl); |
---|
| 1040 | + cancel_delayed_work_sync(&ctrl->button_work); |
---|
955 | 1041 | kfree(ctrl); |
---|
956 | 1042 | } |
---|
957 | 1043 | |
---|
.. | .. |
---|
968 | 1054 | } |
---|
969 | 1055 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, |
---|
970 | 1056 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |
---|
| 1057 | +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0110, |
---|
| 1058 | + PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |
---|
971 | 1059 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400, |
---|
972 | 1060 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |
---|
973 | 1061 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0401, |
---|
974 | 1062 | PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |
---|
| 1063 | +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_HXT, 0x0401, |
---|
| 1064 | + PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); |
---|