Skip to content

Commit

Permalink
I/OAT: I/OAT version 3.0 support
Browse files Browse the repository at this point in the history
This patch adds to ioatdma and dca modules
support for Intel I/OAT DMA engine ver.3 (aka CB3 device).
The main features of I/OAT ver.3 are:
 * 8 single channel DMA devices (8 channels total)
 * 8 DCA providers, each can accept 2 requesters
 * 8-bit TAG values and 32-bit extended APIC IDs

Signed-off-by: Maciej Sosnowski <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
Maciej Sosnowski authored and djbw committed Jul 23, 2008
1 parent 16a37ac commit 7f1b358
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 49 deletions.
131 changes: 103 additions & 28 deletions drivers/dca/dca-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,69 @@
#include <linux/device.h>
#include <linux/dca.h>

MODULE_LICENSE("GPL");
#define DCA_VERSION "1.4"

/* For now we're assuming a single, global, DCA provider for the system. */
MODULE_VERSION(DCA_VERSION);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Intel Corporation");

static DEFINE_SPINLOCK(dca_lock);

static struct dca_provider *global_dca = NULL;
static LIST_HEAD(dca_providers);

static struct dca_provider *dca_find_provider_by_dev(struct device *dev)
{
struct dca_provider *dca, *ret = NULL;

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

return ret;
}

/**
* dca_add_requester - add a dca client to the list
* @dev - the device that wants dca service
*/
int dca_add_requester(struct device *dev)
{
int err, slot;
struct dca_provider *dca;
int err, slot = -ENODEV;

if (!global_dca)
return -ENODEV;
if (!dev)
return -EFAULT;

spin_lock(&dca_lock);
slot = global_dca->ops->add_requester(global_dca, dev);
spin_unlock(&dca_lock);
if (slot < 0)

/* check if the requester has not been added already */
dca = dca_find_provider_by_dev(dev);
if (dca) {
spin_unlock(&dca_lock);
return -EEXIST;
}

list_for_each_entry(dca, &dca_providers, node) {
slot = dca->ops->add_requester(dca, dev);
if (slot >= 0)
break;
}
if (slot < 0) {
spin_unlock(&dca_lock);
return slot;
}

err = dca_sysfs_add_req(global_dca, dev, slot);
err = dca_sysfs_add_req(dca, dev, slot);
if (err) {
spin_lock(&dca_lock);
global_dca->ops->remove_requester(global_dca, dev);
dca->ops->remove_requester(dca, dev);
spin_unlock(&dca_lock);
return err;
}

spin_unlock(&dca_lock);
return 0;
}
EXPORT_SYMBOL_GPL(dca_add_requester);
Expand All @@ -71,30 +101,78 @@ EXPORT_SYMBOL_GPL(dca_add_requester);
*/
int dca_remove_requester(struct device *dev)
{
struct dca_provider *dca;
int slot;
if (!global_dca)
return -ENODEV;

if (!dev)
return -EFAULT;

spin_lock(&dca_lock);
slot = global_dca->ops->remove_requester(global_dca, dev);
spin_unlock(&dca_lock);
if (slot < 0)
dca = dca_find_provider_by_dev(dev);
if (!dca) {
spin_unlock(&dca_lock);
return -ENODEV;
}
slot = dca->ops->remove_requester(dca, dev);
if (slot < 0) {
spin_unlock(&dca_lock);
return slot;
}

dca_sysfs_remove_req(global_dca, slot);
dca_sysfs_remove_req(dca, slot);

spin_unlock(&dca_lock);
return 0;
}
EXPORT_SYMBOL_GPL(dca_remove_requester);

/**
* dca_get_tag - return the dca tag for the given cpu
* dca_common_get_tag - return the dca tag (serves both new and old api)
* @dev - the device that wants dca service
* @cpu - the cpuid as returned by get_cpu()
*/
u8 dca_get_tag(int cpu)
u8 dca_common_get_tag(struct device *dev, int cpu)
{
if (!global_dca)
struct dca_provider *dca;
u8 tag;

spin_lock(&dca_lock);

dca = dca_find_provider_by_dev(dev);
if (!dca) {
spin_unlock(&dca_lock);
return -ENODEV;
return global_dca->ops->get_tag(global_dca, cpu);
}
tag = dca->ops->get_tag(dca, dev, cpu);

spin_unlock(&dca_lock);
return tag;
}

/**
* dca3_get_tag - return the dca tag to the requester device
* for the given cpu (new api)
* @dev - the device that wants dca service
* @cpu - the cpuid as returned by get_cpu()
*/
u8 dca3_get_tag(struct device *dev, int cpu)
{
if (!dev)
return -EFAULT;

return dca_common_get_tag(dev, cpu);
}
EXPORT_SYMBOL_GPL(dca3_get_tag);

/**
* dca_get_tag - return the dca tag for the given cpu (old api)
* @cpu - the cpuid as returned by get_cpu()
*/
u8 dca_get_tag(int cpu)
{
struct device *dev = NULL;

return dca_common_get_tag(dev, cpu);
}
EXPORT_SYMBOL_GPL(dca_get_tag);

Expand Down Expand Up @@ -140,12 +218,10 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev)
{
int err;

if (global_dca)
return -EEXIST;
err = dca_sysfs_add_provider(dca, dev);
if (err)
return err;
global_dca = dca;
list_add(&dca->node, &dca_providers);
blocking_notifier_call_chain(&dca_provider_chain,
DCA_PROVIDER_ADD, NULL);
return 0;
Expand All @@ -158,11 +234,9 @@ EXPORT_SYMBOL_GPL(register_dca_provider);
*/
void unregister_dca_provider(struct dca_provider *dca)
{
if (!global_dca)
return;
blocking_notifier_call_chain(&dca_provider_chain,
DCA_PROVIDER_REMOVE, NULL);
global_dca = NULL;
list_del(&dca->node);
dca_sysfs_remove_provider(dca);
}
EXPORT_SYMBOL_GPL(unregister_dca_provider);
Expand All @@ -187,6 +261,7 @@ EXPORT_SYMBOL_GPL(dca_unregister_notify);

static int __init dca_init(void)
{
printk(KERN_ERR "dca service started, version %s\n", DCA_VERSION);
return dca_sysfs_init();
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/dca/dca-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ static spinlock_t dca_idr_lock;
int dca_sysfs_add_req(struct dca_provider *dca, struct device *dev, int slot)
{
struct device *cd;
static int req_count;

cd = device_create(dca_class, dca->cd, MKDEV(0, slot + 1),
"requester%d", slot);
"requester%d", req_count++);
if (IS_ERR(cd))
return PTR_ERR(cd);
return 0;
Expand Down
15 changes: 15 additions & 0 deletions drivers/dma/ioat.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ static struct pci_device_id ioat_pci_tbl[] = {

/* I/OAT v2 platforms */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB) },

/* I/OAT v3 platforms */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG4) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG6) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG7) },
{ 0, }
};

Expand Down Expand Up @@ -83,6 +93,11 @@ static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase)
if (device->dma && ioat_dca_enabled)
device->dca = ioat2_dca_init(pdev, iobase);
break;
case IOAT_VER_3_0:
device->dma = ioat_dma_probe(pdev, iobase);
if (device->dma && ioat_dca_enabled)
device->dca = ioat3_dca_init(pdev, iobase);
break;
default:
err = -ENODEV;
break;
Expand Down
Loading

0 comments on commit 7f1b358

Please sign in to comment.