aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/iov.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-06-14 19:47:46 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-06-14 19:47:46 -0400
commitdf58f46c0f2a1d69268b734ac25c87ffb7aeb32a (patch)
tree46540d251f4f1c1e44af8d5ce339b37e0045ffe0 /drivers/pci/iov.c
parent726246d2e6d0ed53ac22b6fec50d1345f25e6730 (diff)
parent050134864c1c76f49eb86c134a0e02fb3c196382 (diff)
Merge branch 'pci/jiang-bus-lock-v3' into next
* pci/jiang-bus-lock-v3: PCI: Return early on allocation failures to unindent mainline code PCI: Simplify IOV implementation and fix reference count races PCI: Drop redundant setting of bus->is_added in virtfn_add_bus() unicore32/PCI: Remove redundant call of pci_bus_add_devices() m68k/PCI: Remove redundant call of pci_bus_add_devices() PCI: Rename pci_release_bus_bridge_dev() to pci_release_host_bridge_dev() PCI: Fix refcount issue in pci_create_root_bus() error recovery path ia64/PCI: Clean up pci_scan_root_bus() usage PCI: Convert alloc_pci_dev(void) to pci_alloc_dev(bus) PCI: Introduce pci_alloc_dev(struct pci_bus*) to replace alloc_pci_dev() PCI: Introduce pci_bus_{get|put}() to manage PCI bus reference count Conflicts: drivers/pci/probe.c
Diffstat (limited to 'drivers/pci/iov.c')
-rw-r--r--drivers/pci/iov.c60
1 files changed, 25 insertions, 35 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index a971a6f6268d..de8ffacf9c9b 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -47,46 +47,36 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
47 return NULL; 47 return NULL;
48 48
49 pci_bus_insert_busn_res(child, busnr, busnr); 49 pci_bus_insert_busn_res(child, busnr, busnr);
50 bus->is_added = 1;
51 50
52 return child; 51 return child;
53} 52}
54 53
55static void virtfn_remove_bus(struct pci_bus *bus, int busnr) 54static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
56{ 55{
57 struct pci_bus *child; 56 if (physbus != virtbus && list_empty(&virtbus->devices))
58 57 pci_remove_bus(virtbus);
59 if (bus->number == busnr)
60 return;
61
62 child = pci_find_bus(pci_domain_nr(bus), busnr);
63 BUG_ON(!child);
64
65 if (list_empty(&child->devices))
66 pci_remove_bus(child);
67} 58}
68 59
69static int virtfn_add(struct pci_dev *dev, int id, int reset) 60static int virtfn_add(struct pci_dev *dev, int id, int reset)
70{ 61{
71 int i; 62 int i;
72 int rc; 63 int rc = -ENOMEM;
73 u64 size; 64 u64 size;
74 char buf[VIRTFN_ID_LEN]; 65 char buf[VIRTFN_ID_LEN];
75 struct pci_dev *virtfn; 66 struct pci_dev *virtfn;
76 struct resource *res; 67 struct resource *res;
77 struct pci_sriov *iov = dev->sriov; 68 struct pci_sriov *iov = dev->sriov;
69 struct pci_bus *bus;
78 70
79 virtfn = alloc_pci_dev(); 71 mutex_lock(&iov->dev->sriov->lock);
72 bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
73 if (!bus)
74 goto failed;
75
76 virtfn = pci_alloc_dev(bus);
80 if (!virtfn) 77 if (!virtfn)
81 return -ENOMEM; 78 goto failed0;
82 79
83 mutex_lock(&iov->dev->sriov->lock);
84 virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
85 if (!virtfn->bus) {
86 kfree(virtfn);
87 mutex_unlock(&iov->dev->sriov->lock);
88 return -ENOMEM;
89 }
90 virtfn->devfn = virtfn_devfn(dev, id); 80 virtfn->devfn = virtfn_devfn(dev, id);
91 virtfn->vendor = dev->vendor; 81 virtfn->vendor = dev->vendor;
92 pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); 82 pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
@@ -134,7 +124,9 @@ failed1:
134 pci_dev_put(dev); 124 pci_dev_put(dev);
135 mutex_lock(&iov->dev->sriov->lock); 125 mutex_lock(&iov->dev->sriov->lock);
136 pci_stop_and_remove_bus_device(virtfn); 126 pci_stop_and_remove_bus_device(virtfn);
137 virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); 127failed0:
128 virtfn_remove_bus(dev->bus, bus);
129failed:
138 mutex_unlock(&iov->dev->sriov->lock); 130 mutex_unlock(&iov->dev->sriov->lock);
139 131
140 return rc; 132 return rc;
@@ -143,20 +135,15 @@ failed1:
143static void virtfn_remove(struct pci_dev *dev, int id, int reset) 135static void virtfn_remove(struct pci_dev *dev, int id, int reset)
144{ 136{
145 char buf[VIRTFN_ID_LEN]; 137 char buf[VIRTFN_ID_LEN];
146 struct pci_bus *bus;
147 struct pci_dev *virtfn; 138 struct pci_dev *virtfn;
148 struct pci_sriov *iov = dev->sriov; 139 struct pci_sriov *iov = dev->sriov;
149 140
150 bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); 141 virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
151 if (!bus) 142 virtfn_bus(dev, id),
152 return; 143 virtfn_devfn(dev, id));
153
154 virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
155 if (!virtfn) 144 if (!virtfn)
156 return; 145 return;
157 146
158 pci_dev_put(virtfn);
159
160 if (reset) { 147 if (reset) {
161 device_release_driver(&virtfn->dev); 148 device_release_driver(&virtfn->dev);
162 __pci_reset_function(virtfn); 149 __pci_reset_function(virtfn);
@@ -174,9 +161,11 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
174 161
175 mutex_lock(&iov->dev->sriov->lock); 162 mutex_lock(&iov->dev->sriov->lock);
176 pci_stop_and_remove_bus_device(virtfn); 163 pci_stop_and_remove_bus_device(virtfn);
177 virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); 164 virtfn_remove_bus(dev->bus, virtfn->bus);
178 mutex_unlock(&iov->dev->sriov->lock); 165 mutex_unlock(&iov->dev->sriov->lock);
179 166
167 /* balance pci_get_domain_bus_and_slot() */
168 pci_dev_put(virtfn);
180 pci_dev_put(dev); 169 pci_dev_put(dev);
181} 170}
182 171
@@ -333,13 +322,14 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
333 if (!pdev) 322 if (!pdev)
334 return -ENODEV; 323 return -ENODEV;
335 324
336 pci_dev_put(pdev); 325 if (!pdev->is_physfn) {
337 326 pci_dev_put(pdev);
338 if (!pdev->is_physfn)
339 return -ENODEV; 327 return -ENODEV;
328 }
340 329
341 rc = sysfs_create_link(&dev->dev.kobj, 330 rc = sysfs_create_link(&dev->dev.kobj,
342 &pdev->dev.kobj, "dep_link"); 331 &pdev->dev.kobj, "dep_link");
332 pci_dev_put(pdev);
343 if (rc) 333 if (rc)
344 return rc; 334 return rc;
345 } 335 }