diff options
-rw-r--r-- | drivers/dca/dca-core.c | 122 | ||||
-rw-r--r-- | drivers/dma/ioat/pci.c | 2 | ||||
-rw-r--r-- | include/linux/dca.h | 11 |
3 files changed, 120 insertions, 15 deletions
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index 25b743abfb59..7e318de0904b 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/dca.h> | 29 | #include <linux/dca.h> |
30 | 30 | ||
31 | #define DCA_VERSION "1.8" | 31 | #define DCA_VERSION "1.12.1" |
32 | 32 | ||
33 | MODULE_VERSION(DCA_VERSION); | 33 | MODULE_VERSION(DCA_VERSION); |
34 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
@@ -36,20 +36,92 @@ MODULE_AUTHOR("Intel Corporation"); | |||
36 | 36 | ||
37 | static DEFINE_SPINLOCK(dca_lock); | 37 | static DEFINE_SPINLOCK(dca_lock); |
38 | 38 | ||
39 | static LIST_HEAD(dca_providers); | 39 | static LIST_HEAD(dca_domains); |
40 | 40 | ||
41 | static struct dca_provider *dca_find_provider_by_dev(struct device *dev) | 41 | static struct pci_bus *dca_pci_rc_from_dev(struct device *dev) |
42 | { | 42 | { |
43 | struct dca_provider *dca, *ret = NULL; | 43 | struct pci_dev *pdev = to_pci_dev(dev); |
44 | struct pci_bus *bus = pdev->bus; | ||
44 | 45 | ||
45 | list_for_each_entry(dca, &dca_providers, node) { | 46 | while (bus->parent) |
46 | if ((!dev) || (dca->ops->dev_managed(dca, dev))) { | 47 | bus = bus->parent; |
47 | ret = dca; | 48 | |
48 | break; | 49 | return bus; |
49 | } | 50 | } |
51 | |||
52 | static struct dca_domain *dca_allocate_domain(struct pci_bus *rc) | ||
53 | { | ||
54 | struct dca_domain *domain; | ||
55 | |||
56 | domain = kzalloc(sizeof(*domain), GFP_NOWAIT); | ||
57 | if (!domain) | ||
58 | return NULL; | ||
59 | |||
60 | INIT_LIST_HEAD(&domain->dca_providers); | ||
61 | domain->pci_rc = rc; | ||
62 | |||
63 | return domain; | ||
64 | } | ||
65 | |||
66 | static void dca_free_domain(struct dca_domain *domain) | ||
67 | { | ||
68 | list_del(&domain->node); | ||
69 | kfree(domain); | ||
70 | } | ||
71 | |||
72 | static struct dca_domain *dca_find_domain(struct pci_bus *rc) | ||
73 | { | ||
74 | struct dca_domain *domain; | ||
75 | |||
76 | list_for_each_entry(domain, &dca_domains, node) | ||
77 | if (domain->pci_rc == rc) | ||
78 | return domain; | ||
79 | |||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | static struct dca_domain *dca_get_domain(struct device *dev) | ||
84 | { | ||
85 | struct pci_bus *rc; | ||
86 | struct dca_domain *domain; | ||
87 | |||
88 | rc = dca_pci_rc_from_dev(dev); | ||
89 | domain = dca_find_domain(rc); | ||
90 | |||
91 | if (!domain) { | ||
92 | domain = dca_allocate_domain(rc); | ||
93 | if (domain) | ||
94 | list_add(&domain->node, &dca_domains); | ||
95 | } | ||
96 | |||
97 | return domain; | ||
98 | } | ||
99 | |||
100 | static struct dca_provider *dca_find_provider_by_dev(struct device *dev) | ||
101 | { | ||
102 | struct dca_provider *dca; | ||
103 | struct pci_bus *rc; | ||
104 | struct dca_domain *domain; | ||
105 | |||
106 | if (dev) { | ||
107 | rc = dca_pci_rc_from_dev(dev); | ||
108 | domain = dca_find_domain(rc); | ||
109 | if (!domain) | ||
110 | return NULL; | ||
111 | } else { | ||
112 | if (!list_empty(&dca_domains)) | ||
113 | domain = list_first_entry(&dca_domains, | ||
114 | struct dca_domain, | ||
115 | node); | ||
116 | else | ||
117 | return NULL; | ||
50 | } | 118 | } |
51 | 119 | ||
52 | return ret; | 120 | list_for_each_entry(dca, &domain->dca_providers, node) |
121 | if ((!dev) || (dca->ops->dev_managed(dca, dev))) | ||
122 | return dca; | ||
123 | |||
124 | return NULL; | ||
53 | } | 125 | } |
54 | 126 | ||
55 | /** | 127 | /** |
@@ -61,6 +133,8 @@ int dca_add_requester(struct device *dev) | |||
61 | struct dca_provider *dca; | 133 | struct dca_provider *dca; |
62 | int err, slot = -ENODEV; | 134 | int err, slot = -ENODEV; |
63 | unsigned long flags; | 135 | unsigned long flags; |
136 | struct pci_bus *pci_rc; | ||
137 | struct dca_domain *domain; | ||
64 | 138 | ||
65 | if (!dev) | 139 | if (!dev) |
66 | return -EFAULT; | 140 | return -EFAULT; |
@@ -74,7 +148,14 @@ int dca_add_requester(struct device *dev) | |||
74 | return -EEXIST; | 148 | return -EEXIST; |
75 | } | 149 | } |
76 | 150 | ||
77 | list_for_each_entry(dca, &dca_providers, node) { | 151 | pci_rc = dca_pci_rc_from_dev(dev); |
152 | domain = dca_find_domain(pci_rc); | ||
153 | if (!domain) { | ||
154 | spin_unlock_irqrestore(&dca_lock, flags); | ||
155 | return -ENODEV; | ||
156 | } | ||
157 | |||
158 | list_for_each_entry(dca, &domain->dca_providers, node) { | ||
78 | slot = dca->ops->add_requester(dca, dev); | 159 | slot = dca->ops->add_requester(dca, dev); |
79 | if (slot >= 0) | 160 | if (slot >= 0) |
80 | break; | 161 | break; |
@@ -222,13 +303,19 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev) | |||
222 | { | 303 | { |
223 | int err; | 304 | int err; |
224 | unsigned long flags; | 305 | unsigned long flags; |
306 | struct dca_domain *domain; | ||
225 | 307 | ||
226 | err = dca_sysfs_add_provider(dca, dev); | 308 | err = dca_sysfs_add_provider(dca, dev); |
227 | if (err) | 309 | if (err) |
228 | return err; | 310 | return err; |
229 | 311 | ||
230 | spin_lock_irqsave(&dca_lock, flags); | 312 | spin_lock_irqsave(&dca_lock, flags); |
231 | list_add(&dca->node, &dca_providers); | 313 | domain = dca_get_domain(dev); |
314 | if (!domain) { | ||
315 | spin_unlock_irqrestore(&dca_lock, flags); | ||
316 | return -ENODEV; | ||
317 | } | ||
318 | list_add(&dca->node, &domain->dca_providers); | ||
232 | spin_unlock_irqrestore(&dca_lock, flags); | 319 | spin_unlock_irqrestore(&dca_lock, flags); |
233 | 320 | ||
234 | blocking_notifier_call_chain(&dca_provider_chain, | 321 | blocking_notifier_call_chain(&dca_provider_chain, |
@@ -241,15 +328,24 @@ EXPORT_SYMBOL_GPL(register_dca_provider); | |||
241 | * unregister_dca_provider - remove a dca provider | 328 | * unregister_dca_provider - remove a dca provider |
242 | * @dca - struct created by alloc_dca_provider() | 329 | * @dca - struct created by alloc_dca_provider() |
243 | */ | 330 | */ |
244 | void unregister_dca_provider(struct dca_provider *dca) | 331 | void unregister_dca_provider(struct dca_provider *dca, struct device *dev) |
245 | { | 332 | { |
246 | unsigned long flags; | 333 | unsigned long flags; |
334 | struct pci_bus *pci_rc; | ||
335 | struct dca_domain *domain; | ||
247 | 336 | ||
248 | blocking_notifier_call_chain(&dca_provider_chain, | 337 | blocking_notifier_call_chain(&dca_provider_chain, |
249 | DCA_PROVIDER_REMOVE, NULL); | 338 | DCA_PROVIDER_REMOVE, NULL); |
250 | 339 | ||
251 | spin_lock_irqsave(&dca_lock, flags); | 340 | spin_lock_irqsave(&dca_lock, flags); |
341 | |||
252 | list_del(&dca->node); | 342 | list_del(&dca->node); |
343 | |||
344 | pci_rc = dca_pci_rc_from_dev(dev); | ||
345 | domain = dca_find_domain(pci_rc); | ||
346 | if (list_empty(&domain->dca_providers)) | ||
347 | dca_free_domain(domain); | ||
348 | |||
253 | spin_unlock_irqrestore(&dca_lock, flags); | 349 | spin_unlock_irqrestore(&dca_lock, flags); |
254 | 350 | ||
255 | dca_sysfs_remove_provider(dca); | 351 | dca_sysfs_remove_provider(dca); |
diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index c788fa266470..d545fae30f37 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c | |||
@@ -175,7 +175,7 @@ static void __devexit ioat_remove(struct pci_dev *pdev) | |||
175 | 175 | ||
176 | dev_err(&pdev->dev, "Removing dma and dca services\n"); | 176 | dev_err(&pdev->dev, "Removing dma and dca services\n"); |
177 | if (device->dca) { | 177 | if (device->dca) { |
178 | unregister_dca_provider(device->dca); | 178 | unregister_dca_provider(device->dca, &pdev->dev); |
179 | free_dca_provider(device->dca); | 179 | free_dca_provider(device->dca); |
180 | device->dca = NULL; | 180 | device->dca = NULL; |
181 | } | 181 | } |
diff --git a/include/linux/dca.h b/include/linux/dca.h index 9c20c7e87d0a..d27a7a05718d 100644 --- a/include/linux/dca.h +++ b/include/linux/dca.h | |||
@@ -20,6 +20,9 @@ | |||
20 | */ | 20 | */ |
21 | #ifndef DCA_H | 21 | #ifndef DCA_H |
22 | #define DCA_H | 22 | #define DCA_H |
23 | |||
24 | #include <linux/pci.h> | ||
25 | |||
23 | /* DCA Provider API */ | 26 | /* DCA Provider API */ |
24 | 27 | ||
25 | /* DCA Notifier Interface */ | 28 | /* DCA Notifier Interface */ |
@@ -36,6 +39,12 @@ struct dca_provider { | |||
36 | int id; | 39 | int id; |
37 | }; | 40 | }; |
38 | 41 | ||
42 | struct dca_domain { | ||
43 | struct list_head node; | ||
44 | struct list_head dca_providers; | ||
45 | struct pci_bus *pci_rc; | ||
46 | }; | ||
47 | |||
39 | struct dca_ops { | 48 | struct dca_ops { |
40 | int (*add_requester) (struct dca_provider *, struct device *); | 49 | int (*add_requester) (struct dca_provider *, struct device *); |
41 | int (*remove_requester) (struct dca_provider *, struct device *); | 50 | int (*remove_requester) (struct dca_provider *, struct device *); |
@@ -47,7 +56,7 @@ struct dca_ops { | |||
47 | struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size); | 56 | struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size); |
48 | void free_dca_provider(struct dca_provider *dca); | 57 | void free_dca_provider(struct dca_provider *dca); |
49 | int register_dca_provider(struct dca_provider *dca, struct device *dev); | 58 | int register_dca_provider(struct dca_provider *dca, struct device *dev); |
50 | void unregister_dca_provider(struct dca_provider *dca); | 59 | void unregister_dca_provider(struct dca_provider *dca, struct device *dev); |
51 | 60 | ||
52 | static inline void *dca_priv(struct dca_provider *dca) | 61 | static inline void *dca_priv(struct dca_provider *dca) |
53 | { | 62 | { |