Blame view
drivers/dca/dca-core.c
10.9 KB
7589670f3 DCA: Add Direct C... |
1 |
/* |
211a22ce0 I/OAT: update dri... |
2 |
* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. |
7589670f3 DCA: Add Direct C... |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ /* * This driver supports an interface for DCA clients and providers to meet. */ #include <linux/kernel.h> #include <linux/notifier.h> #include <linux/device.h> #include <linux/dca.h> |
5a0e3ad6a include cleanup: ... |
30 |
#include <linux/slab.h> |
d229807f6 drivers/dca: Add ... |
31 |
#include <linux/module.h> |
7589670f3 DCA: Add Direct C... |
32 |
|
1a5aeeecd dca: registering ... |
33 |
#define DCA_VERSION "1.12.1" |
7589670f3 DCA: Add Direct C... |
34 |
|
7f1b358a2 I/OAT: I/OAT vers... |
35 36 37 |
MODULE_VERSION(DCA_VERSION); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Intel Corporation"); |
7589670f3 DCA: Add Direct C... |
38 |
|
a1741e7fc locking, drivers/... |
39 |
static DEFINE_RAW_SPINLOCK(dca_lock); |
7589670f3 DCA: Add Direct C... |
40 |
|
1a5aeeecd dca: registering ... |
41 |
static LIST_HEAD(dca_domains); |
7f1b358a2 I/OAT: I/OAT vers... |
42 |
|
4e8cec269 dca: disable dca ... |
43 44 45 |
static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); static int dca_providers_blocked; |
1a5aeeecd dca: registering ... |
46 |
static struct pci_bus *dca_pci_rc_from_dev(struct device *dev) |
7f1b358a2 I/OAT: I/OAT vers... |
47 |
{ |
1a5aeeecd dca: registering ... |
48 49 |
struct pci_dev *pdev = to_pci_dev(dev); struct pci_bus *bus = pdev->bus; |
7f1b358a2 I/OAT: I/OAT vers... |
50 |
|
1a5aeeecd dca: registering ... |
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
while (bus->parent) bus = bus->parent; return bus; } static struct dca_domain *dca_allocate_domain(struct pci_bus *rc) { struct dca_domain *domain; domain = kzalloc(sizeof(*domain), GFP_NOWAIT); if (!domain) return NULL; INIT_LIST_HEAD(&domain->dca_providers); domain->pci_rc = rc; return domain; } static void dca_free_domain(struct dca_domain *domain) { list_del(&domain->node); kfree(domain); } |
4e8cec269 dca: disable dca ... |
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
static int dca_provider_ioat_ver_3_0(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); return ((pdev->vendor == PCI_VENDOR_ID_INTEL) && ((pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG0) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG1) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG2) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG3) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG4) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG5) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG6) || (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG7))); } static void unregister_dca_providers(void) { struct dca_provider *dca, *_dca; struct list_head unregistered_providers; struct dca_domain *domain; unsigned long flags; blocking_notifier_call_chain(&dca_provider_chain, DCA_PROVIDER_REMOVE, NULL); INIT_LIST_HEAD(&unregistered_providers); |
a1741e7fc locking, drivers/... |
102 |
raw_spin_lock_irqsave(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
103 104 |
if (list_empty(&dca_domains)) { |
a1741e7fc locking, drivers/... |
105 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
106 107 108 109 110 |
return; } /* at this point only one domain in the list is expected */ domain = list_first_entry(&dca_domains, struct dca_domain, node); |
4e8cec269 dca: disable dca ... |
111 |
|
3bb598fb2 drivers/dca/dca-c... |
112 113 |
list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) list_move(&dca->node, &unregistered_providers); |
4e8cec269 dca: disable dca ... |
114 115 |
dca_free_domain(domain); |
a1741e7fc locking, drivers/... |
116 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
117 118 119 120 121 122 |
list_for_each_entry_safe(dca, _dca, &unregistered_providers, node) { dca_sysfs_remove_provider(dca); list_del(&dca->node); } } |
1a5aeeecd dca: registering ... |
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
static struct dca_domain *dca_find_domain(struct pci_bus *rc) { struct dca_domain *domain; list_for_each_entry(domain, &dca_domains, node) if (domain->pci_rc == rc) return domain; return NULL; } static struct dca_domain *dca_get_domain(struct device *dev) { struct pci_bus *rc; struct dca_domain *domain; rc = dca_pci_rc_from_dev(dev); domain = dca_find_domain(rc); if (!domain) { |
a1741e7fc locking, drivers/... |
143 |
if (dca_provider_ioat_ver_3_0(dev) && !list_empty(&dca_domains)) |
4e8cec269 dca: disable dca ... |
144 |
dca_providers_blocked = 1; |
1a5aeeecd dca: registering ... |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
} return domain; } static struct dca_provider *dca_find_provider_by_dev(struct device *dev) { struct dca_provider *dca; struct pci_bus *rc; struct dca_domain *domain; if (dev) { rc = dca_pci_rc_from_dev(dev); domain = dca_find_domain(rc); if (!domain) return NULL; } else { if (!list_empty(&dca_domains)) domain = list_first_entry(&dca_domains, struct dca_domain, node); else return NULL; |
7f1b358a2 I/OAT: I/OAT vers... |
168 |
} |
1a5aeeecd dca: registering ... |
169 170 171 172 173 |
list_for_each_entry(dca, &domain->dca_providers, node) if ((!dev) || (dca->ops->dev_managed(dca, dev))) return dca; return NULL; |
7f1b358a2 I/OAT: I/OAT vers... |
174 |
} |
7589670f3 DCA: Add Direct C... |
175 176 177 178 179 180 181 |
/** * dca_add_requester - add a dca client to the list * @dev - the device that wants dca service */ int dca_add_requester(struct device *dev) { |
7f1b358a2 I/OAT: I/OAT vers... |
182 183 |
struct dca_provider *dca; int err, slot = -ENODEV; |
eb4400e3a dca: redesign loc... |
184 |
unsigned long flags; |
1a5aeeecd dca: registering ... |
185 186 |
struct pci_bus *pci_rc; struct dca_domain *domain; |
7589670f3 DCA: Add Direct C... |
187 |
|
7f1b358a2 I/OAT: I/OAT vers... |
188 189 |
if (!dev) return -EFAULT; |
7589670f3 DCA: Add Direct C... |
190 |
|
a1741e7fc locking, drivers/... |
191 |
raw_spin_lock_irqsave(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
192 193 194 195 |
/* check if the requester has not been added already */ dca = dca_find_provider_by_dev(dev); if (dca) { |
a1741e7fc locking, drivers/... |
196 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
197 198 |
return -EEXIST; } |
1a5aeeecd dca: registering ... |
199 200 201 |
pci_rc = dca_pci_rc_from_dev(dev); domain = dca_find_domain(pci_rc); if (!domain) { |
a1741e7fc locking, drivers/... |
202 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
1a5aeeecd dca: registering ... |
203 204 205 206 |
return -ENODEV; } list_for_each_entry(dca, &domain->dca_providers, node) { |
7f1b358a2 I/OAT: I/OAT vers... |
207 208 209 210 |
slot = dca->ops->add_requester(dca, dev); if (slot >= 0) break; } |
eb4400e3a dca: redesign loc... |
211 |
|
a1741e7fc locking, drivers/... |
212 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
eb4400e3a dca: redesign loc... |
213 214 |
if (slot < 0) |
7589670f3 DCA: Add Direct C... |
215 |
return slot; |
7f1b358a2 I/OAT: I/OAT vers... |
216 |
err = dca_sysfs_add_req(dca, dev, slot); |
7589670f3 DCA: Add Direct C... |
217 |
if (err) { |
a1741e7fc locking, drivers/... |
218 |
raw_spin_lock_irqsave(&dca_lock, flags); |
eb4400e3a dca: redesign loc... |
219 220 |
if (dca == dca_find_provider_by_dev(dev)) dca->ops->remove_requester(dca, dev); |
a1741e7fc locking, drivers/... |
221 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
7589670f3 DCA: Add Direct C... |
222 223 224 225 226 227 228 229 230 231 232 233 234 |
return err; } return 0; } EXPORT_SYMBOL_GPL(dca_add_requester); /** * dca_remove_requester - remove a dca client from the list * @dev - the device that wants dca service */ int dca_remove_requester(struct device *dev) { |
7f1b358a2 I/OAT: I/OAT vers... |
235 |
struct dca_provider *dca; |
7589670f3 DCA: Add Direct C... |
236 |
int slot; |
eb4400e3a dca: redesign loc... |
237 |
unsigned long flags; |
7f1b358a2 I/OAT: I/OAT vers... |
238 239 240 |
if (!dev) return -EFAULT; |
7589670f3 DCA: Add Direct C... |
241 |
|
a1741e7fc locking, drivers/... |
242 |
raw_spin_lock_irqsave(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
243 244 |
dca = dca_find_provider_by_dev(dev); if (!dca) { |
a1741e7fc locking, drivers/... |
245 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
246 247 248 |
return -ENODEV; } slot = dca->ops->remove_requester(dca, dev); |
a1741e7fc locking, drivers/... |
249 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
eb4400e3a dca: redesign loc... |
250 251 |
if (slot < 0) |
7589670f3 DCA: Add Direct C... |
252 |
return slot; |
7f1b358a2 I/OAT: I/OAT vers... |
253 |
dca_sysfs_remove_req(dca, slot); |
7589670f3 DCA: Add Direct C... |
254 255 256 257 258 |
return 0; } EXPORT_SYMBOL_GPL(dca_remove_requester); /** |
7f1b358a2 I/OAT: I/OAT vers... |
259 260 |
* dca_common_get_tag - return the dca tag (serves both new and old api) * @dev - the device that wants dca service |
7589670f3 DCA: Add Direct C... |
261 262 |
* @cpu - the cpuid as returned by get_cpu() */ |
7f1b358a2 I/OAT: I/OAT vers... |
263 |
u8 dca_common_get_tag(struct device *dev, int cpu) |
7589670f3 DCA: Add Direct C... |
264 |
{ |
7f1b358a2 I/OAT: I/OAT vers... |
265 266 |
struct dca_provider *dca; u8 tag; |
eb4400e3a dca: redesign loc... |
267 |
unsigned long flags; |
7f1b358a2 I/OAT: I/OAT vers... |
268 |
|
a1741e7fc locking, drivers/... |
269 |
raw_spin_lock_irqsave(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
270 271 272 |
dca = dca_find_provider_by_dev(dev); if (!dca) { |
a1741e7fc locking, drivers/... |
273 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
7589670f3 DCA: Add Direct C... |
274 |
return -ENODEV; |
7f1b358a2 I/OAT: I/OAT vers... |
275 276 |
} tag = dca->ops->get_tag(dca, dev, cpu); |
a1741e7fc locking, drivers/... |
277 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
7f1b358a2 I/OAT: I/OAT vers... |
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
return tag; } /** * dca3_get_tag - return the dca tag to the requester device * for the given cpu (new api) * @dev - the device that wants dca service * @cpu - the cpuid as returned by get_cpu() */ u8 dca3_get_tag(struct device *dev, int cpu) { if (!dev) return -EFAULT; return dca_common_get_tag(dev, cpu); } EXPORT_SYMBOL_GPL(dca3_get_tag); /** * dca_get_tag - return the dca tag for the given cpu (old api) * @cpu - the cpuid as returned by get_cpu() */ u8 dca_get_tag(int cpu) { struct device *dev = NULL; return dca_common_get_tag(dev, cpu); |
7589670f3 DCA: Add Direct C... |
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
} EXPORT_SYMBOL_GPL(dca_get_tag); /** * alloc_dca_provider - get data struct for describing a dca provider * @ops - pointer to struct of dca operation function pointers * @priv_size - size of extra mem to be added for provider's needs */ struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size) { struct dca_provider *dca; int alloc_size; alloc_size = (sizeof(*dca) + priv_size); dca = kzalloc(alloc_size, GFP_KERNEL); if (!dca) return NULL; dca->ops = ops; return dca; } EXPORT_SYMBOL_GPL(alloc_dca_provider); /** * free_dca_provider - release the dca provider data struct * @ops - pointer to struct of dca operation function pointers * @priv_size - size of extra mem to be added for provider's needs */ void free_dca_provider(struct dca_provider *dca) { kfree(dca); } EXPORT_SYMBOL_GPL(free_dca_provider); |
7589670f3 DCA: Add Direct C... |
338 339 340 341 342 343 344 345 |
/** * register_dca_provider - register a dca provider * @dca - struct created by alloc_dca_provider() * @dev - device providing dca services */ int register_dca_provider(struct dca_provider *dca, struct device *dev) { int err; |
eb4400e3a dca: redesign loc... |
346 |
unsigned long flags; |
a1741e7fc locking, drivers/... |
347 |
struct dca_domain *domain, *newdomain = NULL; |
7589670f3 DCA: Add Direct C... |
348 |
|
a1741e7fc locking, drivers/... |
349 |
raw_spin_lock_irqsave(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
350 |
if (dca_providers_blocked) { |
a1741e7fc locking, drivers/... |
351 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
352 353 |
return -ENODEV; } |
a1741e7fc locking, drivers/... |
354 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
355 |
|
7589670f3 DCA: Add Direct C... |
356 357 358 |
err = dca_sysfs_add_provider(dca, dev); if (err) return err; |
eb4400e3a dca: redesign loc... |
359 |
|
a1741e7fc locking, drivers/... |
360 |
raw_spin_lock_irqsave(&dca_lock, flags); |
1a5aeeecd dca: registering ... |
361 362 |
domain = dca_get_domain(dev); if (!domain) { |
a1741e7fc locking, drivers/... |
363 |
struct pci_bus *rc; |
4e8cec269 dca: disable dca ... |
364 |
if (dca_providers_blocked) { |
a1741e7fc locking, drivers/... |
365 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
4e8cec269 dca: disable dca ... |
366 367 |
dca_sysfs_remove_provider(dca); unregister_dca_providers(); |
a1741e7fc locking, drivers/... |
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
return -ENODEV; } raw_spin_unlock_irqrestore(&dca_lock, flags); rc = dca_pci_rc_from_dev(dev); newdomain = dca_allocate_domain(rc); if (!newdomain) return -ENODEV; raw_spin_lock_irqsave(&dca_lock, flags); /* Recheck, we might have raced after dropping the lock */ domain = dca_get_domain(dev); if (!domain) { domain = newdomain; newdomain = NULL; list_add(&domain->node, &dca_domains); |
4e8cec269 dca: disable dca ... |
383 |
} |
1a5aeeecd dca: registering ... |
384 385 |
} list_add(&dca->node, &domain->dca_providers); |
a1741e7fc locking, drivers/... |
386 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
eb4400e3a dca: redesign loc... |
387 |
|
7589670f3 DCA: Add Direct C... |
388 389 |
blocking_notifier_call_chain(&dca_provider_chain, DCA_PROVIDER_ADD, NULL); |
a1741e7fc locking, drivers/... |
390 |
kfree(newdomain); |
7589670f3 DCA: Add Direct C... |
391 392 393 394 395 396 397 398 |
return 0; } EXPORT_SYMBOL_GPL(register_dca_provider); /** * unregister_dca_provider - remove a dca provider * @dca - struct created by alloc_dca_provider() */ |
1a5aeeecd dca: registering ... |
399 |
void unregister_dca_provider(struct dca_provider *dca, struct device *dev) |
7589670f3 DCA: Add Direct C... |
400 |
{ |
eb4400e3a dca: redesign loc... |
401 |
unsigned long flags; |
1a5aeeecd dca: registering ... |
402 403 |
struct pci_bus *pci_rc; struct dca_domain *domain; |
eb4400e3a dca: redesign loc... |
404 |
|
7589670f3 DCA: Add Direct C... |
405 406 |
blocking_notifier_call_chain(&dca_provider_chain, DCA_PROVIDER_REMOVE, NULL); |
eb4400e3a dca: redesign loc... |
407 |
|
a1741e7fc locking, drivers/... |
408 |
raw_spin_lock_irqsave(&dca_lock, flags); |
1a5aeeecd dca: registering ... |
409 |
|
7f1b358a2 I/OAT: I/OAT vers... |
410 |
list_del(&dca->node); |
1a5aeeecd dca: registering ... |
411 412 413 414 415 |
pci_rc = dca_pci_rc_from_dev(dev); domain = dca_find_domain(pci_rc); if (list_empty(&domain->dca_providers)) dca_free_domain(domain); |
a1741e7fc locking, drivers/... |
416 |
raw_spin_unlock_irqrestore(&dca_lock, flags); |
eb4400e3a dca: redesign loc... |
417 |
|
7589670f3 DCA: Add Direct C... |
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
dca_sysfs_remove_provider(dca); } EXPORT_SYMBOL_GPL(unregister_dca_provider); /** * dca_register_notify - register a client's notifier callback */ void dca_register_notify(struct notifier_block *nb) { blocking_notifier_chain_register(&dca_provider_chain, nb); } EXPORT_SYMBOL_GPL(dca_register_notify); /** * dca_unregister_notify - remove a client's notifier callback */ void dca_unregister_notify(struct notifier_block *nb) { blocking_notifier_chain_unregister(&dca_provider_chain, nb); } EXPORT_SYMBOL_GPL(dca_unregister_notify); static int __init dca_init(void) { |
084dac53a dca: module load ... |
442 443 |
pr_info("dca service started, version %s ", DCA_VERSION); |
7589670f3 DCA: Add Direct C... |
444 445 446 447 448 449 450 |
return dca_sysfs_init(); } static void __exit dca_exit(void) { dca_sysfs_exit(); } |
652afc27b dmaengine: bump i... |
451 |
arch_initcall(dca_init); |
7589670f3 DCA: Add Direct C... |
452 |
module_exit(dca_exit); |