Skip to content

Commit

Permalink
x86/PCI: Allow DMA ops specific to a PCI domain
Browse files Browse the repository at this point in the history
The Intel Volume Management Device (VMD) is a PCIe endpoint that acts as a
host bridge to another PCI domain.  When devices below the VMD perform DMA,
the VMD replaces their DMA source IDs with its own source ID.  Therefore,
those devices require special DMA ops.

Add interfaces to allow the VMD driver to set up dma_ops for the devices
below it.

[bhelgaas: remove "extern", add "static", changelog]
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  • Loading branch information
Keith Busch authored and Bjorn Helgaas committed Jan 15, 2016
1 parent 64bce3e commit d9c3d6f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
10 changes: 10 additions & 0 deletions arch/x86/include/asm/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ struct dev_archdata {
#endif
};

#if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
struct dma_domain {
struct list_head node;
struct dma_map_ops *dma_ops;
int domain_nr;
};
void add_dma_domain(struct dma_domain *domain);
void del_dma_domain(struct dma_domain *domain);
#endif

struct pdev_archdata {
};

Expand Down
38 changes: 38 additions & 0 deletions arch/x86/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,43 @@ unsigned int pcibios_assign_all_busses(void)
return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
}

#if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
static LIST_HEAD(dma_domain_list);
static DEFINE_SPINLOCK(dma_domain_list_lock);

void add_dma_domain(struct dma_domain *domain)
{
spin_lock(&dma_domain_list_lock);
list_add(&domain->node, &dma_domain_list);
spin_unlock(&dma_domain_list_lock);
}
EXPORT_SYMBOL_GPL(add_dma_domain);

void del_dma_domain(struct dma_domain *domain)
{
spin_lock(&dma_domain_list_lock);
list_del(&domain->node);
spin_unlock(&dma_domain_list_lock);
}
EXPORT_SYMBOL_GPL(del_dma_domain);

static void set_dma_domain_ops(struct pci_dev *pdev)
{
struct dma_domain *domain;

spin_lock(&dma_domain_list_lock);
list_for_each_entry(domain, &dma_domain_list, node) {
if (pci_domain_nr(pdev->bus) == domain->domain_nr) {
pdev->dev.archdata.dma_ops = domain->dma_ops;
break;
}
}
spin_unlock(&dma_domain_list_lock);
}
#else
static void set_dma_domain_ops(struct pci_dev *pdev) {}
#endif

int pcibios_add_device(struct pci_dev *dev)
{
struct setup_data *data;
Expand Down Expand Up @@ -670,6 +707,7 @@ int pcibios_add_device(struct pci_dev *dev)
pa_data = data->next;
iounmap(data);
}
set_dma_domain_ops(dev);
return 0;
}

Expand Down

0 comments on commit d9c3d6f

Please sign in to comment.