ioat: move to drivers/dma/ioat/
When first created the ioat driver was the only inhabitant of drivers/dma/. Now, it is the only multi-file (more than a .c and a .h) driver in the directory. Moving it to an ioat/ subdirectory allows the naming convention to be cleaned up, and allows for future splitting of the source files by hardware version (v1, v2, and v3). Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
2
drivers/dma/ioat/Makefile
Normal file
2
drivers/dma/ioat/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
|
||||
ioatdma-objs := pci.o dma.o dca.o
|
681
drivers/dma/ioat/dca.c
Normal file
681
drivers/dma/ioat/dca.c
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dca.h>
|
||||
|
||||
/* either a kernel change is needed, or we need something like this in kernel */
|
||||
#ifndef CONFIG_SMP
|
||||
#include <asm/smp.h>
|
||||
#undef cpu_physical_id
|
||||
#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24)
|
||||
#endif
|
||||
|
||||
#include "dma.h"
|
||||
#include "registers.h"
|
||||
|
||||
/*
|
||||
* Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6
|
||||
* contain the bit number of the APIC ID to map into the DCA tag. If the valid
|
||||
* bit is not set, then the value must be 0 or 1 and defines the bit in the tag.
|
||||
*/
|
||||
#define DCA_TAG_MAP_VALID 0x80
|
||||
|
||||
#define DCA3_TAG_MAP_BIT_TO_INV 0x80
|
||||
#define DCA3_TAG_MAP_BIT_TO_SEL 0x40
|
||||
#define DCA3_TAG_MAP_LITERAL_VAL 0x1
|
||||
|
||||
#define DCA_TAG_MAP_MASK 0xDF
|
||||
|
||||
/* expected tag map bytes for I/OAT ver.2 */
|
||||
#define DCA2_TAG_MAP_BYTE0 0x80
|
||||
#define DCA2_TAG_MAP_BYTE1 0x0
|
||||
#define DCA2_TAG_MAP_BYTE2 0x81
|
||||
#define DCA2_TAG_MAP_BYTE3 0x82
|
||||
#define DCA2_TAG_MAP_BYTE4 0x82
|
||||
|
||||
/* verify if tag map matches expected values */
|
||||
static inline int dca2_tag_map_valid(u8 *tag_map)
|
||||
{
|
||||
return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) &&
|
||||
(tag_map[1] == DCA2_TAG_MAP_BYTE1) &&
|
||||
(tag_map[2] == DCA2_TAG_MAP_BYTE2) &&
|
||||
(tag_map[3] == DCA2_TAG_MAP_BYTE3) &&
|
||||
(tag_map[4] == DCA2_TAG_MAP_BYTE4));
|
||||
}
|
||||
|
||||
/*
|
||||
* "Legacy" DCA systems do not implement the DCA register set in the
|
||||
* I/OAT device. Software needs direct support for their tag mappings.
|
||||
*/
|
||||
|
||||
#define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x))
|
||||
#define IOAT_TAG_MAP_LEN 8
|
||||
|
||||
static u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = {
|
||||
1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
|
||||
static u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = {
|
||||
1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
|
||||
static u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = {
|
||||
1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), };
|
||||
static u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 };
|
||||
|
||||
/* pack PCI B/D/F into a u16 */
|
||||
static inline u16 dcaid_from_pcidev(struct pci_dev *pci)
|
||||
{
|
||||
return (pci->bus->number << 8) | pci->devfn;
|
||||
}
|
||||
|
||||
static int dca_enabled_in_bios(struct pci_dev *pdev)
|
||||
{
|
||||
/* CPUID level 9 returns DCA configuration */
|
||||
/* Bit 0 indicates DCA enabled by the BIOS */
|
||||
unsigned long cpuid_level_9;
|
||||
int res;
|
||||
|
||||
cpuid_level_9 = cpuid_eax(9);
|
||||
res = test_bit(0, &cpuid_level_9);
|
||||
if (!res)
|
||||
dev_err(&pdev->dev, "DCA is disabled in BIOS\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int system_has_dca_enabled(struct pci_dev *pdev)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_DCA))
|
||||
return dca_enabled_in_bios(pdev);
|
||||
|
||||
dev_err(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ioat_dca_slot {
|
||||
struct pci_dev *pdev; /* requester device */
|
||||
u16 rid; /* requester id, as used by IOAT */
|
||||
};
|
||||
|
||||
#define IOAT_DCA_MAX_REQ 6
|
||||
#define IOAT3_DCA_MAX_REQ 2
|
||||
|
||||
struct ioat_dca_priv {
|
||||
void __iomem *iobase;
|
||||
void __iomem *dca_base;
|
||||
int max_requesters;
|
||||
int requester_count;
|
||||
u8 tag_map[IOAT_TAG_MAP_LEN];
|
||||
struct ioat_dca_slot req_slots[0];
|
||||
};
|
||||
|
||||
/* 5000 series chipset DCA Port Requester ID Table Entry Format
|
||||
* [15:8] PCI-Express Bus Number
|
||||
* [7:3] PCI-Express Device Number
|
||||
* [2:0] PCI-Express Function Number
|
||||
*
|
||||
* 5000 series chipset DCA control register format
|
||||
* [7:1] Reserved (0)
|
||||
* [0] Ignore Function Number
|
||||
*/
|
||||
|
||||
static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
u16 id;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
id = dcaid_from_pcidev(pdev);
|
||||
|
||||
if (ioatdca->requester_count == ioatdca->max_requesters)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == NULL) {
|
||||
/* found an empty slot */
|
||||
ioatdca->requester_count++;
|
||||
ioatdca->req_slots[i].pdev = pdev;
|
||||
ioatdca->req_slots[i].rid = id;
|
||||
writew(id, ioatdca->dca_base + (i * 4));
|
||||
/* make sure the ignore function bit is off */
|
||||
writeb(0, ioatdca->dca_base + (i * 4) + 2);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/* Error, ioatdma->requester_count is out of whack */
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int ioat_dca_remove_requester(struct dca_provider *dca,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == pdev) {
|
||||
writew(0, ioatdca->dca_base + (i * 4));
|
||||
ioatdca->req_slots[i].pdev = NULL;
|
||||
ioatdca->req_slots[i].rid = 0;
|
||||
ioatdca->requester_count--;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static u8 ioat_dca_get_tag(struct dca_provider *dca,
|
||||
struct device *dev,
|
||||
int cpu)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
int i, apic_id, bit, value;
|
||||
u8 entry, tag;
|
||||
|
||||
tag = 0;
|
||||
apic_id = cpu_physical_id(cpu);
|
||||
|
||||
for (i = 0; i < IOAT_TAG_MAP_LEN; i++) {
|
||||
entry = ioatdca->tag_map[i];
|
||||
if (entry & DCA_TAG_MAP_VALID) {
|
||||
bit = entry & ~DCA_TAG_MAP_VALID;
|
||||
value = (apic_id & (1 << bit)) ? 1 : 0;
|
||||
} else {
|
||||
value = entry ? 1 : 0;
|
||||
}
|
||||
tag |= (value << i);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
static int ioat_dca_dev_managed(struct dca_provider *dca,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == pdev)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dca_ops ioat_dca_ops = {
|
||||
.add_requester = ioat_dca_add_requester,
|
||||
.remove_requester = ioat_dca_remove_requester,
|
||||
.get_tag = ioat_dca_get_tag,
|
||||
.dev_managed = ioat_dca_dev_managed,
|
||||
};
|
||||
|
||||
|
||||
struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
|
||||
{
|
||||
struct dca_provider *dca;
|
||||
struct ioat_dca_priv *ioatdca;
|
||||
u8 *tag_map = NULL;
|
||||
int i;
|
||||
int err;
|
||||
u8 version;
|
||||
u8 max_requesters;
|
||||
|
||||
if (!system_has_dca_enabled(pdev))
|
||||
return NULL;
|
||||
|
||||
/* I/OAT v1 systems must have a known tag_map to support DCA */
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT:
|
||||
tag_map = ioat_tag_map_BNB;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_CNB:
|
||||
tag_map = ioat_tag_map_CNB;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SCNB:
|
||||
tag_map = ioat_tag_map_SCNB;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_UNISYS:
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR:
|
||||
tag_map = ioat_tag_map_UNISYS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (tag_map == NULL)
|
||||
return NULL;
|
||||
|
||||
version = readb(iobase + IOAT_VER_OFFSET);
|
||||
if (version == IOAT_VER_3_0)
|
||||
max_requesters = IOAT3_DCA_MAX_REQ;
|
||||
else
|
||||
max_requesters = IOAT_DCA_MAX_REQ;
|
||||
|
||||
dca = alloc_dca_provider(&ioat_dca_ops,
|
||||
sizeof(*ioatdca) +
|
||||
(sizeof(struct ioat_dca_slot) * max_requesters));
|
||||
if (!dca)
|
||||
return NULL;
|
||||
|
||||
ioatdca = dca_priv(dca);
|
||||
ioatdca->max_requesters = max_requesters;
|
||||
ioatdca->dca_base = iobase + 0x54;
|
||||
|
||||
/* copy over the APIC ID to DCA tag mapping */
|
||||
for (i = 0; i < IOAT_TAG_MAP_LEN; i++)
|
||||
ioatdca->tag_map[i] = tag_map[i];
|
||||
|
||||
err = register_dca_provider(dca, &pdev->dev);
|
||||
if (err) {
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dca;
|
||||
}
|
||||
|
||||
|
||||
static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
u16 id;
|
||||
u16 global_req_table;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
id = dcaid_from_pcidev(pdev);
|
||||
|
||||
if (ioatdca->requester_count == ioatdca->max_requesters)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == NULL) {
|
||||
/* found an empty slot */
|
||||
ioatdca->requester_count++;
|
||||
ioatdca->req_slots[i].pdev = pdev;
|
||||
ioatdca->req_slots[i].rid = id;
|
||||
global_req_table =
|
||||
readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
|
||||
writel(id | IOAT_DCA_GREQID_VALID,
|
||||
ioatdca->iobase + global_req_table + (i * 4));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/* Error, ioatdma->requester_count is out of whack */
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int ioat2_dca_remove_requester(struct dca_provider *dca,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
u16 global_req_table;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == pdev) {
|
||||
global_req_table =
|
||||
readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
|
||||
writel(0, ioatdca->iobase + global_req_table + (i * 4));
|
||||
ioatdca->req_slots[i].pdev = NULL;
|
||||
ioatdca->req_slots[i].rid = 0;
|
||||
ioatdca->requester_count--;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static u8 ioat2_dca_get_tag(struct dca_provider *dca,
|
||||
struct device *dev,
|
||||
int cpu)
|
||||
{
|
||||
u8 tag;
|
||||
|
||||
tag = ioat_dca_get_tag(dca, dev, cpu);
|
||||
tag = (~tag) & 0x1F;
|
||||
return tag;
|
||||
}
|
||||
|
||||
static struct dca_ops ioat2_dca_ops = {
|
||||
.add_requester = ioat2_dca_add_requester,
|
||||
.remove_requester = ioat2_dca_remove_requester,
|
||||
.get_tag = ioat2_dca_get_tag,
|
||||
.dev_managed = ioat_dca_dev_managed,
|
||||
};
|
||||
|
||||
static int ioat2_dca_count_dca_slots(void __iomem *iobase, u16 dca_offset)
|
||||
{
|
||||
int slots = 0;
|
||||
u32 req;
|
||||
u16 global_req_table;
|
||||
|
||||
global_req_table = readw(iobase + dca_offset + IOAT_DCA_GREQID_OFFSET);
|
||||
if (global_req_table == 0)
|
||||
return 0;
|
||||
do {
|
||||
req = readl(iobase + global_req_table + (slots * sizeof(u32)));
|
||||
slots++;
|
||||
} while ((req & IOAT_DCA_GREQID_LASTID) == 0);
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
|
||||
{
|
||||
struct dca_provider *dca;
|
||||
struct ioat_dca_priv *ioatdca;
|
||||
int slots;
|
||||
int i;
|
||||
int err;
|
||||
u32 tag_map;
|
||||
u16 dca_offset;
|
||||
u16 csi_fsb_control;
|
||||
u16 pcie_control;
|
||||
u8 bit;
|
||||
|
||||
if (!system_has_dca_enabled(pdev))
|
||||
return NULL;
|
||||
|
||||
dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET);
|
||||
if (dca_offset == 0)
|
||||
return NULL;
|
||||
|
||||
slots = ioat2_dca_count_dca_slots(iobase, dca_offset);
|
||||
if (slots == 0)
|
||||
return NULL;
|
||||
|
||||
dca = alloc_dca_provider(&ioat2_dca_ops,
|
||||
sizeof(*ioatdca)
|
||||
+ (sizeof(struct ioat_dca_slot) * slots));
|
||||
if (!dca)
|
||||
return NULL;
|
||||
|
||||
ioatdca = dca_priv(dca);
|
||||
ioatdca->iobase = iobase;
|
||||
ioatdca->dca_base = iobase + dca_offset;
|
||||
ioatdca->max_requesters = slots;
|
||||
|
||||
/* some bios might not know to turn these on */
|
||||
csi_fsb_control = readw(ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
|
||||
if ((csi_fsb_control & IOAT_FSB_CAP_ENABLE_PREFETCH) == 0) {
|
||||
csi_fsb_control |= IOAT_FSB_CAP_ENABLE_PREFETCH;
|
||||
writew(csi_fsb_control,
|
||||
ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
|
||||
}
|
||||
pcie_control = readw(ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
|
||||
if ((pcie_control & IOAT_PCI_CAP_ENABLE_MEMWR) == 0) {
|
||||
pcie_control |= IOAT_PCI_CAP_ENABLE_MEMWR;
|
||||
writew(pcie_control,
|
||||
ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
/* TODO version, compatibility and configuration checks */
|
||||
|
||||
/* copy out the APIC to DCA tag map */
|
||||
tag_map = readl(ioatdca->dca_base + IOAT_APICID_TAG_MAP_OFFSET);
|
||||
for (i = 0; i < 5; i++) {
|
||||
bit = (tag_map >> (4 * i)) & 0x0f;
|
||||
if (bit < 8)
|
||||
ioatdca->tag_map[i] = bit | DCA_TAG_MAP_VALID;
|
||||
else
|
||||
ioatdca->tag_map[i] = 0;
|
||||
}
|
||||
|
||||
if (!dca2_tag_map_valid(ioatdca->tag_map)) {
|
||||
dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, "
|
||||
"disabling DCA\n");
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = register_dca_provider(dca, &pdev->dev);
|
||||
if (err) {
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dca;
|
||||
}
|
||||
|
||||
static int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
u16 id;
|
||||
u16 global_req_table;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
id = dcaid_from_pcidev(pdev);
|
||||
|
||||
if (ioatdca->requester_count == ioatdca->max_requesters)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == NULL) {
|
||||
/* found an empty slot */
|
||||
ioatdca->requester_count++;
|
||||
ioatdca->req_slots[i].pdev = pdev;
|
||||
ioatdca->req_slots[i].rid = id;
|
||||
global_req_table =
|
||||
readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET);
|
||||
writel(id | IOAT_DCA_GREQID_VALID,
|
||||
ioatdca->iobase + global_req_table + (i * 4));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/* Error, ioatdma->requester_count is out of whack */
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int ioat3_dca_remove_requester(struct dca_provider *dca,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
u16 global_req_table;
|
||||
|
||||
/* This implementation only supports PCI-Express */
|
||||
if (dev->bus != &pci_bus_type)
|
||||
return -ENODEV;
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
for (i = 0; i < ioatdca->max_requesters; i++) {
|
||||
if (ioatdca->req_slots[i].pdev == pdev) {
|
||||
global_req_table =
|
||||
readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET);
|
||||
writel(0, ioatdca->iobase + global_req_table + (i * 4));
|
||||
ioatdca->req_slots[i].pdev = NULL;
|
||||
ioatdca->req_slots[i].rid = 0;
|
||||
ioatdca->requester_count--;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static u8 ioat3_dca_get_tag(struct dca_provider *dca,
|
||||
struct device *dev,
|
||||
int cpu)
|
||||
{
|
||||
u8 tag;
|
||||
|
||||
struct ioat_dca_priv *ioatdca = dca_priv(dca);
|
||||
int i, apic_id, bit, value;
|
||||
u8 entry;
|
||||
|
||||
tag = 0;
|
||||
apic_id = cpu_physical_id(cpu);
|
||||
|
||||
for (i = 0; i < IOAT_TAG_MAP_LEN; i++) {
|
||||
entry = ioatdca->tag_map[i];
|
||||
if (entry & DCA3_TAG_MAP_BIT_TO_SEL) {
|
||||
bit = entry &
|
||||
~(DCA3_TAG_MAP_BIT_TO_SEL | DCA3_TAG_MAP_BIT_TO_INV);
|
||||
value = (apic_id & (1 << bit)) ? 1 : 0;
|
||||
} else if (entry & DCA3_TAG_MAP_BIT_TO_INV) {
|
||||
bit = entry & ~DCA3_TAG_MAP_BIT_TO_INV;
|
||||
value = (apic_id & (1 << bit)) ? 0 : 1;
|
||||
} else {
|
||||
value = (entry & DCA3_TAG_MAP_LITERAL_VAL) ? 1 : 0;
|
||||
}
|
||||
tag |= (value << i);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
static struct dca_ops ioat3_dca_ops = {
|
||||
.add_requester = ioat3_dca_add_requester,
|
||||
.remove_requester = ioat3_dca_remove_requester,
|
||||
.get_tag = ioat3_dca_get_tag,
|
||||
.dev_managed = ioat_dca_dev_managed,
|
||||
};
|
||||
|
||||
static int ioat3_dca_count_dca_slots(void *iobase, u16 dca_offset)
|
||||
{
|
||||
int slots = 0;
|
||||
u32 req;
|
||||
u16 global_req_table;
|
||||
|
||||
global_req_table = readw(iobase + dca_offset + IOAT3_DCA_GREQID_OFFSET);
|
||||
if (global_req_table == 0)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
req = readl(iobase + global_req_table + (slots * sizeof(u32)));
|
||||
slots++;
|
||||
} while ((req & IOAT_DCA_GREQID_LASTID) == 0);
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
|
||||
{
|
||||
struct dca_provider *dca;
|
||||
struct ioat_dca_priv *ioatdca;
|
||||
int slots;
|
||||
int i;
|
||||
int err;
|
||||
u16 dca_offset;
|
||||
u16 csi_fsb_control;
|
||||
u16 pcie_control;
|
||||
u8 bit;
|
||||
|
||||
union {
|
||||
u64 full;
|
||||
struct {
|
||||
u32 low;
|
||||
u32 high;
|
||||
};
|
||||
} tag_map;
|
||||
|
||||
if (!system_has_dca_enabled(pdev))
|
||||
return NULL;
|
||||
|
||||
dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET);
|
||||
if (dca_offset == 0)
|
||||
return NULL;
|
||||
|
||||
slots = ioat3_dca_count_dca_slots(iobase, dca_offset);
|
||||
if (slots == 0)
|
||||
return NULL;
|
||||
|
||||
dca = alloc_dca_provider(&ioat3_dca_ops,
|
||||
sizeof(*ioatdca)
|
||||
+ (sizeof(struct ioat_dca_slot) * slots));
|
||||
if (!dca)
|
||||
return NULL;
|
||||
|
||||
ioatdca = dca_priv(dca);
|
||||
ioatdca->iobase = iobase;
|
||||
ioatdca->dca_base = iobase + dca_offset;
|
||||
ioatdca->max_requesters = slots;
|
||||
|
||||
/* some bios might not know to turn these on */
|
||||
csi_fsb_control = readw(ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET);
|
||||
if ((csi_fsb_control & IOAT3_CSI_CONTROL_PREFETCH) == 0) {
|
||||
csi_fsb_control |= IOAT3_CSI_CONTROL_PREFETCH;
|
||||
writew(csi_fsb_control,
|
||||
ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET);
|
||||
}
|
||||
pcie_control = readw(ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET);
|
||||
if ((pcie_control & IOAT3_PCI_CONTROL_MEMWR) == 0) {
|
||||
pcie_control |= IOAT3_PCI_CONTROL_MEMWR;
|
||||
writew(pcie_control,
|
||||
ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
/* TODO version, compatibility and configuration checks */
|
||||
|
||||
/* copy out the APIC to DCA tag map */
|
||||
tag_map.low =
|
||||
readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_LOW);
|
||||
tag_map.high =
|
||||
readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_HIGH);
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = tag_map.full >> (8 * i);
|
||||
ioatdca->tag_map[i] = bit & DCA_TAG_MAP_MASK;
|
||||
}
|
||||
|
||||
err = register_dca_provider(dca, &pdev->dev);
|
||||
if (err) {
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dca;
|
||||
}
|
1741
drivers/dma/ioat/dma.c
Normal file
1741
drivers/dma/ioat/dma.c
Normal file
File diff suppressed because it is too large
Load Diff
165
drivers/dma/ioat/dma.h
Normal file
165
drivers/dma/ioat/dma.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called COPYING.
|
||||
*/
|
||||
#ifndef IOATDMA_H
|
||||
#define IOATDMA_H
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include "hw.h"
|
||||
#include <linux/init.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#define IOAT_DMA_VERSION "3.64"
|
||||
|
||||
enum ioat_interrupt {
|
||||
none = 0,
|
||||
msix_multi_vector = 1,
|
||||
msix_single_vector = 2,
|
||||
msi = 3,
|
||||
intx = 4,
|
||||
};
|
||||
|
||||
#define IOAT_LOW_COMPLETION_MASK 0xffffffc0
|
||||
#define IOAT_DMA_DCA_ANY_CPU ~0
|
||||
#define IOAT_WATCHDOG_PERIOD (2 * HZ)
|
||||
|
||||
|
||||
/**
|
||||
* struct ioatdma_device - internal representation of a IOAT device
|
||||
* @pdev: PCI-Express device
|
||||
* @reg_base: MMIO register space base address
|
||||
* @dma_pool: for allocating DMA descriptors
|
||||
* @common: embedded struct dma_device
|
||||
* @version: version of ioatdma device
|
||||
* @irq_mode: which style irq to use
|
||||
* @msix_entries: irq handlers
|
||||
* @idx: per channel data
|
||||
*/
|
||||
|
||||
struct ioatdma_device {
|
||||
struct pci_dev *pdev;
|
||||
void __iomem *reg_base;
|
||||
struct pci_pool *dma_pool;
|
||||
struct pci_pool *completion_pool;
|
||||
struct dma_device common;
|
||||
u8 version;
|
||||
enum ioat_interrupt irq_mode;
|
||||
struct delayed_work work;
|
||||
struct msix_entry msix_entries[4];
|
||||
struct ioat_dma_chan *idx[4];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ioat_dma_chan - internal representation of a DMA channel
|
||||
*/
|
||||
struct ioat_dma_chan {
|
||||
|
||||
void __iomem *reg_base;
|
||||
|
||||
dma_cookie_t completed_cookie;
|
||||
unsigned long last_completion;
|
||||
unsigned long last_completion_time;
|
||||
|
||||
size_t xfercap; /* XFERCAP register value expanded out */
|
||||
|
||||
spinlock_t cleanup_lock;
|
||||
spinlock_t desc_lock;
|
||||
struct list_head free_desc;
|
||||
struct list_head used_desc;
|
||||
unsigned long watchdog_completion;
|
||||
int watchdog_tcp_cookie;
|
||||
u32 watchdog_last_tcp_cookie;
|
||||
struct delayed_work work;
|
||||
|
||||
int pending;
|
||||
int dmacount;
|
||||
int desccount;
|
||||
|
||||
struct ioatdma_device *device;
|
||||
struct dma_chan common;
|
||||
|
||||
dma_addr_t completion_addr;
|
||||
union {
|
||||
u64 full; /* HW completion writeback */
|
||||
struct {
|
||||
u32 low;
|
||||
u32 high;
|
||||
};
|
||||
} *completion_virt;
|
||||
unsigned long last_compl_desc_addr_hw;
|
||||
struct tasklet_struct cleanup_task;
|
||||
};
|
||||
|
||||
/* wrapper around hardware descriptor format + additional software fields */
|
||||
|
||||
/**
|
||||
* struct ioat_desc_sw - wrapper around hardware descriptor
|
||||
* @hw: hardware DMA descriptor
|
||||
* @node: this descriptor will either be on the free list,
|
||||
* or attached to a transaction list (async_tx.tx_list)
|
||||
* @tx_cnt: number of descriptors required to complete the transaction
|
||||
* @async_tx: the generic software descriptor for all engines
|
||||
*/
|
||||
struct ioat_desc_sw {
|
||||
struct ioat_dma_descriptor *hw;
|
||||
struct list_head node;
|
||||
int tx_cnt;
|
||||
size_t len;
|
||||
dma_addr_t src;
|
||||
dma_addr_t dst;
|
||||
struct dma_async_tx_descriptor async_tx;
|
||||
};
|
||||
|
||||
static inline void ioat_set_tcp_copy_break(struct ioatdma_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_DMA
|
||||
switch (dev->version) {
|
||||
case IOAT_VER_1_2:
|
||||
sysctl_tcp_dma_copybreak = 4096;
|
||||
break;
|
||||
case IOAT_VER_2_0:
|
||||
sysctl_tcp_dma_copybreak = 2048;
|
||||
break;
|
||||
case IOAT_VER_3_0:
|
||||
sysctl_tcp_dma_copybreak = 262144;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_INTEL_IOATDMA) || defined(CONFIG_INTEL_IOATDMA_MODULE)
|
||||
struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
|
||||
void __iomem *iobase);
|
||||
void ioat_dma_remove(struct ioatdma_device *device);
|
||||
struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase);
|
||||
struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
|
||||
struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase);
|
||||
#else
|
||||
#define ioat_dma_probe(pdev, iobase) NULL
|
||||
#define ioat_dma_remove(device) do { } while (0)
|
||||
#define ioat_dca_init(pdev, iobase) NULL
|
||||
#define ioat2_dca_init(pdev, iobase) NULL
|
||||
#define ioat3_dca_init(pdev, iobase) NULL
|
||||
#endif
|
||||
|
||||
#endif /* IOATDMA_H */
|
70
drivers/dma/ioat/hw.h
Normal file
70
drivers/dma/ioat/hw.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called COPYING.
|
||||
*/
|
||||
#ifndef _IOAT_HW_H_
|
||||
#define _IOAT_HW_H_
|
||||
|
||||
/* PCI Configuration Space Values */
|
||||
#define IOAT_PCI_VID 0x8086
|
||||
|
||||
/* CB device ID's */
|
||||
#define IOAT_PCI_DID_5000 0x1A38
|
||||
#define IOAT_PCI_DID_CNB 0x360B
|
||||
#define IOAT_PCI_DID_SCNB 0x65FF
|
||||
#define IOAT_PCI_DID_SNB 0x402F
|
||||
|
||||
#define IOAT_PCI_RID 0x00
|
||||
#define IOAT_PCI_SVID 0x8086
|
||||
#define IOAT_PCI_SID 0x8086
|
||||
#define IOAT_VER_1_2 0x12 /* Version 1.2 */
|
||||
#define IOAT_VER_2_0 0x20 /* Version 2.0 */
|
||||
#define IOAT_VER_3_0 0x30 /* Version 3.0 */
|
||||
|
||||
struct ioat_dma_descriptor {
|
||||
uint32_t size;
|
||||
uint32_t ctl;
|
||||
uint64_t src_addr;
|
||||
uint64_t dst_addr;
|
||||
uint64_t next;
|
||||
uint64_t rsv1;
|
||||
uint64_t rsv2;
|
||||
uint64_t user1;
|
||||
uint64_t user2;
|
||||
};
|
||||
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_INT_GN 0x00000001
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_SRC_SN 0x00000002
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_DST_SN 0x00000004
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_CP_STS 0x00000008
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_FRAME 0x00000010
|
||||
#define IOAT_DMA_DESCRIPTOR_NUL 0x00000020
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_SP_BRK 0x00000040
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_DP_BRK 0x00000080
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_BNDL 0x00000100
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_DCA 0x00000200
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_BUFHINT 0x00000400
|
||||
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_CONTEXT 0xFF000000
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_DMA 0x00000000
|
||||
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_CONTEXT_DCA 0x00000001
|
||||
#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_MASK 0xFF000000
|
||||
|
||||
#endif
|
202
drivers/dma/ioat/pci.c
Normal file
202
drivers/dma/ioat/pci.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This driver supports an Intel I/OAT DMA engine, which does asynchronous
|
||||
* copy operations.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dca.h>
|
||||
#include "dma.h"
|
||||
#include "registers.h"
|
||||
#include "hw.h"
|
||||
|
||||
MODULE_VERSION(IOAT_DMA_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Intel Corporation");
|
||||
|
||||
static struct pci_device_id ioat_pci_tbl[] = {
|
||||
/* I/OAT v1 platforms */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
|
||||
|
||||
/* 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, }
|
||||
};
|
||||
|
||||
struct ioat_device {
|
||||
struct pci_dev *pdev;
|
||||
void __iomem *iobase;
|
||||
struct ioatdma_device *dma;
|
||||
struct dca_provider *dca;
|
||||
};
|
||||
|
||||
static int __devinit ioat_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id);
|
||||
static void __devexit ioat_remove(struct pci_dev *pdev);
|
||||
|
||||
static int ioat_dca_enabled = 1;
|
||||
module_param(ioat_dca_enabled, int, 0644);
|
||||
MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
|
||||
|
||||
static struct pci_driver ioat_pci_driver = {
|
||||
.name = "ioatdma",
|
||||
.id_table = ioat_pci_tbl,
|
||||
.probe = ioat_probe,
|
||||
.remove = __devexit_p(ioat_remove),
|
||||
};
|
||||
|
||||
static int __devinit ioat_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
void __iomem *iobase;
|
||||
struct ioat_device *device;
|
||||
unsigned long mmio_start, mmio_len;
|
||||
int err;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
goto err_enable_device;
|
||||
|
||||
err = pci_request_regions(pdev, ioat_pci_driver.name);
|
||||
if (err)
|
||||
goto err_request_regions;
|
||||
|
||||
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||
if (err)
|
||||
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (err)
|
||||
goto err_set_dma_mask;
|
||||
|
||||
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||
if (err)
|
||||
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (err)
|
||||
goto err_set_dma_mask;
|
||||
|
||||
mmio_start = pci_resource_start(pdev, 0);
|
||||
mmio_len = pci_resource_len(pdev, 0);
|
||||
iobase = ioremap(mmio_start, mmio_len);
|
||||
if (!iobase) {
|
||||
err = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
device = kzalloc(sizeof(*device), GFP_KERNEL);
|
||||
if (!device) {
|
||||
err = -ENOMEM;
|
||||
goto err_kzalloc;
|
||||
}
|
||||
device->pdev = pdev;
|
||||
pci_set_drvdata(pdev, device);
|
||||
device->iobase = iobase;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
switch (readb(iobase + IOAT_VER_OFFSET)) {
|
||||
case IOAT_VER_1_2:
|
||||
device->dma = ioat_dma_probe(pdev, iobase);
|
||||
if (device->dma && ioat_dca_enabled)
|
||||
device->dca = ioat_dca_init(pdev, iobase);
|
||||
break;
|
||||
case IOAT_VER_2_0:
|
||||
device->dma = ioat_dma_probe(pdev, 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;
|
||||
}
|
||||
if (!device->dma)
|
||||
err = -ENODEV;
|
||||
|
||||
if (err)
|
||||
goto err_version;
|
||||
|
||||
return 0;
|
||||
|
||||
err_version:
|
||||
kfree(device);
|
||||
err_kzalloc:
|
||||
iounmap(iobase);
|
||||
err_ioremap:
|
||||
err_set_dma_mask:
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
err_request_regions:
|
||||
err_enable_device:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __devexit ioat_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ioat_device *device = pci_get_drvdata(pdev);
|
||||
|
||||
dev_err(&pdev->dev, "Removing dma and dca services\n");
|
||||
if (device->dca) {
|
||||
unregister_dca_provider(device->dca);
|
||||
free_dca_provider(device->dca);
|
||||
device->dca = NULL;
|
||||
}
|
||||
|
||||
if (device->dma) {
|
||||
ioat_dma_remove(device->dma);
|
||||
device->dma = NULL;
|
||||
}
|
||||
|
||||
kfree(device);
|
||||
}
|
||||
|
||||
static int __init ioat_init_module(void)
|
||||
{
|
||||
return pci_register_driver(&ioat_pci_driver);
|
||||
}
|
||||
module_init(ioat_init_module);
|
||||
|
||||
static void __exit ioat_exit_module(void)
|
||||
{
|
||||
pci_unregister_driver(&ioat_pci_driver);
|
||||
}
|
||||
module_exit(ioat_exit_module);
|
226
drivers/dma/ioat/registers.h
Normal file
226
drivers/dma/ioat/registers.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called COPYING.
|
||||
*/
|
||||
#ifndef _IOAT_REGISTERS_H_
|
||||
#define _IOAT_REGISTERS_H_
|
||||
|
||||
#define IOAT_PCI_DMACTRL_OFFSET 0x48
|
||||
#define IOAT_PCI_DMACTRL_DMA_EN 0x00000001
|
||||
#define IOAT_PCI_DMACTRL_MSI_EN 0x00000002
|
||||
|
||||
#define IOAT_PCI_DEVICE_ID_OFFSET 0x02
|
||||
#define IOAT_PCI_DMAUNCERRSTS_OFFSET 0x148
|
||||
#define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184
|
||||
|
||||
/* MMIO Device Registers */
|
||||
#define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */
|
||||
|
||||
#define IOAT_XFERCAP_OFFSET 0x01 /* 8-bit */
|
||||
#define IOAT_XFERCAP_4KB 12
|
||||
#define IOAT_XFERCAP_8KB 13
|
||||
#define IOAT_XFERCAP_16KB 14
|
||||
#define IOAT_XFERCAP_32KB 15
|
||||
#define IOAT_XFERCAP_32GB 0
|
||||
|
||||
#define IOAT_GENCTRL_OFFSET 0x02 /* 8-bit */
|
||||
#define IOAT_GENCTRL_DEBUG_EN 0x01
|
||||
|
||||
#define IOAT_INTRCTRL_OFFSET 0x03 /* 8-bit */
|
||||
#define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */
|
||||
#define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */
|
||||
#define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */
|
||||
#define IOAT_INTRCTRL_MSIX_VECTOR_CONTROL 0x08 /* Enable all MSI-X vectors */
|
||||
|
||||
#define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */
|
||||
|
||||
#define IOAT_VER_OFFSET 0x08 /* 8-bit */
|
||||
#define IOAT_VER_MAJOR_MASK 0xF0
|
||||
#define IOAT_VER_MINOR_MASK 0x0F
|
||||
#define GET_IOAT_VER_MAJOR(x) (((x) & IOAT_VER_MAJOR_MASK) >> 4)
|
||||
#define GET_IOAT_VER_MINOR(x) ((x) & IOAT_VER_MINOR_MASK)
|
||||
|
||||
#define IOAT_PERPORTOFFSET_OFFSET 0x0A /* 16-bit */
|
||||
|
||||
#define IOAT_INTRDELAY_OFFSET 0x0C /* 16-bit */
|
||||
#define IOAT_INTRDELAY_INT_DELAY_MASK 0x3FFF /* Interrupt Delay Time */
|
||||
#define IOAT_INTRDELAY_COALESE_SUPPORT 0x8000 /* Interrupt Coalescing Supported */
|
||||
|
||||
#define IOAT_DEVICE_STATUS_OFFSET 0x0E /* 16-bit */
|
||||
#define IOAT_DEVICE_STATUS_DEGRADED_MODE 0x0001
|
||||
|
||||
#define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */
|
||||
|
||||
/* DMA Channel Registers */
|
||||
#define IOAT_CHANCTRL_OFFSET 0x00 /* 16-bit Channel Control Register */
|
||||
#define IOAT_CHANCTRL_CHANNEL_PRIORITY_MASK 0xF000
|
||||
#define IOAT_CHANCTRL_CHANNEL_IN_USE 0x0100
|
||||
#define IOAT_CHANCTRL_DESCRIPTOR_ADDR_SNOOP_CONTROL 0x0020
|
||||
#define IOAT_CHANCTRL_ERR_INT_EN 0x0010
|
||||
#define IOAT_CHANCTRL_ANY_ERR_ABORT_EN 0x0008
|
||||
#define IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004
|
||||
#define IOAT_CHANCTRL_INT_DISABLE 0x0001
|
||||
|
||||
#define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatibility */
|
||||
#define IOAT_DMA_COMP_V1 0x0001 /* Compatibility with DMA version 1 */
|
||||
#define IOAT_DMA_COMP_V2 0x0002 /* Compatibility with DMA version 2 */
|
||||
|
||||
|
||||
#define IOAT1_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
|
||||
#define IOAT2_CHANSTS_OFFSET 0x08 /* 64-bit Channel Status Register */
|
||||
#define IOAT_CHANSTS_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHANSTS_OFFSET : IOAT2_CHANSTS_OFFSET)
|
||||
#define IOAT1_CHANSTS_OFFSET_LOW 0x04
|
||||
#define IOAT2_CHANSTS_OFFSET_LOW 0x08
|
||||
#define IOAT_CHANSTS_OFFSET_LOW(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHANSTS_OFFSET_LOW : IOAT2_CHANSTS_OFFSET_LOW)
|
||||
#define IOAT1_CHANSTS_OFFSET_HIGH 0x08
|
||||
#define IOAT2_CHANSTS_OFFSET_HIGH 0x0C
|
||||
#define IOAT_CHANSTS_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHANSTS_OFFSET_HIGH : IOAT2_CHANSTS_OFFSET_HIGH)
|
||||
#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR ~0x3F
|
||||
#define IOAT_CHANSTS_SOFT_ERR 0x0000000000000010
|
||||
#define IOAT_CHANSTS_UNAFFILIATED_ERR 0x0000000000000008
|
||||
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS 0x0000000000000007
|
||||
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE 0x0
|
||||
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE 0x1
|
||||
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_SUSPENDED 0x2
|
||||
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED 0x3
|
||||
|
||||
|
||||
|
||||
#define IOAT_CHAN_DMACOUNT_OFFSET 0x06 /* 16-bit DMA Count register */
|
||||
|
||||
#define IOAT_DCACTRL_OFFSET 0x30 /* 32 bit Direct Cache Access Control Register */
|
||||
#define IOAT_DCACTRL_CMPL_WRITE_ENABLE 0x10000
|
||||
#define IOAT_DCACTRL_TARGET_CPU_MASK 0xFFFF /* APIC ID */
|
||||
|
||||
/* CB DCA Memory Space Registers */
|
||||
#define IOAT_DCAOFFSET_OFFSET 0x14
|
||||
/* CB_BAR + IOAT_DCAOFFSET value */
|
||||
#define IOAT_DCA_VER_OFFSET 0x00
|
||||
#define IOAT_DCA_VER_MAJOR_MASK 0xF0
|
||||
#define IOAT_DCA_VER_MINOR_MASK 0x0F
|
||||
|
||||
#define IOAT_DCA_COMP_OFFSET 0x02
|
||||
#define IOAT_DCA_COMP_V1 0x1
|
||||
|
||||
#define IOAT_FSB_CAPABILITY_OFFSET 0x04
|
||||
#define IOAT_FSB_CAPABILITY_PREFETCH 0x1
|
||||
|
||||
#define IOAT_PCI_CAPABILITY_OFFSET 0x06
|
||||
#define IOAT_PCI_CAPABILITY_MEMWR 0x1
|
||||
|
||||
#define IOAT_FSB_CAP_ENABLE_OFFSET 0x08
|
||||
#define IOAT_FSB_CAP_ENABLE_PREFETCH 0x1
|
||||
|
||||
#define IOAT_PCI_CAP_ENABLE_OFFSET 0x0A
|
||||
#define IOAT_PCI_CAP_ENABLE_MEMWR 0x1
|
||||
|
||||
#define IOAT_APICID_TAG_MAP_OFFSET 0x0C
|
||||
#define IOAT_APICID_TAG_MAP_TAG0 0x0000000F
|
||||
#define IOAT_APICID_TAG_MAP_TAG0_SHIFT 0
|
||||
#define IOAT_APICID_TAG_MAP_TAG1 0x000000F0
|
||||
#define IOAT_APICID_TAG_MAP_TAG1_SHIFT 4
|
||||
#define IOAT_APICID_TAG_MAP_TAG2 0x00000F00
|
||||
#define IOAT_APICID_TAG_MAP_TAG2_SHIFT 8
|
||||
#define IOAT_APICID_TAG_MAP_TAG3 0x0000F000
|
||||
#define IOAT_APICID_TAG_MAP_TAG3_SHIFT 12
|
||||
#define IOAT_APICID_TAG_MAP_TAG4 0x000F0000
|
||||
#define IOAT_APICID_TAG_MAP_TAG4_SHIFT 16
|
||||
#define IOAT_APICID_TAG_CB2_VALID 0x8080808080
|
||||
|
||||
#define IOAT_DCA_GREQID_OFFSET 0x10
|
||||
#define IOAT_DCA_GREQID_SIZE 0x04
|
||||
#define IOAT_DCA_GREQID_MASK 0xFFFF
|
||||
#define IOAT_DCA_GREQID_IGNOREFUN 0x10000000
|
||||
#define IOAT_DCA_GREQID_VALID 0x20000000
|
||||
#define IOAT_DCA_GREQID_LASTID 0x80000000
|
||||
|
||||
#define IOAT3_CSI_CAPABILITY_OFFSET 0x08
|
||||
#define IOAT3_CSI_CAPABILITY_PREFETCH 0x1
|
||||
|
||||
#define IOAT3_PCI_CAPABILITY_OFFSET 0x0A
|
||||
#define IOAT3_PCI_CAPABILITY_MEMWR 0x1
|
||||
|
||||
#define IOAT3_CSI_CONTROL_OFFSET 0x0C
|
||||
#define IOAT3_CSI_CONTROL_PREFETCH 0x1
|
||||
|
||||
#define IOAT3_PCI_CONTROL_OFFSET 0x0E
|
||||
#define IOAT3_PCI_CONTROL_MEMWR 0x1
|
||||
|
||||
#define IOAT3_APICID_TAG_MAP_OFFSET 0x10
|
||||
#define IOAT3_APICID_TAG_MAP_OFFSET_LOW 0x10
|
||||
#define IOAT3_APICID_TAG_MAP_OFFSET_HIGH 0x14
|
||||
|
||||
#define IOAT3_DCA_GREQID_OFFSET 0x02
|
||||
|
||||
#define IOAT1_CHAINADDR_OFFSET 0x0C /* 64-bit Descriptor Chain Address Register */
|
||||
#define IOAT2_CHAINADDR_OFFSET 0x10 /* 64-bit Descriptor Chain Address Register */
|
||||
#define IOAT_CHAINADDR_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHAINADDR_OFFSET : IOAT2_CHAINADDR_OFFSET)
|
||||
#define IOAT1_CHAINADDR_OFFSET_LOW 0x0C
|
||||
#define IOAT2_CHAINADDR_OFFSET_LOW 0x10
|
||||
#define IOAT_CHAINADDR_OFFSET_LOW(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHAINADDR_OFFSET_LOW : IOAT2_CHAINADDR_OFFSET_LOW)
|
||||
#define IOAT1_CHAINADDR_OFFSET_HIGH 0x10
|
||||
#define IOAT2_CHAINADDR_OFFSET_HIGH 0x14
|
||||
#define IOAT_CHAINADDR_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHAINADDR_OFFSET_HIGH : IOAT2_CHAINADDR_OFFSET_HIGH)
|
||||
|
||||
#define IOAT1_CHANCMD_OFFSET 0x14 /* 8-bit DMA Channel Command Register */
|
||||
#define IOAT2_CHANCMD_OFFSET 0x04 /* 8-bit DMA Channel Command Register */
|
||||
#define IOAT_CHANCMD_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
|
||||
? IOAT1_CHANCMD_OFFSET : IOAT2_CHANCMD_OFFSET)
|
||||
#define IOAT_CHANCMD_RESET 0x20
|
||||
#define IOAT_CHANCMD_RESUME 0x10
|
||||
#define IOAT_CHANCMD_ABORT 0x08
|
||||
#define IOAT_CHANCMD_SUSPEND 0x04
|
||||
#define IOAT_CHANCMD_APPEND 0x02
|
||||
#define IOAT_CHANCMD_START 0x01
|
||||
|
||||
#define IOAT_CHANCMP_OFFSET 0x18 /* 64-bit Channel Completion Address Register */
|
||||
#define IOAT_CHANCMP_OFFSET_LOW 0x18
|
||||
#define IOAT_CHANCMP_OFFSET_HIGH 0x1C
|
||||
|
||||
#define IOAT_CDAR_OFFSET 0x20 /* 64-bit Current Descriptor Address Register */
|
||||
#define IOAT_CDAR_OFFSET_LOW 0x20
|
||||
#define IOAT_CDAR_OFFSET_HIGH 0x24
|
||||
|
||||
#define IOAT_CHANERR_OFFSET 0x28 /* 32-bit Channel Error Register */
|
||||
#define IOAT_CHANERR_DMA_TRANSFER_SRC_ADDR_ERR 0x0001
|
||||
#define IOAT_CHANERR_DMA_TRANSFER_DEST_ADDR_ERR 0x0002
|
||||
#define IOAT_CHANERR_NEXT_DESCRIPTOR_ADDR_ERR 0x0004
|
||||
#define IOAT_CHANERR_NEXT_DESCRIPTOR_ALIGNMENT_ERR 0x0008
|
||||
#define IOAT_CHANERR_CHAIN_ADDR_VALUE_ERR 0x0010
|
||||
#define IOAT_CHANERR_CHANCMD_ERR 0x0020
|
||||
#define IOAT_CHANERR_CHIPSET_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0040
|
||||
#define IOAT_CHANERR_DMA_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0080
|
||||
#define IOAT_CHANERR_READ_DATA_ERR 0x0100
|
||||
#define IOAT_CHANERR_WRITE_DATA_ERR 0x0200
|
||||
#define IOAT_CHANERR_DESCRIPTOR_CONTROL_ERR 0x0400
|
||||
#define IOAT_CHANERR_DESCRIPTOR_LENGTH_ERR 0x0800
|
||||
#define IOAT_CHANERR_COMPLETION_ADDR_ERR 0x1000
|
||||
#define IOAT_CHANERR_INT_CONFIGURATION_ERR 0x2000
|
||||
#define IOAT_CHANERR_SOFT_ERR 0x4000
|
||||
#define IOAT_CHANERR_UNAFFILIATED_ERR 0x8000
|
||||
|
||||
#define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
|
||||
|
||||
#endif /* _IOAT_REGISTERS_H_ */
|
Reference in New Issue
Block a user