diff options
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/Makefile | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/Kconfig.debug | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 93 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 17 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 77 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/ecrc.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 45 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/Makefile | 8 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme.c | 506 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme.h | 28 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme_acpi.c | 54 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 38 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_bus.c | 7 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 262 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 63 |
18 files changed, 919 insertions, 299 deletions
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 5a0c6ad53f8e..b8b494b3e0d0 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig | |||
@@ -46,3 +46,7 @@ config PCIEASPM_DEBUG | |||
46 | help | 46 | help |
47 | This enables PCI Express ASPM debug support. It will add per-device | 47 | This enables PCI Express ASPM debug support. It will add per-device |
48 | interface to control ASPM. | 48 | interface to control ASPM. |
49 | |||
50 | config PCIE_PME | ||
51 | def_bool y | ||
52 | depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI | ||
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index 11f6bb1eae24..ea654545e7c4 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile | |||
@@ -11,3 +11,5 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o | |||
11 | 11 | ||
12 | # Build PCI Express AER if needed | 12 | # Build PCI Express AER if needed |
13 | obj-$(CONFIG_PCIEAER) += aer/ | 13 | obj-$(CONFIG_PCIEAER) += aer/ |
14 | |||
15 | obj-$(CONFIG_PCIE_PME) += pme/ | ||
diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug index b8c925c1f6aa..9142949734f5 100644 --- a/drivers/pci/pcie/aer/Kconfig.debug +++ b/drivers/pci/pcie/aer/Kconfig.debug | |||
@@ -3,14 +3,14 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | config PCIEAER_INJECT | 5 | config PCIEAER_INJECT |
6 | tristate "PCIE AER error injector support" | 6 | tristate "PCIe AER error injector support" |
7 | depends on PCIEAER | 7 | depends on PCIEAER |
8 | default n | 8 | default n |
9 | help | 9 | help |
10 | This enables PCI Express Root Port Advanced Error Reporting | 10 | This enables PCI Express Root Port Advanced Error Reporting |
11 | (AER) software error injector. | 11 | (AER) software error injector. |
12 | 12 | ||
13 | Debuging PCIE AER code is quite difficult because it is hard | 13 | Debugging PCIe AER code is quite difficult because it is hard |
14 | to trigger various real hardware errors. Software based | 14 | to trigger various real hardware errors. Software based |
15 | error injection can fake almost all kinds of errors with the | 15 | error injection can fake almost all kinds of errors with the |
16 | help of a user space helper tool aer-inject, which can be | 16 | help of a user space helper tool aer-inject, which can be |
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 62d15f652bb6..f8f425b8731d 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PCIE AER software error injection support. | 2 | * PCIe AER software error injection support. |
3 | * | 3 | * |
4 | * Debuging PCIE AER code is quite difficult because it is hard to | 4 | * Debuging PCIe AER code is quite difficult because it is hard to |
5 | * trigger various real hardware errors. Software based error | 5 | * trigger various real hardware errors. Software based error |
6 | * injection can fake almost all kinds of errors with the help of a | 6 | * injection can fake almost all kinds of errors with the help of a |
7 | * user space helper tool aer-inject, which can be gotten from: | 7 | * user space helper tool aer-inject, which can be gotten from: |
@@ -21,8 +21,10 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/miscdevice.h> | 22 | #include <linux/miscdevice.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/slab.h> | ||
24 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
25 | #include <linux/uaccess.h> | 26 | #include <linux/uaccess.h> |
27 | #include <linux/stddef.h> | ||
26 | #include "aerdrv.h" | 28 | #include "aerdrv.h" |
27 | 29 | ||
28 | struct aer_error_inj { | 30 | struct aer_error_inj { |
@@ -35,10 +37,12 @@ struct aer_error_inj { | |||
35 | u32 header_log1; | 37 | u32 header_log1; |
36 | u32 header_log2; | 38 | u32 header_log2; |
37 | u32 header_log3; | 39 | u32 header_log3; |
40 | u16 domain; | ||
38 | }; | 41 | }; |
39 | 42 | ||
40 | struct aer_error { | 43 | struct aer_error { |
41 | struct list_head list; | 44 | struct list_head list; |
45 | u16 domain; | ||
42 | unsigned int bus; | 46 | unsigned int bus; |
43 | unsigned int devfn; | 47 | unsigned int devfn; |
44 | int pos_cap_err; | 48 | int pos_cap_err; |
@@ -66,22 +70,27 @@ static LIST_HEAD(pci_bus_ops_list); | |||
66 | /* Protect einjected and pci_bus_ops_list */ | 70 | /* Protect einjected and pci_bus_ops_list */ |
67 | static DEFINE_SPINLOCK(inject_lock); | 71 | static DEFINE_SPINLOCK(inject_lock); |
68 | 72 | ||
69 | static void aer_error_init(struct aer_error *err, unsigned int bus, | 73 | static void aer_error_init(struct aer_error *err, u16 domain, |
70 | unsigned int devfn, int pos_cap_err) | 74 | unsigned int bus, unsigned int devfn, |
75 | int pos_cap_err) | ||
71 | { | 76 | { |
72 | INIT_LIST_HEAD(&err->list); | 77 | INIT_LIST_HEAD(&err->list); |
78 | err->domain = domain; | ||
73 | err->bus = bus; | 79 | err->bus = bus; |
74 | err->devfn = devfn; | 80 | err->devfn = devfn; |
75 | err->pos_cap_err = pos_cap_err; | 81 | err->pos_cap_err = pos_cap_err; |
76 | } | 82 | } |
77 | 83 | ||
78 | /* inject_lock must be held before calling */ | 84 | /* inject_lock must be held before calling */ |
79 | static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) | 85 | static struct aer_error *__find_aer_error(u16 domain, unsigned int bus, |
86 | unsigned int devfn) | ||
80 | { | 87 | { |
81 | struct aer_error *err; | 88 | struct aer_error *err; |
82 | 89 | ||
83 | list_for_each_entry(err, &einjected, list) { | 90 | list_for_each_entry(err, &einjected, list) { |
84 | if (bus == err->bus && devfn == err->devfn) | 91 | if (domain == err->domain && |
92 | bus == err->bus && | ||
93 | devfn == err->devfn) | ||
85 | return err; | 94 | return err; |
86 | } | 95 | } |
87 | return NULL; | 96 | return NULL; |
@@ -90,7 +99,10 @@ static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) | |||
90 | /* inject_lock must be held before calling */ | 99 | /* inject_lock must be held before calling */ |
91 | static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) | 100 | static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) |
92 | { | 101 | { |
93 | return __find_aer_error(dev->bus->number, dev->devfn); | 102 | int domain = pci_domain_nr(dev->bus); |
103 | if (domain < 0) | ||
104 | return NULL; | ||
105 | return __find_aer_error((u16)domain, dev->bus->number, dev->devfn); | ||
94 | } | 106 | } |
95 | 107 | ||
96 | /* inject_lock must be held before calling */ | 108 | /* inject_lock must be held before calling */ |
@@ -172,11 +184,15 @@ static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where, | |||
172 | struct aer_error *err; | 184 | struct aer_error *err; |
173 | unsigned long flags; | 185 | unsigned long flags; |
174 | struct pci_ops *ops; | 186 | struct pci_ops *ops; |
187 | int domain; | ||
175 | 188 | ||
176 | spin_lock_irqsave(&inject_lock, flags); | 189 | spin_lock_irqsave(&inject_lock, flags); |
177 | if (size != sizeof(u32)) | 190 | if (size != sizeof(u32)) |
178 | goto out; | 191 | goto out; |
179 | err = __find_aer_error(bus->number, devfn); | 192 | domain = pci_domain_nr(bus); |
193 | if (domain < 0) | ||
194 | goto out; | ||
195 | err = __find_aer_error((u16)domain, bus->number, devfn); | ||
180 | if (!err) | 196 | if (!err) |
181 | goto out; | 197 | goto out; |
182 | 198 | ||
@@ -200,11 +216,15 @@ int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, | |||
200 | unsigned long flags; | 216 | unsigned long flags; |
201 | int rw1cs; | 217 | int rw1cs; |
202 | struct pci_ops *ops; | 218 | struct pci_ops *ops; |
219 | int domain; | ||
203 | 220 | ||
204 | spin_lock_irqsave(&inject_lock, flags); | 221 | spin_lock_irqsave(&inject_lock, flags); |
205 | if (size != sizeof(u32)) | 222 | if (size != sizeof(u32)) |
206 | goto out; | 223 | goto out; |
207 | err = __find_aer_error(bus->number, devfn); | 224 | domain = pci_domain_nr(bus); |
225 | if (domain < 0) | ||
226 | goto out; | ||
227 | err = __find_aer_error((u16)domain, bus->number, devfn); | ||
208 | if (!err) | 228 | if (!err) |
209 | goto out; | 229 | goto out; |
210 | 230 | ||
@@ -262,7 +282,7 @@ out: | |||
262 | static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) | 282 | static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) |
263 | { | 283 | { |
264 | while (1) { | 284 | while (1) { |
265 | if (!dev->is_pcie) | 285 | if (!pci_is_pcie(dev)) |
266 | break; | 286 | break; |
267 | if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | 287 | if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) |
268 | return dev; | 288 | return dev; |
@@ -302,28 +322,31 @@ static int aer_inject(struct aer_error_inj *einj) | |||
302 | unsigned long flags; | 322 | unsigned long flags; |
303 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); | 323 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); |
304 | int pos_cap_err, rp_pos_cap_err; | 324 | int pos_cap_err, rp_pos_cap_err; |
305 | u32 sever; | 325 | u32 sever, cor_mask, uncor_mask; |
306 | int ret = 0; | 326 | int ret = 0; |
307 | 327 | ||
308 | dev = pci_get_bus_and_slot(einj->bus, devfn); | 328 | dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); |
309 | if (!dev) | 329 | if (!dev) |
310 | return -EINVAL; | 330 | return -ENODEV; |
311 | rpdev = pcie_find_root_port(dev); | 331 | rpdev = pcie_find_root_port(dev); |
312 | if (!rpdev) { | 332 | if (!rpdev) { |
313 | ret = -EINVAL; | 333 | ret = -ENOTTY; |
314 | goto out_put; | 334 | goto out_put; |
315 | } | 335 | } |
316 | 336 | ||
317 | pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 337 | pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
318 | if (!pos_cap_err) { | 338 | if (!pos_cap_err) { |
319 | ret = -EIO; | 339 | ret = -ENOTTY; |
320 | goto out_put; | 340 | goto out_put; |
321 | } | 341 | } |
322 | pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); | 342 | pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); |
343 | pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask); | ||
344 | pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, | ||
345 | &uncor_mask); | ||
323 | 346 | ||
324 | rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); | 347 | rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); |
325 | if (!rp_pos_cap_err) { | 348 | if (!rp_pos_cap_err) { |
326 | ret = -EIO; | 349 | ret = -ENOTTY; |
327 | goto out_put; | 350 | goto out_put; |
328 | } | 351 | } |
329 | 352 | ||
@@ -344,7 +367,8 @@ static int aer_inject(struct aer_error_inj *einj) | |||
344 | if (!err) { | 367 | if (!err) { |
345 | err = err_alloc; | 368 | err = err_alloc; |
346 | err_alloc = NULL; | 369 | err_alloc = NULL; |
347 | aer_error_init(err, einj->bus, devfn, pos_cap_err); | 370 | aer_error_init(err, einj->domain, einj->bus, devfn, |
371 | pos_cap_err); | ||
348 | list_add(&err->list, &einjected); | 372 | list_add(&err->list, &einjected); |
349 | } | 373 | } |
350 | err->uncor_status |= einj->uncor_status; | 374 | err->uncor_status |= einj->uncor_status; |
@@ -354,11 +378,27 @@ static int aer_inject(struct aer_error_inj *einj) | |||
354 | err->header_log2 = einj->header_log2; | 378 | err->header_log2 = einj->header_log2; |
355 | err->header_log3 = einj->header_log3; | 379 | err->header_log3 = einj->header_log3; |
356 | 380 | ||
381 | if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { | ||
382 | ret = -EINVAL; | ||
383 | printk(KERN_WARNING "The correctable error(s) is masked " | ||
384 | "by device\n"); | ||
385 | spin_unlock_irqrestore(&inject_lock, flags); | ||
386 | goto out_put; | ||
387 | } | ||
388 | if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { | ||
389 | ret = -EINVAL; | ||
390 | printk(KERN_WARNING "The uncorrectable error(s) is masked " | ||
391 | "by device\n"); | ||
392 | spin_unlock_irqrestore(&inject_lock, flags); | ||
393 | goto out_put; | ||
394 | } | ||
395 | |||
357 | rperr = __find_aer_error_by_dev(rpdev); | 396 | rperr = __find_aer_error_by_dev(rpdev); |
358 | if (!rperr) { | 397 | if (!rperr) { |
359 | rperr = rperr_alloc; | 398 | rperr = rperr_alloc; |
360 | rperr_alloc = NULL; | 399 | rperr_alloc = NULL; |
361 | aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, | 400 | aer_error_init(rperr, pci_domain_nr(rpdev->bus), |
401 | rpdev->bus->number, rpdev->devfn, | ||
362 | rp_pos_cap_err); | 402 | rp_pos_cap_err); |
363 | list_add(&rperr->list, &einjected); | 403 | list_add(&rperr->list, &einjected); |
364 | } | 404 | } |
@@ -392,8 +432,14 @@ static int aer_inject(struct aer_error_inj *einj) | |||
392 | if (ret) | 432 | if (ret) |
393 | goto out_put; | 433 | goto out_put; |
394 | 434 | ||
395 | if (find_aer_device(rpdev, &edev)) | 435 | if (find_aer_device(rpdev, &edev)) { |
436 | if (!get_service_data(edev)) { | ||
437 | printk(KERN_WARNING "AER service is not initialized\n"); | ||
438 | ret = -EINVAL; | ||
439 | goto out_put; | ||
440 | } | ||
396 | aer_irq(-1, edev); | 441 | aer_irq(-1, edev); |
442 | } | ||
397 | else | 443 | else |
398 | ret = -EINVAL; | 444 | ret = -EINVAL; |
399 | out_put: | 445 | out_put: |
@@ -411,10 +457,11 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, | |||
411 | 457 | ||
412 | if (!capable(CAP_SYS_ADMIN)) | 458 | if (!capable(CAP_SYS_ADMIN)) |
413 | return -EPERM; | 459 | return -EPERM; |
414 | 460 | if (usize < offsetof(struct aer_error_inj, domain) || | |
415 | if (usize != sizeof(struct aer_error_inj)) | 461 | usize > sizeof(einj)) |
416 | return -EINVAL; | 462 | return -EINVAL; |
417 | 463 | ||
464 | memset(&einj, 0, sizeof(einj)); | ||
418 | if (copy_from_user(&einj, ubuf, usize)) | 465 | if (copy_from_user(&einj, ubuf, usize)) |
419 | return -EFAULT; | 466 | return -EFAULT; |
420 | 467 | ||
@@ -452,7 +499,7 @@ static void __exit aer_inject_exit(void) | |||
452 | } | 499 | } |
453 | 500 | ||
454 | spin_lock_irqsave(&inject_lock, flags); | 501 | spin_lock_irqsave(&inject_lock, flags); |
455 | list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { | 502 | list_for_each_entry_safe(err, err_next, &einjected, list) { |
456 | list_del(&err->list); | 503 | list_del(&err->list); |
457 | kfree(err); | 504 | kfree(err); |
458 | } | 505 | } |
@@ -462,5 +509,5 @@ static void __exit aer_inject_exit(void) | |||
462 | module_init(aer_inject_init); | 509 | module_init(aer_inject_init); |
463 | module_exit(aer_inject_exit); | 510 | module_exit(aer_inject_exit); |
464 | 511 | ||
465 | MODULE_DESCRIPTION("PCIE AER software error injector"); | 512 | MODULE_DESCRIPTION("PCIe AER software error injector"); |
466 | MODULE_LICENSE("GPL"); | 513 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 40c3cc5d1caf..7a711ee314b7 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/pcieport_if.h> | 27 | #include <linux/pcieport_if.h> |
28 | #include <linux/slab.h> | ||
28 | 29 | ||
29 | #include "aerdrv.h" | 30 | #include "aerdrv.h" |
30 | #include "../../pci.h" | 31 | #include "../../pci.h" |
@@ -53,7 +54,7 @@ static struct pci_error_handlers aer_error_handlers = { | |||
53 | 54 | ||
54 | static struct pcie_port_service_driver aerdriver = { | 55 | static struct pcie_port_service_driver aerdriver = { |
55 | .name = "aer", | 56 | .name = "aer", |
56 | .port_type = PCIE_RC_PORT, | 57 | .port_type = PCI_EXP_TYPE_ROOT_PORT, |
57 | .service = PCIE_PORT_SERVICE_AER, | 58 | .service = PCIE_PORT_SERVICE_AER, |
58 | 59 | ||
59 | .probe = aer_probe, | 60 | .probe = aer_probe, |
@@ -155,7 +156,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) | |||
155 | mutex_init(&rpc->rpc_mutex); | 156 | mutex_init(&rpc->rpc_mutex); |
156 | init_waitqueue_head(&rpc->wait_release); | 157 | init_waitqueue_head(&rpc->wait_release); |
157 | 158 | ||
158 | /* Use PCIE bus function to store rpc into PCIE device */ | 159 | /* Use PCIe bus function to store rpc into PCIe device */ |
159 | set_service_data(dev, rpc); | 160 | set_service_data(dev, rpc); |
160 | 161 | ||
161 | return rpc; | 162 | return rpc; |
@@ -243,11 +244,17 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) | |||
243 | 244 | ||
244 | /* Assert Secondary Bus Reset */ | 245 | /* Assert Secondary Bus Reset */ |
245 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); | 246 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); |
246 | p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET; | 247 | p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET; |
247 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); | 248 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); |
248 | 249 | ||
250 | /* | ||
251 | * we should send hot reset message for 2ms to allow it time to | ||
252 | * propogate to all downstream ports | ||
253 | */ | ||
254 | msleep(2); | ||
255 | |||
249 | /* De-assert Secondary Bus Reset */ | 256 | /* De-assert Secondary Bus Reset */ |
250 | p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET; | 257 | p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; |
251 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); | 258 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); |
252 | 259 | ||
253 | /* | 260 | /* |
@@ -295,7 +302,7 @@ static void aer_error_resume(struct pci_dev *dev) | |||
295 | u16 reg16; | 302 | u16 reg16; |
296 | 303 | ||
297 | /* Clean up Root device status */ | 304 | /* Clean up Root device status */ |
298 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 305 | pos = pci_pcie_cap(dev); |
299 | pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); | 306 | pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); |
300 | pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); | 307 | pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); |
301 | 308 | ||
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 8edb2f300e8f..04814087658d 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c | |||
@@ -24,7 +24,7 @@ | |||
24 | * | 24 | * |
25 | * @return: Zero on success. Nonzero otherwise. | 25 | * @return: Zero on success. Nonzero otherwise. |
26 | * | 26 | * |
27 | * Invoked when PCIE bus loads AER service driver. To avoid conflict with | 27 | * Invoked when PCIe bus loads AER service driver. To avoid conflict with |
28 | * BIOS AER support requires BIOS to yield AER control to OS native driver. | 28 | * BIOS AER support requires BIOS to yield AER control to OS native driver. |
29 | **/ | 29 | **/ |
30 | int aer_osc_setup(struct pcie_device *pciedev) | 30 | int aer_osc_setup(struct pcie_device *pciedev) |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 9f5ccbeb4fa5..aceb04b67b60 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pm.h> | 23 | #include <linux/pm.h> |
24 | #include <linux/suspend.h> | 24 | #include <linux/suspend.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/slab.h> | ||
26 | #include "aerdrv.h" | 27 | #include "aerdrv.h" |
27 | 28 | ||
28 | static int forceload; | 29 | static int forceload; |
@@ -35,11 +36,14 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev) | |||
35 | u16 reg16 = 0; | 36 | u16 reg16 = 0; |
36 | int pos; | 37 | int pos; |
37 | 38 | ||
39 | if (dev->aer_firmware_first) | ||
40 | return -EIO; | ||
41 | |||
38 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 42 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
39 | if (!pos) | 43 | if (!pos) |
40 | return -EIO; | 44 | return -EIO; |
41 | 45 | ||
42 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 46 | pos = pci_pcie_cap(dev); |
43 | if (!pos) | 47 | if (!pos) |
44 | return -EIO; | 48 | return -EIO; |
45 | 49 | ||
@@ -60,7 +64,10 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev) | |||
60 | u16 reg16 = 0; | 64 | u16 reg16 = 0; |
61 | int pos; | 65 | int pos; |
62 | 66 | ||
63 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 67 | if (dev->aer_firmware_first) |
68 | return -EIO; | ||
69 | |||
70 | pos = pci_pcie_cap(dev); | ||
64 | if (!pos) | 71 | if (!pos) |
65 | return -EIO; | 72 | return -EIO; |
66 | 73 | ||
@@ -78,48 +85,27 @@ EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); | |||
78 | int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) | 85 | int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) |
79 | { | 86 | { |
80 | int pos; | 87 | int pos; |
81 | u32 status, mask; | 88 | u32 status; |
82 | 89 | ||
83 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 90 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
84 | if (!pos) | 91 | if (!pos) |
85 | return -EIO; | 92 | return -EIO; |
86 | 93 | ||
87 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); | 94 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
88 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); | 95 | if (status) |
89 | if (dev->error_state == pci_channel_io_normal) | 96 | pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); |
90 | status &= ~mask; /* Clear corresponding nonfatal bits */ | ||
91 | else | ||
92 | status &= mask; /* Clear corresponding fatal bits */ | ||
93 | pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); | ||
94 | 97 | ||
95 | return 0; | 98 | return 0; |
96 | } | 99 | } |
97 | EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); | 100 | EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); |
98 | 101 | ||
99 | #if 0 | ||
100 | int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) | ||
101 | { | ||
102 | int pos; | ||
103 | u32 status; | ||
104 | |||
105 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
106 | if (!pos) | ||
107 | return -EIO; | ||
108 | |||
109 | pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); | ||
110 | pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | #endif /* 0 */ | ||
115 | |||
116 | static int set_device_error_reporting(struct pci_dev *dev, void *data) | 102 | static int set_device_error_reporting(struct pci_dev *dev, void *data) |
117 | { | 103 | { |
118 | bool enable = *((bool *)data); | 104 | bool enable = *((bool *)data); |
119 | 105 | ||
120 | if (dev->pcie_type == PCIE_RC_PORT || | 106 | if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) || |
121 | dev->pcie_type == PCIE_SW_UPSTREAM_PORT || | 107 | (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) || |
122 | dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) { | 108 | (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) { |
123 | if (enable) | 109 | if (enable) |
124 | pci_enable_pcie_error_reporting(dev); | 110 | pci_enable_pcie_error_reporting(dev); |
125 | else | 111 | else |
@@ -218,7 +204,7 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
218 | */ | 204 | */ |
219 | if (atomic_read(&dev->enable_cnt) == 0) | 205 | if (atomic_read(&dev->enable_cnt) == 0) |
220 | return 0; | 206 | return 0; |
221 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 207 | pos = pci_pcie_cap(dev); |
222 | if (!pos) | 208 | if (!pos) |
223 | return 0; | 209 | return 0; |
224 | /* Check if AER is enabled */ | 210 | /* Check if AER is enabled */ |
@@ -431,10 +417,9 @@ static int find_aer_service_iter(struct device *device, void *data) | |||
431 | result = (struct find_aer_service_data *) data; | 417 | result = (struct find_aer_service_data *) data; |
432 | 418 | ||
433 | if (device->bus == &pcie_port_bus_type) { | 419 | if (device->bus == &pcie_port_bus_type) { |
434 | struct pcie_port_data *port_data; | 420 | struct pcie_device *pcie = to_pcie_device(device); |
435 | 421 | ||
436 | port_data = pci_get_drvdata(to_pcie_device(device)->port); | 422 | if (pcie->port->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) |
437 | if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT) | ||
438 | result->is_downstream = 1; | 423 | result->is_downstream = 1; |
439 | 424 | ||
440 | driver = device->driver; | 425 | driver = device->driver; |
@@ -603,7 +588,7 @@ static void handle_error_source(struct pcie_device *aerdev, | |||
603 | * aer_enable_rootport - enable Root Port's interrupts when receiving messages | 588 | * aer_enable_rootport - enable Root Port's interrupts when receiving messages |
604 | * @rpc: pointer to a Root Port data structure | 589 | * @rpc: pointer to a Root Port data structure |
605 | * | 590 | * |
606 | * Invoked when PCIE bus loads AER service driver. | 591 | * Invoked when PCIe bus loads AER service driver. |
607 | */ | 592 | */ |
608 | void aer_enable_rootport(struct aer_rpc *rpc) | 593 | void aer_enable_rootport(struct aer_rpc *rpc) |
609 | { | 594 | { |
@@ -612,8 +597,8 @@ void aer_enable_rootport(struct aer_rpc *rpc) | |||
612 | u16 reg16; | 597 | u16 reg16; |
613 | u32 reg32; | 598 | u32 reg32; |
614 | 599 | ||
615 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 600 | pos = pci_pcie_cap(pdev); |
616 | /* Clear PCIE Capability's Device Status */ | 601 | /* Clear PCIe Capability's Device Status */ |
617 | pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); | 602 | pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); |
618 | pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); | 603 | pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); |
619 | 604 | ||
@@ -647,7 +632,7 @@ void aer_enable_rootport(struct aer_rpc *rpc) | |||
647 | * disable_root_aer - disable Root Port's interrupts when receiving messages | 632 | * disable_root_aer - disable Root Port's interrupts when receiving messages |
648 | * @rpc: pointer to a Root Port data structure | 633 | * @rpc: pointer to a Root Port data structure |
649 | * | 634 | * |
650 | * Invoked when PCIE bus unloads AER service driver. | 635 | * Invoked when PCIe bus unloads AER service driver. |
651 | */ | 636 | */ |
652 | static void disable_root_aer(struct aer_rpc *rpc) | 637 | static void disable_root_aer(struct aer_rpc *rpc) |
653 | { | 638 | { |
@@ -874,8 +859,22 @@ void aer_delete_rootport(struct aer_rpc *rpc) | |||
874 | */ | 859 | */ |
875 | int aer_init(struct pcie_device *dev) | 860 | int aer_init(struct pcie_device *dev) |
876 | { | 861 | { |
877 | if (aer_osc_setup(dev) && !forceload) | 862 | if (dev->port->aer_firmware_first) { |
878 | return -ENXIO; | 863 | dev_printk(KERN_DEBUG, &dev->device, |
864 | "PCIe errors handled by platform firmware.\n"); | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | if (aer_osc_setup(dev)) | ||
869 | goto out; | ||
879 | 870 | ||
880 | return 0; | 871 | return 0; |
872 | out: | ||
873 | if (forceload) { | ||
874 | dev_printk(KERN_DEBUG, &dev->device, | ||
875 | "aerdrv forceload requested.\n"); | ||
876 | dev->port->aer_firmware_first = 0; | ||
877 | return 0; | ||
878 | } | ||
879 | return -ENXIO; | ||
881 | } | 880 | } |
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 44acde72294f..9d3e4c8d0184 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -184,7 +184,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
184 | 184 | ||
185 | if (info->status == 0) { | 185 | if (info->status == 0) { |
186 | AER_PR(info, dev, | 186 | AER_PR(info, dev, |
187 | "PCIE Bus Error: severity=%s, type=Unaccessible, " | 187 | "PCIe Bus Error: severity=%s, type=Unaccessible, " |
188 | "id=%04x(Unregistered Agent ID)\n", | 188 | "id=%04x(Unregistered Agent ID)\n", |
189 | aer_error_severity_string[info->severity], id); | 189 | aer_error_severity_string[info->severity], id); |
190 | } else { | 190 | } else { |
@@ -194,7 +194,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
194 | agent = AER_GET_AGENT(info->severity, info->status); | 194 | agent = AER_GET_AGENT(info->severity, info->status); |
195 | 195 | ||
196 | AER_PR(info, dev, | 196 | AER_PR(info, dev, |
197 | "PCIE Bus Error: severity=%s, type=%s, id=%04x(%s)\n", | 197 | "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", |
198 | aer_error_severity_string[info->severity], | 198 | aer_error_severity_string[info->severity], |
199 | aer_error_layer[layer], id, aer_agent_string[agent]); | 199 | aer_error_layer[layer], id, aer_agent_string[agent]); |
200 | 200 | ||
diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c index a928d8ab6bda..a2747a663bc9 100644 --- a/drivers/pci/pcie/aer/ecrc.c +++ b/drivers/pci/pcie/aer/ecrc.c | |||
@@ -51,7 +51,7 @@ static int enable_ecrc_checking(struct pci_dev *dev) | |||
51 | int pos; | 51 | int pos; |
52 | u32 reg32; | 52 | u32 reg32; |
53 | 53 | ||
54 | if (!dev->is_pcie) | 54 | if (!pci_is_pcie(dev)) |
55 | return -ENODEV; | 55 | return -ENODEV; |
56 | 56 | ||
57 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 57 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
@@ -79,7 +79,7 @@ static int disable_ecrc_checking(struct pci_dev *dev) | |||
79 | int pos; | 79 | int pos; |
80 | u32 reg32; | 80 | u32 reg32; |
81 | 81 | ||
82 | if (!dev->is_pcie) | 82 | if (!pci_is_pcie(dev)) |
83 | return -ENODEV; | 83 | return -ENODEV; |
84 | 84 | ||
85 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 85 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 5b7056cec00c..be53d98fa384 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * File: drivers/pci/pcie/aspm.c | 2 | * File: drivers/pci/pcie/aspm.c |
3 | * Enabling PCIE link L0s/L1 state and Clock Power Management | 3 | * Enabling PCIe link L0s/L1 state and Clock Power Management |
4 | * | 4 | * |
5 | * Copyright (C) 2007 Intel | 5 | * Copyright (C) 2007 Intel |
6 | * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) | 6 | * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) |
@@ -122,7 +122,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) | |||
122 | struct pci_bus *linkbus = link->pdev->subordinate; | 122 | struct pci_bus *linkbus = link->pdev->subordinate; |
123 | 123 | ||
124 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 124 | list_for_each_entry(child, &linkbus->devices, bus_list) { |
125 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); | 125 | pos = pci_pcie_cap(child); |
126 | if (!pos) | 126 | if (!pos) |
127 | return; | 127 | return; |
128 | pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); | 128 | pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); |
@@ -156,7 +156,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) | |||
156 | 156 | ||
157 | /* All functions should have the same cap and state, take the worst */ | 157 | /* All functions should have the same cap and state, take the worst */ |
158 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 158 | list_for_each_entry(child, &linkbus->devices, bus_list) { |
159 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); | 159 | pos = pci_pcie_cap(child); |
160 | if (!pos) | 160 | if (!pos) |
161 | return; | 161 | return; |
162 | pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); | 162 | pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); |
@@ -191,23 +191,23 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) | |||
191 | * Configuration, so just check one function | 191 | * Configuration, so just check one function |
192 | */ | 192 | */ |
193 | child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); | 193 | child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); |
194 | BUG_ON(!child->is_pcie); | 194 | BUG_ON(!pci_is_pcie(child)); |
195 | 195 | ||
196 | /* Check downstream component if bit Slot Clock Configuration is 1 */ | 196 | /* Check downstream component if bit Slot Clock Configuration is 1 */ |
197 | cpos = pci_find_capability(child, PCI_CAP_ID_EXP); | 197 | cpos = pci_pcie_cap(child); |
198 | pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); | 198 | pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); |
199 | if (!(reg16 & PCI_EXP_LNKSTA_SLC)) | 199 | if (!(reg16 & PCI_EXP_LNKSTA_SLC)) |
200 | same_clock = 0; | 200 | same_clock = 0; |
201 | 201 | ||
202 | /* Check upstream component if bit Slot Clock Configuration is 1 */ | 202 | /* Check upstream component if bit Slot Clock Configuration is 1 */ |
203 | ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); | 203 | ppos = pci_pcie_cap(parent); |
204 | pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); | 204 | pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); |
205 | if (!(reg16 & PCI_EXP_LNKSTA_SLC)) | 205 | if (!(reg16 & PCI_EXP_LNKSTA_SLC)) |
206 | same_clock = 0; | 206 | same_clock = 0; |
207 | 207 | ||
208 | /* Configure downstream component, all functions */ | 208 | /* Configure downstream component, all functions */ |
209 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 209 | list_for_each_entry(child, &linkbus->devices, bus_list) { |
210 | cpos = pci_find_capability(child, PCI_CAP_ID_EXP); | 210 | cpos = pci_pcie_cap(child); |
211 | pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); | 211 | pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); |
212 | child_reg[PCI_FUNC(child->devfn)] = reg16; | 212 | child_reg[PCI_FUNC(child->devfn)] = reg16; |
213 | if (same_clock) | 213 | if (same_clock) |
@@ -247,7 +247,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) | |||
247 | dev_printk(KERN_ERR, &parent->dev, | 247 | dev_printk(KERN_ERR, &parent->dev, |
248 | "ASPM: Could not configure common clock\n"); | 248 | "ASPM: Could not configure common clock\n"); |
249 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 249 | list_for_each_entry(child, &linkbus->devices, bus_list) { |
250 | cpos = pci_find_capability(child, PCI_CAP_ID_EXP); | 250 | cpos = pci_pcie_cap(child); |
251 | pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, | 251 | pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, |
252 | child_reg[PCI_FUNC(child->devfn)]); | 252 | child_reg[PCI_FUNC(child->devfn)]); |
253 | } | 253 | } |
@@ -300,7 +300,7 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev, | |||
300 | u16 reg16; | 300 | u16 reg16; |
301 | u32 reg32; | 301 | u32 reg32; |
302 | 302 | ||
303 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 303 | pos = pci_pcie_cap(pdev); |
304 | pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); | 304 | pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); |
305 | info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; | 305 | info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; |
306 | info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; | 306 | info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; |
@@ -420,7 +420,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | |||
420 | child->pcie_type != PCI_EXP_TYPE_LEG_END) | 420 | child->pcie_type != PCI_EXP_TYPE_LEG_END) |
421 | continue; | 421 | continue; |
422 | 422 | ||
423 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); | 423 | pos = pci_pcie_cap(child); |
424 | pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); | 424 | pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); |
425 | /* Calculate endpoint L0s acceptable latency */ | 425 | /* Calculate endpoint L0s acceptable latency */ |
426 | encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; | 426 | encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; |
@@ -436,7 +436,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | |||
436 | static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) | 436 | static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) |
437 | { | 437 | { |
438 | u16 reg16; | 438 | u16 reg16; |
439 | int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 439 | int pos = pci_pcie_cap(pdev); |
440 | 440 | ||
441 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); | 441 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); |
442 | reg16 &= ~0x3; | 442 | reg16 &= ~0x3; |
@@ -499,11 +499,11 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
499 | int pos; | 499 | int pos; |
500 | u32 reg32; | 500 | u32 reg32; |
501 | /* | 501 | /* |
502 | * Some functions in a slot might not all be PCIE functions, | 502 | * Some functions in a slot might not all be PCIe functions, |
503 | * very strange. Disable ASPM for the whole slot | 503 | * very strange. Disable ASPM for the whole slot |
504 | */ | 504 | */ |
505 | list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { | 505 | list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { |
506 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); | 506 | pos = pci_pcie_cap(child); |
507 | if (!pos) | 507 | if (!pos) |
508 | return -EINVAL; | 508 | return -EINVAL; |
509 | /* | 509 | /* |
@@ -563,7 +563,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
563 | struct pcie_link_state *link; | 563 | struct pcie_link_state *link; |
564 | int blacklist = !!pcie_aspm_sanity_check(pdev); | 564 | int blacklist = !!pcie_aspm_sanity_check(pdev); |
565 | 565 | ||
566 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) | 566 | if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) |
567 | return; | 567 | return; |
568 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 568 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
569 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 569 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
@@ -629,7 +629,8 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
629 | struct pci_dev *parent = pdev->bus->self; | 629 | struct pci_dev *parent = pdev->bus->self; |
630 | struct pcie_link_state *link, *root, *parent_link; | 630 | struct pcie_link_state *link, *root, *parent_link; |
631 | 631 | ||
632 | if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) | 632 | if (aspm_disabled || !pci_is_pcie(pdev) || |
633 | !parent || !parent->link_state) | ||
633 | return; | 634 | return; |
634 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | 635 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
635 | (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) | 636 | (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) |
@@ -670,7 +671,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) | |||
670 | { | 671 | { |
671 | struct pcie_link_state *link = pdev->link_state; | 672 | struct pcie_link_state *link = pdev->link_state; |
672 | 673 | ||
673 | if (aspm_disabled || !pdev->is_pcie || !link) | 674 | if (aspm_disabled || !pci_is_pcie(pdev) || !link) |
674 | return; | 675 | return; |
675 | if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | 676 | if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
676 | (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) | 677 | (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) |
@@ -696,7 +697,7 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) | |||
696 | struct pci_dev *parent = pdev->bus->self; | 697 | struct pci_dev *parent = pdev->bus->self; |
697 | struct pcie_link_state *link; | 698 | struct pcie_link_state *link; |
698 | 699 | ||
699 | if (aspm_disabled || !pdev->is_pcie) | 700 | if (aspm_disabled || !pci_is_pcie(pdev)) |
700 | return; | 701 | return; |
701 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || | 702 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || |
702 | pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) | 703 | pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) |
@@ -841,8 +842,9 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) | |||
841 | { | 842 | { |
842 | struct pcie_link_state *link_state = pdev->link_state; | 843 | struct pcie_link_state *link_state = pdev->link_state; |
843 | 844 | ||
844 | if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 845 | if (!pci_is_pcie(pdev) || |
845 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) | 846 | (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
847 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) | ||
846 | return; | 848 | return; |
847 | 849 | ||
848 | if (link_state->aspm_support) | 850 | if (link_state->aspm_support) |
@@ -857,8 +859,9 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
857 | { | 859 | { |
858 | struct pcie_link_state *link_state = pdev->link_state; | 860 | struct pcie_link_state *link_state = pdev->link_state; |
859 | 861 | ||
860 | if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 862 | if (!pci_is_pcie(pdev) || |
861 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) | 863 | (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
864 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) | ||
862 | return; | 865 | return; |
863 | 866 | ||
864 | if (link_state->aspm_support) | 867 | if (link_state->aspm_support) |
diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile new file mode 100644 index 000000000000..8b9238053080 --- /dev/null +++ b/drivers/pci/pcie/pme/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for PCI-Express Root Port PME signaling driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCIE_PME) += pmedriver.o | ||
6 | |||
7 | pmedriver-objs := pcie_pme.o | ||
8 | pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o | ||
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c new file mode 100644 index 000000000000..aac285a16b62 --- /dev/null +++ b/drivers/pci/pcie/pme/pcie_pme.c | |||
@@ -0,0 +1,506 @@ | |||
1 | /* | ||
2 | * PCIe Native PME support | ||
3 | * | ||
4 | * Copyright (C) 2007 - 2009 Intel Corp | ||
5 | * Copyright (C) 2007 - 2009 Shaohua Li <shaohua.li@intel.com> | ||
6 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License V2. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/pcieport_if.h> | ||
22 | #include <linux/acpi.h> | ||
23 | #include <linux/pci-acpi.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | |||
26 | #include "../../pci.h" | ||
27 | #include "pcie_pme.h" | ||
28 | |||
29 | #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ | ||
30 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | ||
31 | |||
32 | /* | ||
33 | * If set, this switch will prevent the PCIe root port PME service driver from | ||
34 | * being registered. Consequently, the interrupt-based PCIe PME signaling will | ||
35 | * not be used by any PCIe root ports in that case. | ||
36 | */ | ||
37 | static bool pcie_pme_disabled; | ||
38 | |||
39 | /* | ||
40 | * The PCI Express Base Specification 2.0, Section 6.1.8, states the following: | ||
41 | * "In order to maintain compatibility with non-PCI Express-aware system | ||
42 | * software, system power management logic must be configured by firmware to use | ||
43 | * the legacy mechanism of signaling PME by default. PCI Express-aware system | ||
44 | * software must notify the firmware prior to enabling native, interrupt-based | ||
45 | * PME signaling." However, if the platform doesn't provide us with a suitable | ||
46 | * notification mechanism or the notification fails, it is not clear whether or | ||
47 | * not we are supposed to use the interrupt-based PCIe PME signaling. The | ||
48 | * switch below can be used to indicate the desired behaviour. When set, it | ||
49 | * will make the kernel use the interrupt-based PCIe PME signaling regardless of | ||
50 | * the platform notification status, although the kernel will attempt to notify | ||
51 | * the platform anyway. When unset, it will prevent the kernel from using the | ||
52 | * the interrupt-based PCIe PME signaling if the platform notification fails, | ||
53 | * which is the default. | ||
54 | */ | ||
55 | static bool pcie_pme_force_enable; | ||
56 | |||
57 | /* | ||
58 | * If this switch is set, MSI will not be used for PCIe PME signaling. This | ||
59 | * causes the PCIe port driver to use INTx interrupts only, but it turns out | ||
60 | * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based | ||
61 | * wake-up from system sleep states. | ||
62 | */ | ||
63 | bool pcie_pme_msi_disabled; | ||
64 | |||
65 | static int __init pcie_pme_setup(char *str) | ||
66 | { | ||
67 | if (!strcmp(str, "off")) | ||
68 | pcie_pme_disabled = true; | ||
69 | else if (!strcmp(str, "force")) | ||
70 | pcie_pme_force_enable = true; | ||
71 | else if (!strcmp(str, "nomsi")) | ||
72 | pcie_pme_msi_disabled = true; | ||
73 | return 1; | ||
74 | } | ||
75 | __setup("pcie_pme=", pcie_pme_setup); | ||
76 | |||
77 | /** | ||
78 | * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME. | ||
79 | * @srv: PCIe PME root port service to use for carrying out the check. | ||
80 | * | ||
81 | * Notify the platform that the native PCIe PME is going to be used and return | ||
82 | * 'true' if the control of the PCIe PME registers has been acquired from the | ||
83 | * platform. | ||
84 | */ | ||
85 | static bool pcie_pme_platform_setup(struct pcie_device *srv) | ||
86 | { | ||
87 | if (!pcie_pme_platform_notify(srv)) | ||
88 | return true; | ||
89 | return pcie_pme_force_enable; | ||
90 | } | ||
91 | |||
92 | struct pcie_pme_service_data { | ||
93 | spinlock_t lock; | ||
94 | struct pcie_device *srv; | ||
95 | struct work_struct work; | ||
96 | bool noirq; /* Don't enable the PME interrupt used by this service. */ | ||
97 | }; | ||
98 | |||
99 | /** | ||
100 | * pcie_pme_interrupt_enable - Enable/disable PCIe PME interrupt generation. | ||
101 | * @dev: PCIe root port or event collector. | ||
102 | * @enable: Enable or disable the interrupt. | ||
103 | */ | ||
104 | static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) | ||
105 | { | ||
106 | int rtctl_pos; | ||
107 | u16 rtctl; | ||
108 | |||
109 | rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL; | ||
110 | |||
111 | pci_read_config_word(dev, rtctl_pos, &rtctl); | ||
112 | if (enable) | ||
113 | rtctl |= PCI_EXP_RTCTL_PMEIE; | ||
114 | else | ||
115 | rtctl &= ~PCI_EXP_RTCTL_PMEIE; | ||
116 | pci_write_config_word(dev, rtctl_pos, rtctl); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * pcie_pme_clear_status - Clear root port PME interrupt status. | ||
121 | * @dev: PCIe root port or event collector. | ||
122 | */ | ||
123 | static void pcie_pme_clear_status(struct pci_dev *dev) | ||
124 | { | ||
125 | int rtsta_pos; | ||
126 | u32 rtsta; | ||
127 | |||
128 | rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; | ||
129 | |||
130 | pci_read_config_dword(dev, rtsta_pos, &rtsta); | ||
131 | rtsta |= PCI_EXP_RTSTA_PME; | ||
132 | pci_write_config_dword(dev, rtsta_pos, rtsta); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. | ||
137 | * @bus: PCI bus to scan. | ||
138 | * | ||
139 | * Scan given PCI bus and all buses under it for devices asserting PME#. | ||
140 | */ | ||
141 | static bool pcie_pme_walk_bus(struct pci_bus *bus) | ||
142 | { | ||
143 | struct pci_dev *dev; | ||
144 | bool ret = false; | ||
145 | |||
146 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
147 | /* Skip PCIe devices in case we started from a root port. */ | ||
148 | if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { | ||
149 | pm_request_resume(&dev->dev); | ||
150 | ret = true; | ||
151 | } | ||
152 | |||
153 | if (dev->subordinate && pcie_pme_walk_bus(dev->subordinate)) | ||
154 | ret = true; | ||
155 | } | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * pcie_pme_from_pci_bridge - Check if PCIe-PCI bridge generated a PME. | ||
162 | * @bus: Secondary bus of the bridge. | ||
163 | * @devfn: Device/function number to check. | ||
164 | * | ||
165 | * PME from PCI devices under a PCIe-PCI bridge may be converted to an in-band | ||
166 | * PCIe PME message. In such that case the bridge should use the Requester ID | ||
167 | * of device/function number 0 on its secondary bus. | ||
168 | */ | ||
169 | static bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn) | ||
170 | { | ||
171 | struct pci_dev *dev; | ||
172 | bool found = false; | ||
173 | |||
174 | if (devfn) | ||
175 | return false; | ||
176 | |||
177 | dev = pci_dev_get(bus->self); | ||
178 | if (!dev) | ||
179 | return false; | ||
180 | |||
181 | if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { | ||
182 | down_read(&pci_bus_sem); | ||
183 | if (pcie_pme_walk_bus(bus)) | ||
184 | found = true; | ||
185 | up_read(&pci_bus_sem); | ||
186 | } | ||
187 | |||
188 | pci_dev_put(dev); | ||
189 | return found; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * pcie_pme_handle_request - Find device that generated PME and handle it. | ||
194 | * @port: Root port or event collector that generated the PME interrupt. | ||
195 | * @req_id: PCIe Requester ID of the device that generated the PME. | ||
196 | */ | ||
197 | static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) | ||
198 | { | ||
199 | u8 busnr = req_id >> 8, devfn = req_id & 0xff; | ||
200 | struct pci_bus *bus; | ||
201 | struct pci_dev *dev; | ||
202 | bool found = false; | ||
203 | |||
204 | /* First, check if the PME is from the root port itself. */ | ||
205 | if (port->devfn == devfn && port->bus->number == busnr) { | ||
206 | if (pci_check_pme_status(port)) { | ||
207 | pm_request_resume(&port->dev); | ||
208 | found = true; | ||
209 | } else { | ||
210 | /* | ||
211 | * Apparently, the root port generated the PME on behalf | ||
212 | * of a non-PCIe device downstream. If this is done by | ||
213 | * a root port, the Requester ID field in its status | ||
214 | * register may contain either the root port's, or the | ||
215 | * source device's information (PCI Express Base | ||
216 | * Specification, Rev. 2.0, Section 6.1.9). | ||
217 | */ | ||
218 | down_read(&pci_bus_sem); | ||
219 | found = pcie_pme_walk_bus(port->subordinate); | ||
220 | up_read(&pci_bus_sem); | ||
221 | } | ||
222 | goto out; | ||
223 | } | ||
224 | |||
225 | /* Second, find the bus the source device is on. */ | ||
226 | bus = pci_find_bus(pci_domain_nr(port->bus), busnr); | ||
227 | if (!bus) | ||
228 | goto out; | ||
229 | |||
230 | /* Next, check if the PME is from a PCIe-PCI bridge. */ | ||
231 | found = pcie_pme_from_pci_bridge(bus, devfn); | ||
232 | if (found) | ||
233 | goto out; | ||
234 | |||
235 | /* Finally, try to find the PME source on the bus. */ | ||
236 | down_read(&pci_bus_sem); | ||
237 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
238 | pci_dev_get(dev); | ||
239 | if (dev->devfn == devfn) { | ||
240 | found = true; | ||
241 | break; | ||
242 | } | ||
243 | pci_dev_put(dev); | ||
244 | } | ||
245 | up_read(&pci_bus_sem); | ||
246 | |||
247 | if (found) { | ||
248 | /* The device is there, but we have to check its PME status. */ | ||
249 | found = pci_check_pme_status(dev); | ||
250 | if (found) | ||
251 | pm_request_resume(&dev->dev); | ||
252 | pci_dev_put(dev); | ||
253 | } else if (devfn) { | ||
254 | /* | ||
255 | * The device is not there, but we can still try to recover by | ||
256 | * assuming that the PME was reported by a PCIe-PCI bridge that | ||
257 | * used devfn different from zero. | ||
258 | */ | ||
259 | dev_dbg(&port->dev, "PME interrupt generated for " | ||
260 | "non-existent device %02x:%02x.%d\n", | ||
261 | busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); | ||
262 | found = pcie_pme_from_pci_bridge(bus, 0); | ||
263 | } | ||
264 | |||
265 | out: | ||
266 | if (!found) | ||
267 | dev_dbg(&port->dev, "Spurious native PME interrupt!\n"); | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * pcie_pme_work_fn - Work handler for PCIe PME interrupt. | ||
272 | * @work: Work structure giving access to service data. | ||
273 | */ | ||
274 | static void pcie_pme_work_fn(struct work_struct *work) | ||
275 | { | ||
276 | struct pcie_pme_service_data *data = | ||
277 | container_of(work, struct pcie_pme_service_data, work); | ||
278 | struct pci_dev *port = data->srv->port; | ||
279 | int rtsta_pos; | ||
280 | u32 rtsta; | ||
281 | |||
282 | rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; | ||
283 | |||
284 | spin_lock_irq(&data->lock); | ||
285 | |||
286 | for (;;) { | ||
287 | if (data->noirq) | ||
288 | break; | ||
289 | |||
290 | pci_read_config_dword(port, rtsta_pos, &rtsta); | ||
291 | if (rtsta & PCI_EXP_RTSTA_PME) { | ||
292 | /* | ||
293 | * Clear PME status of the port. If there are other | ||
294 | * pending PMEs, the status will be set again. | ||
295 | */ | ||
296 | pcie_pme_clear_status(port); | ||
297 | |||
298 | spin_unlock_irq(&data->lock); | ||
299 | pcie_pme_handle_request(port, rtsta & 0xffff); | ||
300 | spin_lock_irq(&data->lock); | ||
301 | |||
302 | continue; | ||
303 | } | ||
304 | |||
305 | /* No need to loop if there are no more PMEs pending. */ | ||
306 | if (!(rtsta & PCI_EXP_RTSTA_PENDING)) | ||
307 | break; | ||
308 | |||
309 | spin_unlock_irq(&data->lock); | ||
310 | cpu_relax(); | ||
311 | spin_lock_irq(&data->lock); | ||
312 | } | ||
313 | |||
314 | if (!data->noirq) | ||
315 | pcie_pme_interrupt_enable(port, true); | ||
316 | |||
317 | spin_unlock_irq(&data->lock); | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * pcie_pme_irq - Interrupt handler for PCIe root port PME interrupt. | ||
322 | * @irq: Interrupt vector. | ||
323 | * @context: Interrupt context pointer. | ||
324 | */ | ||
325 | static irqreturn_t pcie_pme_irq(int irq, void *context) | ||
326 | { | ||
327 | struct pci_dev *port; | ||
328 | struct pcie_pme_service_data *data; | ||
329 | int rtsta_pos; | ||
330 | u32 rtsta; | ||
331 | unsigned long flags; | ||
332 | |||
333 | port = ((struct pcie_device *)context)->port; | ||
334 | data = get_service_data((struct pcie_device *)context); | ||
335 | |||
336 | rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; | ||
337 | |||
338 | spin_lock_irqsave(&data->lock, flags); | ||
339 | pci_read_config_dword(port, rtsta_pos, &rtsta); | ||
340 | |||
341 | if (!(rtsta & PCI_EXP_RTSTA_PME)) { | ||
342 | spin_unlock_irqrestore(&data->lock, flags); | ||
343 | return IRQ_NONE; | ||
344 | } | ||
345 | |||
346 | pcie_pme_interrupt_enable(port, false); | ||
347 | spin_unlock_irqrestore(&data->lock, flags); | ||
348 | |||
349 | /* We don't use pm_wq, because it's freezable. */ | ||
350 | schedule_work(&data->work); | ||
351 | |||
352 | return IRQ_HANDLED; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * pcie_pme_set_native - Set the PME interrupt flag for given device. | ||
357 | * @dev: PCI device to handle. | ||
358 | * @ign: Ignored. | ||
359 | */ | ||
360 | static int pcie_pme_set_native(struct pci_dev *dev, void *ign) | ||
361 | { | ||
362 | dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n"); | ||
363 | |||
364 | device_set_run_wake(&dev->dev, true); | ||
365 | dev->pme_interrupt = true; | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port. | ||
371 | * @port: PCIe root port or event collector to handle. | ||
372 | * | ||
373 | * For each device below given root port, including the port itself (or for each | ||
374 | * root complex integrated endpoint if @port is a root complex event collector) | ||
375 | * set the flag indicating that it can signal run-time wake-up events via PCIe | ||
376 | * PME interrupts. | ||
377 | */ | ||
378 | static void pcie_pme_mark_devices(struct pci_dev *port) | ||
379 | { | ||
380 | pcie_pme_set_native(port, NULL); | ||
381 | if (port->subordinate) { | ||
382 | pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL); | ||
383 | } else { | ||
384 | struct pci_bus *bus = port->bus; | ||
385 | struct pci_dev *dev; | ||
386 | |||
387 | /* Check if this is a root port event collector. */ | ||
388 | if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus) | ||
389 | return; | ||
390 | |||
391 | down_read(&pci_bus_sem); | ||
392 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
393 | if (pci_is_pcie(dev) | ||
394 | && dev->pcie_type == PCI_EXP_TYPE_RC_END) | ||
395 | pcie_pme_set_native(dev, NULL); | ||
396 | up_read(&pci_bus_sem); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * pcie_pme_probe - Initialize PCIe PME service for given root port. | ||
402 | * @srv: PCIe service to initialize. | ||
403 | */ | ||
404 | static int pcie_pme_probe(struct pcie_device *srv) | ||
405 | { | ||
406 | struct pci_dev *port; | ||
407 | struct pcie_pme_service_data *data; | ||
408 | int ret; | ||
409 | |||
410 | if (!pcie_pme_platform_setup(srv)) | ||
411 | return -EACCES; | ||
412 | |||
413 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
414 | if (!data) | ||
415 | return -ENOMEM; | ||
416 | |||
417 | spin_lock_init(&data->lock); | ||
418 | INIT_WORK(&data->work, pcie_pme_work_fn); | ||
419 | data->srv = srv; | ||
420 | set_service_data(srv, data); | ||
421 | |||
422 | port = srv->port; | ||
423 | pcie_pme_interrupt_enable(port, false); | ||
424 | pcie_pme_clear_status(port); | ||
425 | |||
426 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); | ||
427 | if (ret) { | ||
428 | kfree(data); | ||
429 | } else { | ||
430 | pcie_pme_mark_devices(port); | ||
431 | pcie_pme_interrupt_enable(port, true); | ||
432 | } | ||
433 | |||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | /** | ||
438 | * pcie_pme_suspend - Suspend PCIe PME service device. | ||
439 | * @srv: PCIe service device to suspend. | ||
440 | */ | ||
441 | static int pcie_pme_suspend(struct pcie_device *srv) | ||
442 | { | ||
443 | struct pcie_pme_service_data *data = get_service_data(srv); | ||
444 | struct pci_dev *port = srv->port; | ||
445 | |||
446 | spin_lock_irq(&data->lock); | ||
447 | pcie_pme_interrupt_enable(port, false); | ||
448 | pcie_pme_clear_status(port); | ||
449 | data->noirq = true; | ||
450 | spin_unlock_irq(&data->lock); | ||
451 | |||
452 | synchronize_irq(srv->irq); | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * pcie_pme_resume - Resume PCIe PME service device. | ||
459 | * @srv - PCIe service device to resume. | ||
460 | */ | ||
461 | static int pcie_pme_resume(struct pcie_device *srv) | ||
462 | { | ||
463 | struct pcie_pme_service_data *data = get_service_data(srv); | ||
464 | struct pci_dev *port = srv->port; | ||
465 | |||
466 | spin_lock_irq(&data->lock); | ||
467 | data->noirq = false; | ||
468 | pcie_pme_clear_status(port); | ||
469 | pcie_pme_interrupt_enable(port, true); | ||
470 | spin_unlock_irq(&data->lock); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * pcie_pme_remove - Prepare PCIe PME service device for removal. | ||
477 | * @srv - PCIe service device to resume. | ||
478 | */ | ||
479 | static void pcie_pme_remove(struct pcie_device *srv) | ||
480 | { | ||
481 | pcie_pme_suspend(srv); | ||
482 | free_irq(srv->irq, srv); | ||
483 | kfree(get_service_data(srv)); | ||
484 | } | ||
485 | |||
486 | static struct pcie_port_service_driver pcie_pme_driver = { | ||
487 | .name = "pcie_pme", | ||
488 | .port_type = PCI_EXP_TYPE_ROOT_PORT, | ||
489 | .service = PCIE_PORT_SERVICE_PME, | ||
490 | |||
491 | .probe = pcie_pme_probe, | ||
492 | .suspend = pcie_pme_suspend, | ||
493 | .resume = pcie_pme_resume, | ||
494 | .remove = pcie_pme_remove, | ||
495 | }; | ||
496 | |||
497 | /** | ||
498 | * pcie_pme_service_init - Register the PCIe PME service driver. | ||
499 | */ | ||
500 | static int __init pcie_pme_service_init(void) | ||
501 | { | ||
502 | return pcie_pme_disabled ? | ||
503 | -ENODEV : pcie_port_service_register(&pcie_pme_driver); | ||
504 | } | ||
505 | |||
506 | module_init(pcie_pme_service_init); | ||
diff --git a/drivers/pci/pcie/pme/pcie_pme.h b/drivers/pci/pcie/pme/pcie_pme.h new file mode 100644 index 000000000000..b30d2b7c9775 --- /dev/null +++ b/drivers/pci/pcie/pme/pcie_pme.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * drivers/pci/pcie/pme/pcie_pme.h | ||
3 | * | ||
4 | * PCI Express Root Port PME signaling support | ||
5 | * | ||
6 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
7 | */ | ||
8 | |||
9 | #ifndef _PCIE_PME_H_ | ||
10 | #define _PCIE_PME_H_ | ||
11 | |||
12 | struct pcie_device; | ||
13 | |||
14 | #ifdef CONFIG_ACPI | ||
15 | extern int pcie_pme_acpi_setup(struct pcie_device *srv); | ||
16 | |||
17 | static inline int pcie_pme_platform_notify(struct pcie_device *srv) | ||
18 | { | ||
19 | return pcie_pme_acpi_setup(srv); | ||
20 | } | ||
21 | #else /* !CONFIG_ACPI */ | ||
22 | static inline int pcie_pme_platform_notify(struct pcie_device *srv) | ||
23 | { | ||
24 | return 0; | ||
25 | } | ||
26 | #endif /* !CONFIG_ACPI */ | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c new file mode 100644 index 000000000000..83ab2287ae3f --- /dev/null +++ b/drivers/pci/pcie/pme/pcie_pme_acpi.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * PCIe Native PME support, ACPI-related part | ||
3 | * | ||
4 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License V2. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/pci.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/acpi.h> | ||
15 | #include <linux/pci-acpi.h> | ||
16 | #include <linux/pcieport_if.h> | ||
17 | |||
18 | /** | ||
19 | * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME. | ||
20 | * @srv - PCIe PME service for a root port or event collector. | ||
21 | * | ||
22 | * Invoked when the PCIe bus type loads PCIe PME service driver. To avoid | ||
23 | * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME | ||
24 | * control to the kernel. | ||
25 | */ | ||
26 | int pcie_pme_acpi_setup(struct pcie_device *srv) | ||
27 | { | ||
28 | acpi_status status = AE_NOT_FOUND; | ||
29 | struct pci_dev *port = srv->port; | ||
30 | acpi_handle handle; | ||
31 | int error = 0; | ||
32 | |||
33 | if (acpi_pci_disabled) | ||
34 | return -ENOSYS; | ||
35 | |||
36 | dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n"); | ||
37 | |||
38 | handle = acpi_find_root_bridge_handle(port); | ||
39 | if (!handle) | ||
40 | return -EINVAL; | ||
41 | |||
42 | status = acpi_pci_osc_control_set(handle, | ||
43 | OSC_PCI_EXPRESS_PME_CONTROL | | ||
44 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
45 | if (ACPI_FAILURE(status)) { | ||
46 | dev_info(&port->dev, | ||
47 | "Failed to receive control of PCIe PME service: %s\n", | ||
48 | (status == AE_SUPPORT || status == AE_NOT_FOUND) ? | ||
49 | "no _OSC support" : "ACPI _OSC failed"); | ||
50 | error = -ENODEV; | ||
51 | } | ||
52 | |||
53 | return error; | ||
54 | } | ||
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 17ad53868f9f..813a5c3427b6 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -11,31 +11,16 @@ | |||
11 | 11 | ||
12 | #include <linux/compiler.h> | 12 | #include <linux/compiler.h> |
13 | 13 | ||
14 | #if !defined(PCI_CAP_ID_PME) | 14 | #define PCIE_PORT_DEVICE_MAXSERVICES 4 |
15 | #define PCI_CAP_ID_PME 1 | ||
16 | #endif | ||
17 | |||
18 | #if !defined(PCI_CAP_ID_EXP) | ||
19 | #define PCI_CAP_ID_EXP 0x10 | ||
20 | #endif | ||
21 | |||
22 | #define PORT_TYPE_MASK 0xf | ||
23 | #define PORT_TO_SLOT_MASK 0x100 | ||
24 | #define SLOT_HP_CAPABLE_MASK 0x40 | ||
25 | #define PCIE_CAPABILITIES_REG 0x2 | ||
26 | #define PCIE_SLOT_CAPABILITIES_REG 0x14 | ||
27 | #define PCIE_PORT_DEVICE_MAXSERVICES 4 | ||
28 | #define PCIE_PORT_MSI_VECTOR_MASK 0x1f | ||
29 | /* | 15 | /* |
30 | * According to the PCI Express Base Specification 2.0, the indices of the MSI-X | 16 | * According to the PCI Express Base Specification 2.0, the indices of |
31 | * table entires used by port services must not exceed 31 | 17 | * the MSI-X table entires used by port services must not exceed 31 |
32 | */ | 18 | */ |
33 | #define PCIE_PORT_MAX_MSIX_ENTRIES 32 | 19 | #define PCIE_PORT_MAX_MSIX_ENTRIES 32 |
34 | 20 | ||
35 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | 21 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) |
36 | 22 | ||
37 | extern struct bus_type pcie_port_bus_type; | 23 | extern struct bus_type pcie_port_bus_type; |
38 | extern int pcie_port_device_probe(struct pci_dev *dev); | ||
39 | extern int pcie_port_device_register(struct pci_dev *dev); | 24 | extern int pcie_port_device_register(struct pci_dev *dev); |
40 | #ifdef CONFIG_PM | 25 | #ifdef CONFIG_PM |
41 | extern int pcie_port_device_suspend(struct device *dev); | 26 | extern int pcie_port_device_suspend(struct device *dev); |
@@ -45,4 +30,21 @@ extern void pcie_port_device_remove(struct pci_dev *dev); | |||
45 | extern int __must_check pcie_port_bus_register(void); | 30 | extern int __must_check pcie_port_bus_register(void); |
46 | extern void pcie_port_bus_unregister(void); | 31 | extern void pcie_port_bus_unregister(void); |
47 | 32 | ||
33 | #ifdef CONFIG_PCIE_PME | ||
34 | extern bool pcie_pme_msi_disabled; | ||
35 | |||
36 | static inline void pcie_pme_disable_msi(void) | ||
37 | { | ||
38 | pcie_pme_msi_disabled = true; | ||
39 | } | ||
40 | |||
41 | static inline bool pcie_pme_no_msi(void) | ||
42 | { | ||
43 | return pcie_pme_msi_disabled; | ||
44 | } | ||
45 | #else /* !CONFIG_PCIE_PME */ | ||
46 | static inline void pcie_pme_disable_msi(void) {} | ||
47 | static inline bool pcie_pme_no_msi(void) { return false; } | ||
48 | #endif /* !CONFIG_PCIE_PME */ | ||
49 | |||
48 | #endif /* _PORTDRV_H_ */ | 50 | #endif /* _PORTDRV_H_ */ |
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c index ef3a4eeaebb4..18bf90f748f6 100644 --- a/drivers/pci/pcie/portdrv_bus.c +++ b/drivers/pci/pcie/portdrv_bus.c | |||
@@ -26,7 +26,6 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type); | |||
26 | static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) | 26 | static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) |
27 | { | 27 | { |
28 | struct pcie_device *pciedev; | 28 | struct pcie_device *pciedev; |
29 | struct pcie_port_data *port_data; | ||
30 | struct pcie_port_service_driver *driver; | 29 | struct pcie_port_service_driver *driver; |
31 | 30 | ||
32 | if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) | 31 | if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) |
@@ -38,10 +37,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) | |||
38 | if (driver->service != pciedev->service) | 37 | if (driver->service != pciedev->service) |
39 | return 0; | 38 | return 0; |
40 | 39 | ||
41 | port_data = pci_get_drvdata(pciedev->port); | 40 | if ((driver->port_type != PCIE_ANY_PORT) && |
42 | 41 | (driver->port_type != pciedev->port->pcie_type)) | |
43 | if (driver->port_type != PCIE_ANY_PORT | ||
44 | && driver->port_type != port_data->port_type) | ||
45 | return 0; | 42 | return 0; |
46 | 43 | ||
47 | return 1; | 44 | return 1; |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 52f84fca9f7d..e73effbe402c 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -27,7 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | static void release_pcie_device(struct device *dev) | 28 | static void release_pcie_device(struct device *dev) |
29 | { | 29 | { |
30 | kfree(to_pcie_device(dev)); | 30 | kfree(to_pcie_device(dev)); |
31 | } | 31 | } |
32 | 32 | ||
33 | /** | 33 | /** |
@@ -108,9 +108,9 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) | |||
108 | * the value in this field indicates which MSI-X Table entry is | 108 | * the value in this field indicates which MSI-X Table entry is |
109 | * used to generate the interrupt message." | 109 | * used to generate the interrupt message." |
110 | */ | 110 | */ |
111 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 111 | pos = pci_pcie_cap(dev); |
112 | pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); | 112 | pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); |
113 | entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK; | 113 | entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9; |
114 | if (entry >= nr_entries) | 114 | if (entry >= nr_entries) |
115 | goto Error; | 115 | goto Error; |
116 | 116 | ||
@@ -177,37 +177,48 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) | |||
177 | } | 177 | } |
178 | 178 | ||
179 | /** | 179 | /** |
180 | * assign_interrupt_mode - choose interrupt mode for PCI Express port services | 180 | * init_service_irqs - initialize irqs for PCI Express port services |
181 | * (INTx, MSI-X, MSI) and set up vectors | ||
182 | * @dev: PCI Express port to handle | 181 | * @dev: PCI Express port to handle |
183 | * @vectors: Array of interrupt vectors to populate | 182 | * @irqs: Array of irqs to populate |
184 | * @mask: Bitmask of port capabilities returned by get_port_device_capability() | 183 | * @mask: Bitmask of port capabilities returned by get_port_device_capability() |
185 | * | 184 | * |
186 | * Return value: Interrupt mode associated with the port | 185 | * Return value: Interrupt mode associated with the port |
187 | */ | 186 | */ |
188 | static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | 187 | static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) |
189 | { | 188 | { |
190 | int irq, interrupt_mode = PCIE_PORT_NO_IRQ; | 189 | int i, irq = -1; |
191 | int i; | 190 | |
191 | /* We have to use INTx if MSI cannot be used for PCIe PME. */ | ||
192 | if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) { | ||
193 | if (dev->pin) | ||
194 | irq = dev->irq; | ||
195 | goto no_msi; | ||
196 | } | ||
192 | 197 | ||
193 | /* Try to use MSI-X if supported */ | 198 | /* Try to use MSI-X if supported */ |
194 | if (!pcie_port_enable_msix(dev, vectors, mask)) | 199 | if (!pcie_port_enable_msix(dev, irqs, mask)) |
195 | return PCIE_PORT_MSIX_MODE; | 200 | return 0; |
196 | 201 | ||
197 | /* We're not going to use MSI-X, so try MSI and fall back to INTx */ | 202 | /* We're not going to use MSI-X, so try MSI and fall back to INTx */ |
198 | if (!pci_enable_msi(dev)) | 203 | if (!pci_enable_msi(dev) || dev->pin) |
199 | interrupt_mode = PCIE_PORT_MSI_MODE; | 204 | irq = dev->irq; |
200 | |||
201 | if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin) | ||
202 | interrupt_mode = PCIE_PORT_INTx_MODE; | ||
203 | 205 | ||
204 | irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1; | 206 | no_msi: |
205 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) | 207 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) |
206 | vectors[i] = irq; | 208 | irqs[i] = irq; |
209 | irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1; | ||
207 | 210 | ||
208 | vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1; | 211 | if (irq < 0) |
212 | return -ENODEV; | ||
213 | return 0; | ||
214 | } | ||
209 | 215 | ||
210 | return interrupt_mode; | 216 | static void cleanup_service_irqs(struct pci_dev *dev) |
217 | { | ||
218 | if (dev->msix_enabled) | ||
219 | pci_disable_msix(dev); | ||
220 | else if (dev->msi_enabled) | ||
221 | pci_disable_msi(dev); | ||
211 | } | 222 | } |
212 | 223 | ||
213 | /** | 224 | /** |
@@ -226,13 +237,12 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
226 | u16 reg16; | 237 | u16 reg16; |
227 | u32 reg32; | 238 | u32 reg32; |
228 | 239 | ||
229 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 240 | pos = pci_pcie_cap(dev); |
230 | pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); | 241 | pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); |
231 | /* Hot-Plug Capable */ | 242 | /* Hot-Plug Capable */ |
232 | if (reg16 & PORT_TO_SLOT_MASK) { | 243 | if (reg16 & PCI_EXP_FLAGS_SLOT) { |
233 | pci_read_config_dword(dev, | 244 | pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); |
234 | pos + PCIE_SLOT_CAPABILITIES_REG, ®32); | 245 | if (reg32 & PCI_EXP_SLTCAP_HPC) |
235 | if (reg32 & SLOT_HP_CAPABLE_MASK) | ||
236 | services |= PCIE_PORT_SERVICE_HP; | 246 | services |= PCIE_PORT_SERVICE_HP; |
237 | } | 247 | } |
238 | /* AER capable */ | 248 | /* AER capable */ |
@@ -241,80 +251,48 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
241 | /* VC support */ | 251 | /* VC support */ |
242 | if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) | 252 | if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) |
243 | services |= PCIE_PORT_SERVICE_VC; | 253 | services |= PCIE_PORT_SERVICE_VC; |
254 | /* Root ports are capable of generating PME too */ | ||
255 | if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | ||
256 | services |= PCIE_PORT_SERVICE_PME; | ||
244 | 257 | ||
245 | return services; | 258 | return services; |
246 | } | 259 | } |
247 | 260 | ||
248 | /** | 261 | /** |
249 | * pcie_device_init - initialize PCI Express port service device | 262 | * pcie_device_init - allocate and initialize PCI Express port service device |
250 | * @dev: Port service device to initialize | 263 | * @pdev: PCI Express port to associate the service device with |
251 | * @parent: PCI Express port to associate the service device with | 264 | * @service: Type of service to associate with the service device |
252 | * @port_type: Type of the port | ||
253 | * @service_type: Type of service to associate with the service device | ||
254 | * @irq: Interrupt vector to associate with the service device | 265 | * @irq: Interrupt vector to associate with the service device |
255 | */ | 266 | */ |
256 | static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, | 267 | static int pcie_device_init(struct pci_dev *pdev, int service, int irq) |
257 | int service_type, int irq) | ||
258 | { | 268 | { |
259 | struct pcie_port_data *port_data = pci_get_drvdata(parent); | 269 | int retval; |
270 | struct pcie_device *pcie; | ||
260 | struct device *device; | 271 | struct device *device; |
261 | int port_type = port_data->port_type; | ||
262 | 272 | ||
263 | dev->port = parent; | 273 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); |
264 | dev->irq = irq; | 274 | if (!pcie) |
265 | dev->service = service_type; | 275 | return -ENOMEM; |
276 | pcie->port = pdev; | ||
277 | pcie->irq = irq; | ||
278 | pcie->service = service; | ||
266 | 279 | ||
267 | /* Initialize generic device interface */ | 280 | /* Initialize generic device interface */ |
268 | device = &dev->device; | 281 | device = &pcie->device; |
269 | memset(device, 0, sizeof(struct device)); | ||
270 | device->bus = &pcie_port_bus_type; | 282 | device->bus = &pcie_port_bus_type; |
271 | device->driver = NULL; | ||
272 | dev_set_drvdata(device, NULL); | ||
273 | device->release = release_pcie_device; /* callback to free pcie dev */ | 283 | device->release = release_pcie_device; /* callback to free pcie dev */ |
274 | dev_set_name(device, "%s:pcie%02x", | 284 | dev_set_name(device, "%s:pcie%02x", |
275 | pci_name(parent), get_descriptor_id(port_type, service_type)); | 285 | pci_name(pdev), |
276 | device->parent = &parent->dev; | 286 | get_descriptor_id(pdev->pcie_type, service)); |
277 | } | 287 | device->parent = &pdev->dev; |
278 | 288 | device_enable_async_suspend(device); | |
279 | /** | 289 | |
280 | * alloc_pcie_device - allocate PCI Express port service device structure | 290 | retval = device_register(device); |
281 | * @parent: PCI Express port to associate the service device with | 291 | if (retval) |
282 | * @port_type: Type of the port | 292 | kfree(pcie); |
283 | * @service_type: Type of service to associate with the service device | 293 | else |
284 | * @irq: Interrupt vector to associate with the service device | 294 | get_device(device); |
285 | */ | 295 | return retval; |
286 | static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, | ||
287 | int service_type, int irq) | ||
288 | { | ||
289 | struct pcie_device *device; | ||
290 | |||
291 | device = kzalloc(sizeof(struct pcie_device), GFP_KERNEL); | ||
292 | if (!device) | ||
293 | return NULL; | ||
294 | |||
295 | pcie_device_init(parent, device, service_type, irq); | ||
296 | return device; | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * pcie_port_device_probe - check if device is a PCI Express port | ||
301 | * @dev: Device to check | ||
302 | */ | ||
303 | int pcie_port_device_probe(struct pci_dev *dev) | ||
304 | { | ||
305 | int pos, type; | ||
306 | u16 reg; | ||
307 | |||
308 | if (!(pos = pci_find_capability(dev, PCI_CAP_ID_EXP))) | ||
309 | return -ENODEV; | ||
310 | |||
311 | pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); | ||
312 | type = (reg >> 4) & PORT_TYPE_MASK; | ||
313 | if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || | ||
314 | type == PCIE_SW_DOWNSTREAM_PORT ) | ||
315 | return 0; | ||
316 | |||
317 | return -ENODEV; | ||
318 | } | 296 | } |
319 | 297 | ||
320 | /** | 298 | /** |
@@ -326,77 +304,49 @@ int pcie_port_device_probe(struct pci_dev *dev) | |||
326 | */ | 304 | */ |
327 | int pcie_port_device_register(struct pci_dev *dev) | 305 | int pcie_port_device_register(struct pci_dev *dev) |
328 | { | 306 | { |
329 | struct pcie_port_data *port_data; | 307 | int status, capabilities, i, nr_service; |
330 | int status, capabilities, irq_mode, i, nr_serv; | 308 | int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; |
331 | int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; | ||
332 | u16 reg16; | ||
333 | |||
334 | port_data = kzalloc(sizeof(*port_data), GFP_KERNEL); | ||
335 | if (!port_data) | ||
336 | return -ENOMEM; | ||
337 | pci_set_drvdata(dev, port_data); | ||
338 | |||
339 | /* Get port type */ | ||
340 | pci_read_config_word(dev, | ||
341 | pci_find_capability(dev, PCI_CAP_ID_EXP) + | ||
342 | PCIE_CAPABILITIES_REG, ®16); | ||
343 | port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK; | ||
344 | 309 | ||
310 | /* Get and check PCI Express port services */ | ||
345 | capabilities = get_port_device_capability(dev); | 311 | capabilities = get_port_device_capability(dev); |
346 | /* Root ports are capable of generating PME too */ | 312 | if (!capabilities) |
347 | if (port_data->port_type == PCIE_RC_PORT) | 313 | return -ENODEV; |
348 | capabilities |= PCIE_PORT_SERVICE_PME; | ||
349 | |||
350 | irq_mode = assign_interrupt_mode(dev, vectors, capabilities); | ||
351 | if (irq_mode == PCIE_PORT_NO_IRQ) { | ||
352 | /* | ||
353 | * Don't use service devices that require interrupts if there is | ||
354 | * no way to generate them. | ||
355 | */ | ||
356 | if (!(capabilities & PCIE_PORT_SERVICE_VC)) { | ||
357 | status = -ENODEV; | ||
358 | goto Error; | ||
359 | } | ||
360 | capabilities = PCIE_PORT_SERVICE_VC; | ||
361 | } | ||
362 | port_data->port_irq_mode = irq_mode; | ||
363 | 314 | ||
315 | /* Enable PCI Express port device */ | ||
364 | status = pci_enable_device(dev); | 316 | status = pci_enable_device(dev); |
365 | if (status) | 317 | if (status) |
366 | goto Error; | 318 | return status; |
367 | pci_set_master(dev); | 319 | pci_set_master(dev); |
320 | /* | ||
321 | * Initialize service irqs. Don't use service devices that | ||
322 | * require interrupts if there is no way to generate them. | ||
323 | */ | ||
324 | status = init_service_irqs(dev, irqs, capabilities); | ||
325 | if (status) { | ||
326 | capabilities &= PCIE_PORT_SERVICE_VC; | ||
327 | if (!capabilities) | ||
328 | goto error_disable; | ||
329 | } | ||
368 | 330 | ||
369 | /* Allocate child services if any */ | 331 | /* Allocate child services if any */ |
370 | for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { | 332 | status = -ENODEV; |
371 | struct pcie_device *child; | 333 | nr_service = 0; |
334 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { | ||
372 | int service = 1 << i; | 335 | int service = 1 << i; |
373 | |||
374 | if (!(capabilities & service)) | 336 | if (!(capabilities & service)) |
375 | continue; | 337 | continue; |
376 | 338 | if (!pcie_device_init(dev, service, irqs[i])) | |
377 | child = alloc_pcie_device(dev, service, vectors[i]); | 339 | nr_service++; |
378 | if (!child) | ||
379 | continue; | ||
380 | |||
381 | status = device_register(&child->device); | ||
382 | if (status) { | ||
383 | kfree(child); | ||
384 | continue; | ||
385 | } | ||
386 | |||
387 | get_device(&child->device); | ||
388 | nr_serv++; | ||
389 | } | ||
390 | if (!nr_serv) { | ||
391 | pci_disable_device(dev); | ||
392 | status = -ENODEV; | ||
393 | goto Error; | ||
394 | } | 340 | } |
341 | if (!nr_service) | ||
342 | goto error_cleanup_irqs; | ||
395 | 343 | ||
396 | return 0; | 344 | return 0; |
397 | 345 | ||
398 | Error: | 346 | error_cleanup_irqs: |
399 | kfree(port_data); | 347 | cleanup_service_irqs(dev); |
348 | error_disable: | ||
349 | pci_disable_device(dev); | ||
400 | return status; | 350 | return status; |
401 | } | 351 | } |
402 | 352 | ||
@@ -405,12 +355,11 @@ static int suspend_iter(struct device *dev, void *data) | |||
405 | { | 355 | { |
406 | struct pcie_port_service_driver *service_driver; | 356 | struct pcie_port_service_driver *service_driver; |
407 | 357 | ||
408 | if ((dev->bus == &pcie_port_bus_type) && | 358 | if ((dev->bus == &pcie_port_bus_type) && dev->driver) { |
409 | (dev->driver)) { | 359 | service_driver = to_service_driver(dev->driver); |
410 | service_driver = to_service_driver(dev->driver); | 360 | if (service_driver->suspend) |
411 | if (service_driver->suspend) | 361 | service_driver->suspend(to_pcie_device(dev)); |
412 | service_driver->suspend(to_pcie_device(dev)); | 362 | } |
413 | } | ||
414 | return 0; | 363 | return 0; |
415 | } | 364 | } |
416 | 365 | ||
@@ -464,21 +413,9 @@ static int remove_iter(struct device *dev, void *data) | |||
464 | */ | 413 | */ |
465 | void pcie_port_device_remove(struct pci_dev *dev) | 414 | void pcie_port_device_remove(struct pci_dev *dev) |
466 | { | 415 | { |
467 | struct pcie_port_data *port_data = pci_get_drvdata(dev); | ||
468 | |||
469 | device_for_each_child(&dev->dev, NULL, remove_iter); | 416 | device_for_each_child(&dev->dev, NULL, remove_iter); |
417 | cleanup_service_irqs(dev); | ||
470 | pci_disable_device(dev); | 418 | pci_disable_device(dev); |
471 | |||
472 | switch (port_data->port_irq_mode) { | ||
473 | case PCIE_PORT_MSIX_MODE: | ||
474 | pci_disable_msix(dev); | ||
475 | break; | ||
476 | case PCIE_PORT_MSI_MODE: | ||
477 | pci_disable_msi(dev); | ||
478 | break; | ||
479 | } | ||
480 | |||
481 | kfree(port_data); | ||
482 | } | 419 | } |
483 | 420 | ||
484 | /** | 421 | /** |
@@ -565,6 +502,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) | |||
565 | 502 | ||
566 | return driver_register(&new->driver); | 503 | return driver_register(&new->driver); |
567 | } | 504 | } |
505 | EXPORT_SYMBOL(pcie_port_service_register); | ||
568 | 506 | ||
569 | /** | 507 | /** |
570 | * pcie_port_service_unregister - unregister PCI Express port service driver | 508 | * pcie_port_service_unregister - unregister PCI Express port service driver |
@@ -574,6 +512,4 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *drv) | |||
574 | { | 512 | { |
575 | driver_unregister(&drv->driver); | 513 | driver_unregister(&drv->driver); |
576 | } | 514 | } |
577 | |||
578 | EXPORT_SYMBOL(pcie_port_service_register); | ||
579 | EXPORT_SYMBOL(pcie_port_service_unregister); | 515 | EXPORT_SYMBOL(pcie_port_service_unregister); |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f635e476d632..3debed25e46b 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -12,9 +12,9 @@ | |||
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/pm.h> | 13 | #include <linux/pm.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | ||
16 | #include <linux/pcieport_if.h> | 15 | #include <linux/pcieport_if.h> |
17 | #include <linux/aer.h> | 16 | #include <linux/aer.h> |
17 | #include <linux/dmi.h> | ||
18 | 18 | ||
19 | #include "portdrv.h" | 19 | #include "portdrv.h" |
20 | #include "aer/aerdrv.h" | 20 | #include "aer/aerdrv.h" |
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | #define DRIVER_VERSION "v1.0" | 25 | #define DRIVER_VERSION "v1.0" |
26 | #define DRIVER_AUTHOR "tom.l.nguyen@intel.com" | 26 | #define DRIVER_AUTHOR "tom.l.nguyen@intel.com" |
27 | #define DRIVER_DESC "PCIE Port Bus Driver" | 27 | #define DRIVER_DESC "PCIe Port Bus Driver" |
28 | MODULE_AUTHOR(DRIVER_AUTHOR); | 28 | MODULE_AUTHOR(DRIVER_AUTHOR); |
29 | MODULE_DESCRIPTION(DRIVER_DESC); | 29 | MODULE_DESCRIPTION(DRIVER_DESC); |
30 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
@@ -43,7 +43,7 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) | |||
43 | } | 43 | } |
44 | 44 | ||
45 | #ifdef CONFIG_PM | 45 | #ifdef CONFIG_PM |
46 | static struct dev_pm_ops pcie_portdrv_pm_ops = { | 46 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { |
47 | .suspend = pcie_port_device_suspend, | 47 | .suspend = pcie_port_device_suspend, |
48 | .resume = pcie_port_device_resume, | 48 | .resume = pcie_port_device_resume, |
49 | .freeze = pcie_port_device_suspend, | 49 | .freeze = pcie_port_device_suspend, |
@@ -63,20 +63,22 @@ static struct dev_pm_ops pcie_portdrv_pm_ops = { | |||
63 | * pcie_portdrv_probe - Probe PCI-Express port devices | 63 | * pcie_portdrv_probe - Probe PCI-Express port devices |
64 | * @dev: PCI-Express port device being probed | 64 | * @dev: PCI-Express port device being probed |
65 | * | 65 | * |
66 | * If detected invokes the pcie_port_device_register() method for | 66 | * If detected invokes the pcie_port_device_register() method for |
67 | * this port device. | 67 | * this port device. |
68 | * | 68 | * |
69 | */ | 69 | */ |
70 | static int __devinit pcie_portdrv_probe (struct pci_dev *dev, | 70 | static int __devinit pcie_portdrv_probe(struct pci_dev *dev, |
71 | const struct pci_device_id *id ) | 71 | const struct pci_device_id *id) |
72 | { | 72 | { |
73 | int status; | 73 | int status; |
74 | 74 | ||
75 | status = pcie_port_device_probe(dev); | 75 | if (!pci_is_pcie(dev) || |
76 | if (status) | 76 | ((dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
77 | return status; | 77 | (dev->pcie_type != PCI_EXP_TYPE_UPSTREAM) && |
78 | (dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))) | ||
79 | return -ENODEV; | ||
78 | 80 | ||
79 | if (!dev->irq && dev->pin) { | 81 | if (!dev->irq && dev->pin) { |
80 | dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " | 82 | dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " |
81 | "check vendor BIOS\n", dev->vendor, dev->device); | 83 | "check vendor BIOS\n", dev->vendor, dev->device); |
82 | } | 84 | } |
@@ -89,7 +91,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, | |||
89 | return 0; | 91 | return 0; |
90 | } | 92 | } |
91 | 93 | ||
92 | static void pcie_portdrv_remove (struct pci_dev *dev) | 94 | static void pcie_portdrv_remove(struct pci_dev *dev) |
93 | { | 95 | { |
94 | pcie_port_device_remove(dev); | 96 | pcie_port_device_remove(dev); |
95 | pci_disable_device(dev); | 97 | pci_disable_device(dev); |
@@ -127,14 +129,13 @@ static int error_detected_iter(struct device *device, void *data) | |||
127 | static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, | 129 | static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, |
128 | enum pci_channel_state error) | 130 | enum pci_channel_state error) |
129 | { | 131 | { |
130 | struct aer_broadcast_data result_data = | 132 | struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER}; |
131 | {error, PCI_ERS_RESULT_CAN_RECOVER}; | 133 | int ret; |
132 | int retval; | ||
133 | 134 | ||
134 | /* can not fail */ | 135 | /* can not fail */ |
135 | retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); | 136 | ret = device_for_each_child(&dev->dev, &data, error_detected_iter); |
136 | 137 | ||
137 | return result_data.result; | 138 | return data.result; |
138 | } | 139 | } |
139 | 140 | ||
140 | static int mmio_enabled_iter(struct device *device, void *data) | 141 | static int mmio_enabled_iter(struct device *device, void *data) |
@@ -272,10 +273,36 @@ static struct pci_driver pcie_portdriver = { | |||
272 | .driver.pm = PCIE_PORTDRV_PM_OPS, | 273 | .driver.pm = PCIE_PORTDRV_PM_OPS, |
273 | }; | 274 | }; |
274 | 275 | ||
276 | static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d) | ||
277 | { | ||
278 | pr_notice("%s detected: will not use MSI for PCIe PME signaling\n", | ||
279 | d->ident); | ||
280 | pcie_pme_disable_msi(); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = { | ||
285 | /* | ||
286 | * Boxes that should not use MSI for PCIe PME signaling. | ||
287 | */ | ||
288 | { | ||
289 | .callback = dmi_pcie_pme_disable_msi, | ||
290 | .ident = "MSI Wind U-100", | ||
291 | .matches = { | ||
292 | DMI_MATCH(DMI_SYS_VENDOR, | ||
293 | "MICRO-STAR INTERNATIONAL CO., LTD"), | ||
294 | DMI_MATCH(DMI_PRODUCT_NAME, "U-100"), | ||
295 | }, | ||
296 | }, | ||
297 | {} | ||
298 | }; | ||
299 | |||
275 | static int __init pcie_portdrv_init(void) | 300 | static int __init pcie_portdrv_init(void) |
276 | { | 301 | { |
277 | int retval; | 302 | int retval; |
278 | 303 | ||
304 | dmi_check_system(pcie_portdrv_dmi_table); | ||
305 | |||
279 | retval = pcie_port_bus_register(); | 306 | retval = pcie_port_bus_register(); |
280 | if (retval) { | 307 | if (retval) { |
281 | printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); | 308 | printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); |
@@ -288,7 +315,7 @@ static int __init pcie_portdrv_init(void) | |||
288 | return retval; | 315 | return retval; |
289 | } | 316 | } |
290 | 317 | ||
291 | static void __exit pcie_portdrv_exit(void) | 318 | static void __exit pcie_portdrv_exit(void) |
292 | { | 319 | { |
293 | pci_unregister_driver(&pcie_portdriver); | 320 | pci_unregister_driver(&pcie_portdriver); |
294 | pcie_port_bus_unregister(); | 321 | pcie_port_bus_unregister(); |