Commit 1a5aeeecd550ee4344cfba1791f1134739b16dc6

Authored by Maciej Sosnowski
Committed by Dan Williams
1 parent 9a8de639f3

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>

Showing 3 changed files with 120 additions and 15 deletions Side-by-side Diff

drivers/dca/dca-core.c
... ... @@ -28,7 +28,7 @@
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");
35 35  
36 36  
37 37  
38 38  
... ... @@ -36,20 +36,92 @@
36 36  
37 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 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 +}
  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 /**
... ... @@ -61,6 +133,8 @@
61 133 struct dca_provider *dca;
62 134 int err, slot = -ENODEV;
63 135 unsigned long flags;
  136 + struct pci_bus *pci_rc;
  137 + struct dca_domain *domain;
64 138  
65 139 if (!dev)
66 140 return -EFAULT;
... ... @@ -74,7 +148,14 @@
74 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 159 slot = dca->ops->add_requester(dca, dev);
79 160 if (slot >= 0)
80 161 break;
81 162  
... ... @@ -222,13 +303,19 @@
222 303 {
223 304 int err;
224 305 unsigned long flags;
  306 + struct dca_domain *domain;
225 307  
226 308 err = dca_sysfs_add_provider(dca, dev);
227 309 if (err)
228 310 return err;
229 311  
230 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 319 spin_unlock_irqrestore(&dca_lock, flags);
233 320  
234 321 blocking_notifier_call_chain(&dca_provider_chain,
235 322  
236 323  
237 324  
... ... @@ -241,15 +328,24 @@
241 328 * unregister_dca_provider - remove a dca provider
242 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 333 unsigned long flags;
  334 + struct pci_bus *pci_rc;
  335 + struct dca_domain *domain;
247 336  
248 337 blocking_notifier_call_chain(&dca_provider_chain,
249 338 DCA_PROVIDER_REMOVE, NULL);
250 339  
251 340 spin_lock_irqsave(&dca_lock, flags);
  341 +
252 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 349 spin_unlock_irqrestore(&dca_lock, flags);
254 350  
255 351 dca_sysfs_remove_provider(dca);
drivers/dma/ioat/pci.c
... ... @@ -175,7 +175,7 @@
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 }
... ... @@ -20,6 +20,9 @@
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 */
... ... @@ -36,6 +39,12 @@
36 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 48 struct dca_ops {
40 49 int (*add_requester) (struct dca_provider *, struct device *);
41 50 int (*remove_requester) (struct dca_provider *, struct device *);
... ... @@ -47,7 +56,7 @@
47 56 struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size);
48 57 void free_dca_provider(struct dca_provider *dca);
49 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 61 static inline void *dca_priv(struct dca_provider *dca)
53 62 {