0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/notifier.h>
0012 #include <linux/device.h>
0013 #include <linux/dca.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016
0017 #define DCA_VERSION "1.12.1"
0018
0019 MODULE_VERSION(DCA_VERSION);
0020 MODULE_LICENSE("GPL");
0021 MODULE_AUTHOR("Intel Corporation");
0022
0023 static DEFINE_RAW_SPINLOCK(dca_lock);
0024
0025 static LIST_HEAD(dca_domains);
0026
0027 static BLOCKING_NOTIFIER_HEAD(dca_provider_chain);
0028
0029 static int dca_providers_blocked;
0030
0031 static struct pci_bus *dca_pci_rc_from_dev(struct device *dev)
0032 {
0033 struct pci_dev *pdev = to_pci_dev(dev);
0034 struct pci_bus *bus = pdev->bus;
0035
0036 while (bus->parent)
0037 bus = bus->parent;
0038
0039 return bus;
0040 }
0041
0042 static struct dca_domain *dca_allocate_domain(struct pci_bus *rc)
0043 {
0044 struct dca_domain *domain;
0045
0046 domain = kzalloc(sizeof(*domain), GFP_NOWAIT);
0047 if (!domain)
0048 return NULL;
0049
0050 INIT_LIST_HEAD(&domain->dca_providers);
0051 domain->pci_rc = rc;
0052
0053 return domain;
0054 }
0055
0056 static void dca_free_domain(struct dca_domain *domain)
0057 {
0058 list_del(&domain->node);
0059 kfree(domain);
0060 }
0061
0062 static int dca_provider_ioat_ver_3_0(struct device *dev)
0063 {
0064 struct pci_dev *pdev = to_pci_dev(dev);
0065
0066 return ((pdev->vendor == PCI_VENDOR_ID_INTEL) &&
0067 ((pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG0) ||
0068 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG1) ||
0069 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG2) ||
0070 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG3) ||
0071 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG4) ||
0072 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG5) ||
0073 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG6) ||
0074 (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG7)));
0075 }
0076
0077 static void unregister_dca_providers(void)
0078 {
0079 struct dca_provider *dca, *_dca;
0080 struct list_head unregistered_providers;
0081 struct dca_domain *domain;
0082 unsigned long flags;
0083
0084 blocking_notifier_call_chain(&dca_provider_chain,
0085 DCA_PROVIDER_REMOVE, NULL);
0086
0087 INIT_LIST_HEAD(&unregistered_providers);
0088
0089 raw_spin_lock_irqsave(&dca_lock, flags);
0090
0091 if (list_empty(&dca_domains)) {
0092 raw_spin_unlock_irqrestore(&dca_lock, flags);
0093 return;
0094 }
0095
0096
0097 domain = list_first_entry(&dca_domains, struct dca_domain, node);
0098
0099 list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node)
0100 list_move(&dca->node, &unregistered_providers);
0101
0102 dca_free_domain(domain);
0103
0104 raw_spin_unlock_irqrestore(&dca_lock, flags);
0105
0106 list_for_each_entry_safe(dca, _dca, &unregistered_providers, node) {
0107 dca_sysfs_remove_provider(dca);
0108 list_del(&dca->node);
0109 }
0110 }
0111
0112 static struct dca_domain *dca_find_domain(struct pci_bus *rc)
0113 {
0114 struct dca_domain *domain;
0115
0116 list_for_each_entry(domain, &dca_domains, node)
0117 if (domain->pci_rc == rc)
0118 return domain;
0119
0120 return NULL;
0121 }
0122
0123 static struct dca_domain *dca_get_domain(struct device *dev)
0124 {
0125 struct pci_bus *rc;
0126 struct dca_domain *domain;
0127
0128 rc = dca_pci_rc_from_dev(dev);
0129 domain = dca_find_domain(rc);
0130
0131 if (!domain) {
0132 if (dca_provider_ioat_ver_3_0(dev) && !list_empty(&dca_domains))
0133 dca_providers_blocked = 1;
0134 }
0135
0136 return domain;
0137 }
0138
0139 static struct dca_provider *dca_find_provider_by_dev(struct device *dev)
0140 {
0141 struct dca_provider *dca;
0142 struct pci_bus *rc;
0143 struct dca_domain *domain;
0144
0145 if (dev) {
0146 rc = dca_pci_rc_from_dev(dev);
0147 domain = dca_find_domain(rc);
0148 if (!domain)
0149 return NULL;
0150 } else {
0151 if (!list_empty(&dca_domains))
0152 domain = list_first_entry(&dca_domains,
0153 struct dca_domain,
0154 node);
0155 else
0156 return NULL;
0157 }
0158
0159 list_for_each_entry(dca, &domain->dca_providers, node)
0160 if ((!dev) || (dca->ops->dev_managed(dca, dev)))
0161 return dca;
0162
0163 return NULL;
0164 }
0165
0166
0167
0168
0169
0170 int dca_add_requester(struct device *dev)
0171 {
0172 struct dca_provider *dca;
0173 int err, slot = -ENODEV;
0174 unsigned long flags;
0175 struct pci_bus *pci_rc;
0176 struct dca_domain *domain;
0177
0178 if (!dev)
0179 return -EFAULT;
0180
0181 raw_spin_lock_irqsave(&dca_lock, flags);
0182
0183
0184 dca = dca_find_provider_by_dev(dev);
0185 if (dca) {
0186 raw_spin_unlock_irqrestore(&dca_lock, flags);
0187 return -EEXIST;
0188 }
0189
0190 pci_rc = dca_pci_rc_from_dev(dev);
0191 domain = dca_find_domain(pci_rc);
0192 if (!domain) {
0193 raw_spin_unlock_irqrestore(&dca_lock, flags);
0194 return -ENODEV;
0195 }
0196
0197 list_for_each_entry(dca, &domain->dca_providers, node) {
0198 slot = dca->ops->add_requester(dca, dev);
0199 if (slot >= 0)
0200 break;
0201 }
0202
0203 raw_spin_unlock_irqrestore(&dca_lock, flags);
0204
0205 if (slot < 0)
0206 return slot;
0207
0208 err = dca_sysfs_add_req(dca, dev, slot);
0209 if (err) {
0210 raw_spin_lock_irqsave(&dca_lock, flags);
0211 if (dca == dca_find_provider_by_dev(dev))
0212 dca->ops->remove_requester(dca, dev);
0213 raw_spin_unlock_irqrestore(&dca_lock, flags);
0214 return err;
0215 }
0216
0217 return 0;
0218 }
0219 EXPORT_SYMBOL_GPL(dca_add_requester);
0220
0221
0222
0223
0224
0225 int dca_remove_requester(struct device *dev)
0226 {
0227 struct dca_provider *dca;
0228 int slot;
0229 unsigned long flags;
0230
0231 if (!dev)
0232 return -EFAULT;
0233
0234 raw_spin_lock_irqsave(&dca_lock, flags);
0235 dca = dca_find_provider_by_dev(dev);
0236 if (!dca) {
0237 raw_spin_unlock_irqrestore(&dca_lock, flags);
0238 return -ENODEV;
0239 }
0240 slot = dca->ops->remove_requester(dca, dev);
0241 raw_spin_unlock_irqrestore(&dca_lock, flags);
0242
0243 if (slot < 0)
0244 return slot;
0245
0246 dca_sysfs_remove_req(dca, slot);
0247
0248 return 0;
0249 }
0250 EXPORT_SYMBOL_GPL(dca_remove_requester);
0251
0252
0253
0254
0255
0256
0257 static u8 dca_common_get_tag(struct device *dev, int cpu)
0258 {
0259 struct dca_provider *dca;
0260 u8 tag;
0261 unsigned long flags;
0262
0263 raw_spin_lock_irqsave(&dca_lock, flags);
0264
0265 dca = dca_find_provider_by_dev(dev);
0266 if (!dca) {
0267 raw_spin_unlock_irqrestore(&dca_lock, flags);
0268 return -ENODEV;
0269 }
0270 tag = dca->ops->get_tag(dca, dev, cpu);
0271
0272 raw_spin_unlock_irqrestore(&dca_lock, flags);
0273 return tag;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282 u8 dca3_get_tag(struct device *dev, int cpu)
0283 {
0284 if (!dev)
0285 return -EFAULT;
0286
0287 return dca_common_get_tag(dev, cpu);
0288 }
0289 EXPORT_SYMBOL_GPL(dca3_get_tag);
0290
0291
0292
0293
0294
0295 u8 dca_get_tag(int cpu)
0296 {
0297 struct device *dev = NULL;
0298
0299 return dca_common_get_tag(dev, cpu);
0300 }
0301 EXPORT_SYMBOL_GPL(dca_get_tag);
0302
0303
0304
0305
0306
0307
0308 struct dca_provider *alloc_dca_provider(const struct dca_ops *ops,
0309 int priv_size)
0310 {
0311 struct dca_provider *dca;
0312 int alloc_size;
0313
0314 alloc_size = (sizeof(*dca) + priv_size);
0315 dca = kzalloc(alloc_size, GFP_KERNEL);
0316 if (!dca)
0317 return NULL;
0318 dca->ops = ops;
0319
0320 return dca;
0321 }
0322 EXPORT_SYMBOL_GPL(alloc_dca_provider);
0323
0324
0325
0326
0327
0328
0329 void free_dca_provider(struct dca_provider *dca)
0330 {
0331 kfree(dca);
0332 }
0333 EXPORT_SYMBOL_GPL(free_dca_provider);
0334
0335
0336
0337
0338
0339
0340 int register_dca_provider(struct dca_provider *dca, struct device *dev)
0341 {
0342 int err;
0343 unsigned long flags;
0344 struct dca_domain *domain, *newdomain = NULL;
0345
0346 raw_spin_lock_irqsave(&dca_lock, flags);
0347 if (dca_providers_blocked) {
0348 raw_spin_unlock_irqrestore(&dca_lock, flags);
0349 return -ENODEV;
0350 }
0351 raw_spin_unlock_irqrestore(&dca_lock, flags);
0352
0353 err = dca_sysfs_add_provider(dca, dev);
0354 if (err)
0355 return err;
0356
0357 raw_spin_lock_irqsave(&dca_lock, flags);
0358 domain = dca_get_domain(dev);
0359 if (!domain) {
0360 struct pci_bus *rc;
0361
0362 if (dca_providers_blocked) {
0363 raw_spin_unlock_irqrestore(&dca_lock, flags);
0364 dca_sysfs_remove_provider(dca);
0365 unregister_dca_providers();
0366 return -ENODEV;
0367 }
0368
0369 raw_spin_unlock_irqrestore(&dca_lock, flags);
0370 rc = dca_pci_rc_from_dev(dev);
0371 newdomain = dca_allocate_domain(rc);
0372 if (!newdomain)
0373 return -ENODEV;
0374 raw_spin_lock_irqsave(&dca_lock, flags);
0375
0376 domain = dca_get_domain(dev);
0377 if (!domain) {
0378 domain = newdomain;
0379 newdomain = NULL;
0380 list_add(&domain->node, &dca_domains);
0381 }
0382 }
0383 list_add(&dca->node, &domain->dca_providers);
0384 raw_spin_unlock_irqrestore(&dca_lock, flags);
0385
0386 blocking_notifier_call_chain(&dca_provider_chain,
0387 DCA_PROVIDER_ADD, NULL);
0388 kfree(newdomain);
0389 return 0;
0390 }
0391 EXPORT_SYMBOL_GPL(register_dca_provider);
0392
0393
0394
0395
0396
0397 void unregister_dca_provider(struct dca_provider *dca, struct device *dev)
0398 {
0399 unsigned long flags;
0400 struct pci_bus *pci_rc;
0401 struct dca_domain *domain;
0402
0403 blocking_notifier_call_chain(&dca_provider_chain,
0404 DCA_PROVIDER_REMOVE, NULL);
0405
0406 raw_spin_lock_irqsave(&dca_lock, flags);
0407
0408 if (list_empty(&dca_domains)) {
0409 raw_spin_unlock_irqrestore(&dca_lock, flags);
0410 return;
0411 }
0412
0413 list_del(&dca->node);
0414
0415 pci_rc = dca_pci_rc_from_dev(dev);
0416 domain = dca_find_domain(pci_rc);
0417 if (list_empty(&domain->dca_providers))
0418 dca_free_domain(domain);
0419
0420 raw_spin_unlock_irqrestore(&dca_lock, flags);
0421
0422 dca_sysfs_remove_provider(dca);
0423 }
0424 EXPORT_SYMBOL_GPL(unregister_dca_provider);
0425
0426
0427
0428
0429 void dca_register_notify(struct notifier_block *nb)
0430 {
0431 blocking_notifier_chain_register(&dca_provider_chain, nb);
0432 }
0433 EXPORT_SYMBOL_GPL(dca_register_notify);
0434
0435
0436
0437
0438 void dca_unregister_notify(struct notifier_block *nb)
0439 {
0440 blocking_notifier_chain_unregister(&dca_provider_chain, nb);
0441 }
0442 EXPORT_SYMBOL_GPL(dca_unregister_notify);
0443
0444 static int __init dca_init(void)
0445 {
0446 pr_info("dca service started, version %s\n", DCA_VERSION);
0447 return dca_sysfs_init();
0448 }
0449
0450 static void __exit dca_exit(void)
0451 {
0452 dca_sysfs_exit();
0453 }
0454
0455 arch_initcall(dca_init);
0456 module_exit(dca_exit);
0457