Skip to content

Commit

Permalink
dca: registering requesters in multiple dca domains
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Maciej Sosnowski <[email protected]>
  • Loading branch information
Maciej Sosnowski authored and djbw committed Sep 10, 2009
1 parent 9a8de63 commit 1a5aeee
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 15 deletions.
122 changes: 109 additions & 13 deletions drivers/dca/dca-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,100 @@
#include <linux/device.h>
#include <linux/dca.h>

#define DCA_VERSION "1.8"
#define DCA_VERSION "1.12.1"

MODULE_VERSION(DCA_VERSION);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Intel Corporation");

static DEFINE_SPINLOCK(dca_lock);

static LIST_HEAD(dca_providers);
static LIST_HEAD(dca_domains);

static struct dca_provider *dca_find_provider_by_dev(struct device *dev)
static struct pci_bus *dca_pci_rc_from_dev(struct device *dev)
{
struct dca_provider *dca, *ret = NULL;
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_bus *bus = pdev->bus;

list_for_each_entry(dca, &dca_providers, node) {
if ((!dev) || (dca->ops->dev_managed(dca, dev))) {
ret = dca;
break;
}
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);
}

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) {
domain = dca_allocate_domain(rc);
if (domain)
list_add(&domain->node, &dca_domains);
}

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;
}

return ret;
list_for_each_entry(dca, &domain->dca_providers, node)
if ((!dev) || (dca->ops->dev_managed(dca, dev)))
return dca;

return NULL;
}

/**
Expand All @@ -61,6 +133,8 @@ int dca_add_requester(struct device *dev)
struct dca_provider *dca;
int err, slot = -ENODEV;
unsigned long flags;
struct pci_bus *pci_rc;
struct dca_domain *domain;

if (!dev)
return -EFAULT;
Expand All @@ -74,7 +148,14 @@ int dca_add_requester(struct device *dev)
return -EEXIST;
}

list_for_each_entry(dca, &dca_providers, node) {
pci_rc = dca_pci_rc_from_dev(dev);
domain = dca_find_domain(pci_rc);
if (!domain) {
spin_unlock_irqrestore(&dca_lock, flags);
return -ENODEV;
}

list_for_each_entry(dca, &domain->dca_providers, node) {
slot = dca->ops->add_requester(dca, dev);
if (slot >= 0)
break;
Expand Down Expand Up @@ -222,13 +303,19 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev)
{
int err;
unsigned long flags;
struct dca_domain *domain;

err = dca_sysfs_add_provider(dca, dev);
if (err)
return err;

spin_lock_irqsave(&dca_lock, flags);
list_add(&dca->node, &dca_providers);
domain = dca_get_domain(dev);
if (!domain) {
spin_unlock_irqrestore(&dca_lock, flags);
return -ENODEV;
}
list_add(&dca->node, &domain->dca_providers);
spin_unlock_irqrestore(&dca_lock, flags);

blocking_notifier_call_chain(&dca_provider_chain,
Expand All @@ -241,15 +328,24 @@ EXPORT_SYMBOL_GPL(register_dca_provider);
* unregister_dca_provider - remove a dca provider
* @dca - struct created by alloc_dca_provider()
*/
void unregister_dca_provider(struct dca_provider *dca)
void unregister_dca_provider(struct dca_provider *dca, struct device *dev)
{
unsigned long flags;
struct pci_bus *pci_rc;
struct dca_domain *domain;

blocking_notifier_call_chain(&dca_provider_chain,
DCA_PROVIDER_REMOVE, NULL);

spin_lock_irqsave(&dca_lock, flags);

list_del(&dca->node);

pci_rc = dca_pci_rc_from_dev(dev);
domain = dca_find_domain(pci_rc);
if (list_empty(&domain->dca_providers))
dca_free_domain(domain);

spin_unlock_irqrestore(&dca_lock, flags);

dca_sysfs_remove_provider(dca);
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/ioat/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static void __devexit ioat_remove(struct pci_dev *pdev)

dev_err(&pdev->dev, "Removing dma and dca services\n");
if (device->dca) {
unregister_dca_provider(device->dca);
unregister_dca_provider(device->dca, &pdev->dev);
free_dca_provider(device->dca);
device->dca = NULL;
}
Expand Down
11 changes: 10 additions & 1 deletion include/linux/dca.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
*/
#ifndef DCA_H
#define DCA_H

#include <linux/pci.h>

/* DCA Provider API */

/* DCA Notifier Interface */
Expand All @@ -36,6 +39,12 @@ struct dca_provider {
int id;
};

struct dca_domain {
struct list_head node;
struct list_head dca_providers;
struct pci_bus *pci_rc;
};

struct dca_ops {
int (*add_requester) (struct dca_provider *, struct device *);
int (*remove_requester) (struct dca_provider *, struct device *);
Expand All @@ -47,7 +56,7 @@ struct dca_ops {
struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size);
void free_dca_provider(struct dca_provider *dca);
int register_dca_provider(struct dca_provider *dca, struct device *dev);
void unregister_dca_provider(struct dca_provider *dca);
void unregister_dca_provider(struct dca_provider *dca, struct device *dev);

static inline void *dca_priv(struct dca_provider *dca)
{
Expand Down

0 comments on commit 1a5aeee

Please sign in to comment.