aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c91
1 files changed, 86 insertions, 5 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index cab05f31223f..460d046ab6fe 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -10,6 +10,8 @@
10#include <linux/kernel.h> 10#include <linux/kernel.h>
11#include <linux/delay.h> 11#include <linux/delay.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/of.h>
14#include <linux/of_pci.h>
13#include <linux/pci.h> 15#include <linux/pci.h>
14#include <linux/pm.h> 16#include <linux/pm.h>
15#include <linux/slab.h> 17#include <linux/slab.h>
@@ -3197,7 +3199,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
3197{ 3199{
3198 u16 csr; 3200 u16 csr;
3199 3201
3200 if (!dev->pm_cap) 3202 if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
3201 return -ENOTTY; 3203 return -ENOTTY;
3202 3204
3203 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr); 3205 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
@@ -3271,7 +3273,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
3271{ 3273{
3272 struct pci_dev *pdev; 3274 struct pci_dev *pdev;
3273 3275
3274 if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) 3276 if (pci_is_root_bus(dev->bus) || dev->subordinate ||
3277 !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
3275 return -ENOTTY; 3278 return -ENOTTY;
3276 3279
3277 list_for_each_entry(pdev, &dev->bus->devices, bus_list) 3280 list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3305,7 +3308,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
3305{ 3308{
3306 struct pci_dev *pdev; 3309 struct pci_dev *pdev;
3307 3310
3308 if (dev->subordinate || !dev->slot) 3311 if (dev->subordinate || !dev->slot ||
3312 dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
3309 return -ENOTTY; 3313 return -ENOTTY;
3310 3314
3311 list_for_each_entry(pdev, &dev->bus->devices, bus_list) 3315 list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3557,6 +3561,20 @@ int pci_try_reset_function(struct pci_dev *dev)
3557} 3561}
3558EXPORT_SYMBOL_GPL(pci_try_reset_function); 3562EXPORT_SYMBOL_GPL(pci_try_reset_function);
3559 3563
3564/* Do any devices on or below this bus prevent a bus reset? */
3565static bool pci_bus_resetable(struct pci_bus *bus)
3566{
3567 struct pci_dev *dev;
3568
3569 list_for_each_entry(dev, &bus->devices, bus_list) {
3570 if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
3571 (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
3572 return false;
3573 }
3574
3575 return true;
3576}
3577
3560/* Lock devices from the top of the tree down */ 3578/* Lock devices from the top of the tree down */
3561static void pci_bus_lock(struct pci_bus *bus) 3579static void pci_bus_lock(struct pci_bus *bus)
3562{ 3580{
@@ -3607,6 +3625,22 @@ unlock:
3607 return 0; 3625 return 0;
3608} 3626}
3609 3627
3628/* Do any devices on or below this slot prevent a bus reset? */
3629static bool pci_slot_resetable(struct pci_slot *slot)
3630{
3631 struct pci_dev *dev;
3632
3633 list_for_each_entry(dev, &slot->bus->devices, bus_list) {
3634 if (!dev->slot || dev->slot != slot)
3635 continue;
3636 if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
3637 (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
3638 return false;
3639 }
3640
3641 return true;
3642}
3643
3610/* Lock devices from the top of the tree down */ 3644/* Lock devices from the top of the tree down */
3611static void pci_slot_lock(struct pci_slot *slot) 3645static void pci_slot_lock(struct pci_slot *slot)
3612{ 3646{
@@ -3728,7 +3762,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
3728{ 3762{
3729 int rc; 3763 int rc;
3730 3764
3731 if (!slot) 3765 if (!slot || !pci_slot_resetable(slot))
3732 return -ENOTTY; 3766 return -ENOTTY;
3733 3767
3734 if (!probe) 3768 if (!probe)
@@ -3820,7 +3854,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);
3820 3854
3821static int pci_bus_reset(struct pci_bus *bus, int probe) 3855static int pci_bus_reset(struct pci_bus *bus, int probe)
3822{ 3856{
3823 if (!bus->self) 3857 if (!bus->self || !pci_bus_resetable(bus))
3824 return -ENOTTY; 3858 return -ENOTTY;
3825 3859
3826 if (probe) 3860 if (probe)
@@ -4439,6 +4473,53 @@ int pci_get_new_domain_nr(void)
4439{ 4473{
4440 return atomic_inc_return(&__domain_nr); 4474 return atomic_inc_return(&__domain_nr);
4441} 4475}
4476
4477#ifdef CONFIG_PCI_DOMAINS_GENERIC
4478void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
4479{
4480 static int use_dt_domains = -1;
4481 int domain = of_get_pci_domain_nr(parent->of_node);
4482
4483 /*
4484 * Check DT domain and use_dt_domains values.
4485 *
4486 * If DT domain property is valid (domain >= 0) and
4487 * use_dt_domains != 0, the DT assignment is valid since this means
4488 * we have not previously allocated a domain number by using
4489 * pci_get_new_domain_nr(); we should also update use_dt_domains to
4490 * 1, to indicate that we have just assigned a domain number from
4491 * DT.
4492 *
4493 * If DT domain property value is not valid (ie domain < 0), and we
4494 * have not previously assigned a domain number from DT
4495 * (use_dt_domains != 1) we should assign a domain number by
4496 * using the:
4497 *
4498 * pci_get_new_domain_nr()
4499 *
4500 * API and update the use_dt_domains value to keep track of method we
4501 * are using to assign domain numbers (use_dt_domains = 0).
4502 *
4503 * All other combinations imply we have a platform that is trying
4504 * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
4505 * which is a recipe for domain mishandling and it is prevented by
4506 * invalidating the domain value (domain = -1) and printing a
4507 * corresponding error.
4508 */
4509 if (domain >= 0 && use_dt_domains) {
4510 use_dt_domains = 1;
4511 } else if (domain < 0 && use_dt_domains != 1) {
4512 use_dt_domains = 0;
4513 domain = pci_get_new_domain_nr();
4514 } else {
4515 dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
4516 parent->of_node->full_name);
4517 domain = -1;
4518 }
4519
4520 bus->domain_nr = domain;
4521}
4522#endif
4442#endif 4523#endif
4443 4524
4444/** 4525/**