Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dca: registering requesters in multiple dca domains

This patch enables DCA support on multiple-IOH/multiple-IIO architectures.
It modifies dca module by replacing single dca_providers list
with dca_domains list, each domain containing separate list of providers.
This approach lets dca driver manage multiple domains, i.e. sets of providers
and requesters mapped back to the same PCI root complex device.
The driver takes care to register each requester to a provider
from the same domain.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com>

authored by

Maciej Sosnowski and committed by
Dan Williams
1a5aeeec 9a8de639

+119 -14
+108 -12
drivers/dca/dca-core.c
··· 28 28 #include <linux/device.h> 29 29 #include <linux/dca.h> 30 30 31 - #define DCA_VERSION "1.8" 31 + #define DCA_VERSION "1.12.1" 32 32 33 33 MODULE_VERSION(DCA_VERSION); 34 34 MODULE_LICENSE("GPL"); ··· 36 36 37 37 static DEFINE_SPINLOCK(dca_lock); 38 38 39 - static LIST_HEAD(dca_providers); 39 + static LIST_HEAD(dca_domains); 40 + 41 + static struct pci_bus *dca_pci_rc_from_dev(struct device *dev) 42 + { 43 + struct pci_dev *pdev = to_pci_dev(dev); 44 + struct pci_bus *bus = pdev->bus; 45 + 46 + while (bus->parent) 47 + bus = bus->parent; 48 + 49 + return bus; 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 + } 40 99 41 100 static struct dca_provider *dca_find_provider_by_dev(struct device *dev) 42 101 { 43 - struct dca_provider *dca, *ret = NULL; 102 + struct dca_provider *dca; 103 + struct pci_bus *rc; 104 + struct dca_domain *domain; 44 105 45 - list_for_each_entry(dca, &dca_providers, node) { 46 - if ((!dev) || (dca->ops->dev_managed(dca, dev))) { 47 - ret = dca; 48 - break; 49 - } 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 /** ··· 133 61 struct dca_provider *dca; 134 62 int err, slot = -ENODEV; 135 63 unsigned long flags; 64 + struct pci_bus *pci_rc; 65 + struct dca_domain *domain; 136 66 137 67 if (!dev) 138 68 return -EFAULT; ··· 148 74 return -EEXIST; 149 75 } 150 76 151 - list_for_each_entry(dca, &dca_providers, node) { 77 + pci_rc = dca_pci_rc_from_dev(dev); 78 + domain = dca_find_domain(pci_rc); 79 + if (!domain) { 80 + spin_unlock_irqrestore(&dca_lock, flags); 81 + return -ENODEV; 82 + } 83 + 84 + list_for_each_entry(dca, &domain->dca_providers, node) { 152 85 slot = dca->ops->add_requester(dca, dev); 153 86 if (slot >= 0) 154 87 break; ··· 303 222 { 304 223 int err; 305 224 unsigned long flags; 225 + struct dca_domain *domain; 306 226 307 227 err = dca_sysfs_add_provider(dca, dev); 308 228 if (err) 309 229 return err; 310 230 311 231 spin_lock_irqsave(&dca_lock, flags); 312 - list_add(&dca->node, &dca_providers); 232 + domain = dca_get_domain(dev); 233 + if (!domain) { 234 + spin_unlock_irqrestore(&dca_lock, flags); 235 + return -ENODEV; 236 + } 237 + list_add(&dca->node, &domain->dca_providers); 313 238 spin_unlock_irqrestore(&dca_lock, flags); 314 239 315 240 blocking_notifier_call_chain(&dca_provider_chain, ··· 328 241 * unregister_dca_provider - remove a dca provider 329 242 * @dca - struct created by alloc_dca_provider() 330 243 */ 331 - void unregister_dca_provider(struct dca_provider *dca) 244 + void unregister_dca_provider(struct dca_provider *dca, struct device *dev) 332 245 { 333 246 unsigned long flags; 247 + struct pci_bus *pci_rc; 248 + struct dca_domain *domain; 334 249 335 250 blocking_notifier_call_chain(&dca_provider_chain, 336 251 DCA_PROVIDER_REMOVE, NULL); 337 252 338 253 spin_lock_irqsave(&dca_lock, flags); 254 + 339 255 list_del(&dca->node); 256 + 257 + pci_rc = dca_pci_rc_from_dev(dev); 258 + domain = dca_find_domain(pci_rc); 259 + if (list_empty(&domain->dca_providers)) 260 + dca_free_domain(domain); 261 + 340 262 spin_unlock_irqrestore(&dca_lock, flags); 341 263 342 264 dca_sysfs_remove_provider(dca);
+1 -1
drivers/dma/ioat/pci.c
··· 175 175 176 176 dev_err(&pdev->dev, "Removing dma and dca services\n"); 177 177 if (device->dca) { 178 - unregister_dca_provider(device->dca); 178 + unregister_dca_provider(device->dca, &pdev->dev); 179 179 free_dca_provider(device->dca); 180 180 device->dca = NULL; 181 181 }
+10 -1
include/linux/dca.h
··· 20 20 */ 21 21 #ifndef DCA_H 22 22 #define DCA_H 23 + 24 + #include <linux/pci.h> 25 + 23 26 /* DCA Provider API */ 24 27 25 28 /* DCA Notifier Interface */ ··· 39 36 int id; 40 37 }; 41 38 39 + struct dca_domain { 40 + struct list_head node; 41 + struct list_head dca_providers; 42 + struct pci_bus *pci_rc; 43 + }; 44 + 42 45 struct dca_ops { 43 46 int (*add_requester) (struct dca_provider *, struct device *); 44 47 int (*remove_requester) (struct dca_provider *, struct device *); ··· 56 47 struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size); 57 48 void free_dca_provider(struct dca_provider *dca); 58 49 int register_dca_provider(struct dca_provider *dca, struct device *dev); 59 - void unregister_dca_provider(struct dca_provider *dca); 50 + void unregister_dca_provider(struct dca_provider *dca, struct device *dev); 60 51 61 52 static inline void *dca_priv(struct dca_provider *dca) 62 53 {