aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/iov.c
diff options
context:
space:
mode:
authorJiang Liu <liuj97@gmail.com>2013-05-25 09:48:37 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-06-14 19:39:40 -0400
commitdc087f2f6a2925e81831f3016b9cbb6e470e7423 (patch)
tree28d1e60368d9e13b4716f5ecceb1af36565dea07 /drivers/pci/iov.c
parentd35329d9f17f05277f2718eb54402dea3e833d19 (diff)
PCI: Simplify IOV implementation and fix reference count races
Trivial changes to IOV: 1) use new PCI interfaces to simplify IOV implementation 2) fix some reference count related race windows [bhelgaas: fix virtfn_add() add bus/alloc dev error paths] Signed-off-by: Jiang Liu <jiang.liu@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Donald Dutile <ddutile@redhat.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Ram Pai <linuxram@us.ibm.com>
Diffstat (limited to 'drivers/pci/iov.c')
-rw-r--r--drivers/pci/iov.c59
1 files changed, 24 insertions, 35 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 8f1e1174b71f..5fffca995a91 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -51,24 +51,16 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
51 return child; 51 return child;
52} 52}
53 53
54static void virtfn_remove_bus(struct pci_bus *bus, int busnr) 54static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
55{ 55{
56 struct pci_bus *child; 56 if (physbus != virtbus && list_empty(&virtbus->devices))
57 57 pci_remove_bus(virtbus);
58 if (bus->number == busnr)
59 return;
60
61 child = pci_find_bus(pci_domain_nr(bus), busnr);
62 BUG_ON(!child);
63
64 if (list_empty(&child->devices))
65 pci_remove_bus(child);
66} 58}
67 59
68static int virtfn_add(struct pci_dev *dev, int id, int reset) 60static int virtfn_add(struct pci_dev *dev, int id, int reset)
69{ 61{
70 int i; 62 int i;
71 int rc; 63 int rc = -ENOMEM;
72 u64 size; 64 u64 size;
73 char buf[VIRTFN_ID_LEN]; 65 char buf[VIRTFN_ID_LEN];
74 struct pci_dev *virtfn; 66 struct pci_dev *virtfn;
@@ -76,18 +68,15 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
76 struct pci_sriov *iov = dev->sriov; 68 struct pci_sriov *iov = dev->sriov;
77 struct pci_bus *bus; 69 struct pci_bus *bus;
78 70
79 virtfn = pci_alloc_dev(NULL);
80 if (!virtfn)
81 return -ENOMEM;
82
83 mutex_lock(&iov->dev->sriov->lock); 71 mutex_lock(&iov->dev->sriov->lock);
84 bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); 72 bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
85 if (!bus) { 73 if (!bus)
86 kfree(virtfn); 74 goto failed;
87 mutex_unlock(&iov->dev->sriov->lock); 75
88 return -ENOMEM; 76 virtfn = pci_alloc_dev(bus);
89 } 77 if (!virtfn)
90 virtfn->bus = pci_bus_get(bus); 78 goto failed0;
79
91 virtfn->devfn = virtfn_devfn(dev, id); 80 virtfn->devfn = virtfn_devfn(dev, id);
92 virtfn->vendor = dev->vendor; 81 virtfn->vendor = dev->vendor;
93 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);
@@ -136,7 +125,9 @@ failed1:
136 pci_dev_put(dev); 125 pci_dev_put(dev);
137 mutex_lock(&iov->dev->sriov->lock); 126 mutex_lock(&iov->dev->sriov->lock);
138 pci_stop_and_remove_bus_device(virtfn); 127 pci_stop_and_remove_bus_device(virtfn);
139 virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); 128failed0:
129 virtfn_remove_bus(dev->bus, bus);
130failed:
140 mutex_unlock(&iov->dev->sriov->lock); 131 mutex_unlock(&iov->dev->sriov->lock);
141 132
142 return rc; 133 return rc;
@@ -145,20 +136,15 @@ failed1:
145static void virtfn_remove(struct pci_dev *dev, int id, int reset) 136static void virtfn_remove(struct pci_dev *dev, int id, int reset)
146{ 137{
147 char buf[VIRTFN_ID_LEN]; 138 char buf[VIRTFN_ID_LEN];
148 struct pci_bus *bus;
149 struct pci_dev *virtfn; 139 struct pci_dev *virtfn;
150 struct pci_sriov *iov = dev->sriov; 140 struct pci_sriov *iov = dev->sriov;
151 141
152 bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); 142 virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
153 if (!bus) 143 virtfn_bus(dev, id),
154 return; 144 virtfn_devfn(dev, id));
155
156 virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
157 if (!virtfn) 145 if (!virtfn)
158 return; 146 return;
159 147
160 pci_dev_put(virtfn);
161
162 if (reset) { 148 if (reset) {
163 device_release_driver(&virtfn->dev); 149 device_release_driver(&virtfn->dev);
164 __pci_reset_function(virtfn); 150 __pci_reset_function(virtfn);
@@ -176,9 +162,11 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
176 162
177 mutex_lock(&iov->dev->sriov->lock); 163 mutex_lock(&iov->dev->sriov->lock);
178 pci_stop_and_remove_bus_device(virtfn); 164 pci_stop_and_remove_bus_device(virtfn);
179 virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); 165 virtfn_remove_bus(dev->bus, virtfn->bus);
180 mutex_unlock(&iov->dev->sriov->lock); 166 mutex_unlock(&iov->dev->sriov->lock);
181 167
168 /* balance pci_get_domain_bus_and_slot() */
169 pci_dev_put(virtfn);
182 pci_dev_put(dev); 170 pci_dev_put(dev);
183} 171}
184 172
@@ -335,13 +323,14 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
335 if (!pdev) 323 if (!pdev)
336 return -ENODEV; 324 return -ENODEV;
337 325
338 pci_dev_put(pdev); 326 if (!pdev->is_physfn) {
339 327 pci_dev_put(pdev);
340 if (!pdev->is_physfn)
341 return -ENODEV; 328 return -ENODEV;
329 }
342 330
343 rc = sysfs_create_link(&dev->dev.kobj, 331 rc = sysfs_create_link(&dev->dev.kobj,
344 &pdev->dev.kobj, "dep_link"); 332 &pdev->dev.kobj, "dep_link");
333 pci_dev_put(pdev);
345 if (rc) 334 if (rc)
346 return rc; 335 return rc;
347 } 336 }