12ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/*
22ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * Intel I/OAT DMA Linux driver
3211a22ce08dbb27eb1a66df8a4bdae5e96092bc8Maciej Sosnowski * Copyright(c) 2007 - 2009 Intel Corporation.
42ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
52ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * This program is free software; you can redistribute it and/or modify it
62ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * under the terms and conditions of the GNU General Public License,
72ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * version 2, as published by the Free Software Foundation.
82ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
92ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * This program is distributed in the hope that it will be useful, but WITHOUT
102ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
112ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
122ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * more details.
132ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
142ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * You should have received a copy of the GNU General Public License along with
152ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * this program; if not, write to the Free Software Foundation, Inc.,
162ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
172ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
182ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * The full GNU General Public License is included in this distribution in
192ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * the file called "COPYING".
202ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
212ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson */
222ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
232ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <linux/kernel.h>
242ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <linux/pci.h>
252ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <linux/smp.h>
262ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <linux/interrupt.h>
272ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <linux/dca.h>
282ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
292ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/* either a kernel change is needed, or we need something like this in kernel */
302ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#ifndef CONFIG_SMP
312ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#include <asm/smp.h>
322ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#undef cpu_physical_id
332ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24)
342ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#endif
352ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
36584ec22759c06cdfc189c03a727f20038526245bDan Williams#include "dma.h"
37584ec22759c06cdfc189c03a727f20038526245bDan Williams#include "registers.h"
382ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
392ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/*
407f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6
412ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * contain the bit number of the APIC ID to map into the DCA tag.  If the valid
422ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * bit is not set, then the value must be 0 or 1 and defines the bit in the tag.
432ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson */
442ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#define DCA_TAG_MAP_VALID 0x80
452ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
467f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski#define DCA3_TAG_MAP_BIT_TO_INV 0x80
477f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski#define DCA3_TAG_MAP_BIT_TO_SEL 0x40
487f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski#define DCA3_TAG_MAP_LITERAL_VAL 0x1
497f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
507f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski#define DCA_TAG_MAP_MASK 0xDF
517f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5249bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski/* expected tag map bytes for I/OAT ver.2 */
5349bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski#define DCA2_TAG_MAP_BYTE0 0x80
5449bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski#define DCA2_TAG_MAP_BYTE1 0x0
5549bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski#define DCA2_TAG_MAP_BYTE2 0x81
5649bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski#define DCA2_TAG_MAP_BYTE3 0x82
5749bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski#define DCA2_TAG_MAP_BYTE4 0x82
5849bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski
5949bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski/* verify if tag map matches expected values */
6049bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowskistatic inline int dca2_tag_map_valid(u8 *tag_map)
6149bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski{
6249bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski	return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) &&
6349bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		(tag_map[1] == DCA2_TAG_MAP_BYTE1) &&
6449bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		(tag_map[2] == DCA2_TAG_MAP_BYTE2) &&
6549bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		(tag_map[3] == DCA2_TAG_MAP_BYTE3) &&
6649bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		(tag_map[4] == DCA2_TAG_MAP_BYTE4));
6749bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski}
6849bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski
692ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/*
702ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * "Legacy" DCA systems do not implement the DCA register set in the
712ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * I/OAT device.  Software needs direct support for their tag mappings.
722ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson */
732ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
742ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#define APICID_BIT(x)		(DCA_TAG_MAP_VALID | (x))
752ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#define IOAT_TAG_MAP_LEN	8
762ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
772ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = {
782ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
792ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = {
802ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
812ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = {
822ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), };
832ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 };
842ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
852ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/* pack PCI B/D/F into a u16 */
862ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic inline u16 dcaid_from_pcidev(struct pci_dev *pci)
872ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
882ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return (pci->bus->number << 8) | pci->devfn;
892ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
902ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
915149fd010f404889b7d8f79159057791fbb817b1Shannon Nelsonstatic int dca_enabled_in_bios(struct pci_dev *pdev)
922ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
932ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* CPUID level 9 returns DCA configuration */
942ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* Bit 0 indicates DCA enabled by the BIOS */
952ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	unsigned long cpuid_level_9;
962ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int res;
972ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
982ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	cpuid_level_9 = cpuid_eax(9);
992ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	res = test_bit(0, &cpuid_level_9);
1002ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (!res)
101e22dde9904c2d26a522f1a2b89854a8238bf0933Dan Williams		dev_dbg(&pdev->dev, "DCA is disabled in BIOS\n");
1022ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1032ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return res;
1042ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
1052ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
106228c4f5cfbf1cda411d9aa7204a612a63c89b1e8Dan Williamsint system_has_dca_enabled(struct pci_dev *pdev)
1072ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
1082ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (boot_cpu_has(X86_FEATURE_DCA))
1095149fd010f404889b7d8f79159057791fbb817b1Shannon Nelson		return dca_enabled_in_bios(pdev);
1102ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
111e22dde9904c2d26a522f1a2b89854a8238bf0933Dan Williams	dev_dbg(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n");
1122ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return 0;
1132ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
1142ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1152ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstruct ioat_dca_slot {
1162ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct pci_dev *pdev;	/* requester device */
1172ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	u16 rid;		/* requester id, as used by IOAT */
1182ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson};
1192ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1202ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson#define IOAT_DCA_MAX_REQ 6
1217f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski#define IOAT3_DCA_MAX_REQ 2
1222ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1232ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstruct ioat_dca_priv {
1242ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	void __iomem		*iobase;
12553a0c98e117272125183138aefc6b13b4a5f38a1Al Viro	void __iomem		*dca_base;
1262ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int			 max_requesters;
1272ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int			 requester_count;
1282ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	u8			 tag_map[IOAT_TAG_MAP_LEN];
1292ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct ioat_dca_slot 	 req_slots[0];
1302ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson};
1312ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1322ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson/* 5000 series chipset DCA Port Requester ID Table Entry Format
1332ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * [15:8]	PCI-Express Bus Number
1342ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * [7:3]	PCI-Express Device Number
1352ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * [2:0]	PCI-Express Function Number
1362ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson *
1372ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * 5000 series chipset DCA control register format
1382ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * [7:1]	Reserved (0)
1392ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson * [0]		Ignore Function Number
1402ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson */
1412ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1422ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev)
1432ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
1442ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct ioat_dca_priv *ioatdca = dca_priv(dca);
1452ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct pci_dev *pdev;
1462ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int i;
1472ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	u16 id;
1482ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1492ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* This implementation only supports PCI-Express */
1502ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (dev->bus != &pci_bus_type)
1512ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return -ENODEV;
1522ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	pdev = to_pci_dev(dev);
1532ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	id = dcaid_from_pcidev(pdev);
1542ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1552ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (ioatdca->requester_count == ioatdca->max_requesters)
1562ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return -ENODEV;
1572ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1582ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	for (i = 0; i < ioatdca->max_requesters; i++) {
1592ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		if (ioatdca->req_slots[i].pdev == NULL) {
1602ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			/* found an empty slot */
1612ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->requester_count++;
1622ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->req_slots[i].pdev = pdev;
1632ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->req_slots[i].rid = id;
1642ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			writew(id, ioatdca->dca_base + (i * 4));
1652ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			/* make sure the ignore function bit is off */
1662ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			writeb(0, ioatdca->dca_base + (i * 4) + 2);
1672ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			return i;
1682ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		}
1692ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	}
1702ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* Error, ioatdma->requester_count is out of whack */
1712ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return -EFAULT;
1722ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
1732ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1742ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic int ioat_dca_remove_requester(struct dca_provider *dca,
1752ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson				     struct device *dev)
1762ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
1772ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct ioat_dca_priv *ioatdca = dca_priv(dca);
1782ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct pci_dev *pdev;
1792ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int i;
1802ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1812ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* This implementation only supports PCI-Express */
1822ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (dev->bus != &pci_bus_type)
1832ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return -ENODEV;
1842ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	pdev = to_pci_dev(dev);
1852ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1862ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	for (i = 0; i < ioatdca->max_requesters; i++) {
1872ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		if (ioatdca->req_slots[i].pdev == pdev) {
1882ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			writew(0, ioatdca->dca_base + (i * 4));
1892ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->req_slots[i].pdev = NULL;
1902ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->req_slots[i].rid = 0;
1912ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			ioatdca->requester_count--;
1922ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			return i;
1932ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		}
1942ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	}
1952ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return -ENODEV;
1962ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
1972ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
1987f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic u8 ioat_dca_get_tag(struct dca_provider *dca,
1997f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			   struct device *dev,
2007f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			   int cpu)
2012ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
2022ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct ioat_dca_priv *ioatdca = dca_priv(dca);
2032ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int i, apic_id, bit, value;
2042ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	u8 entry, tag;
2052ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2062ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	tag = 0;
2072ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	apic_id = cpu_physical_id(cpu);
2082ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2092ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	for (i = 0; i < IOAT_TAG_MAP_LEN; i++) {
2102ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		entry = ioatdca->tag_map[i];
2112ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		if (entry & DCA_TAG_MAP_VALID) {
2122ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			bit = entry & ~DCA_TAG_MAP_VALID;
2132ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			value = (apic_id & (1 << bit)) ? 1 : 0;
2142ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		} else {
2152ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			value = entry ? 1 : 0;
2162ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		}
2172ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		tag |= (value << i);
2182ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	}
2192ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return tag;
2202ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
2212ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2227f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic int ioat_dca_dev_managed(struct dca_provider *dca,
2237f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski				struct device *dev)
2247f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
2257f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct ioat_dca_priv *ioatdca = dca_priv(dca);
2267f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct pci_dev *pdev;
2277f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int i;
2287f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
2297f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	pdev = to_pci_dev(dev);
2307f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	for (i = 0; i < ioatdca->max_requesters; i++) {
2317f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		if (ioatdca->req_slots[i].pdev == pdev)
2327f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			return 1;
2337f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
2347f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return 0;
2357f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
2367f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
2372ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelsonstatic struct dca_ops ioat_dca_ops = {
2382ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	.add_requester		= ioat_dca_add_requester,
2392ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	.remove_requester	= ioat_dca_remove_requester,
2402ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	.get_tag		= ioat_dca_get_tag,
2417f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.dev_managed		= ioat_dca_dev_managed,
2422ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson};
2432ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2442ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
245345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsstruct dca_provider * __devinit
246345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
2472ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson{
2482ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct dca_provider *dca;
2492ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	struct ioat_dca_priv *ioatdca;
2502ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	u8 *tag_map = NULL;
2512ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int i;
2522ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	int err;
2537f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u8 version;
2547f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u8 max_requesters;
2552ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2565149fd010f404889b7d8f79159057791fbb817b1Shannon Nelson	if (!system_has_dca_enabled(pdev))
2572ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return NULL;
2582ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2592ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* I/OAT v1 systems must have a known tag_map to support DCA */
2602ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	switch (pdev->vendor) {
2612ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	case PCI_VENDOR_ID_INTEL:
2622ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		switch (pdev->device) {
2632ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		case PCI_DEVICE_ID_INTEL_IOAT:
2642ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			tag_map = ioat_tag_map_BNB;
2652ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			break;
2662ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		case PCI_DEVICE_ID_INTEL_IOAT_CNB:
2672ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			tag_map = ioat_tag_map_CNB;
2682ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			break;
2692ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		case PCI_DEVICE_ID_INTEL_IOAT_SCNB:
2702ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			tag_map = ioat_tag_map_SCNB;
2712ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			break;
2722ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		}
2732ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		break;
2742ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	case PCI_VENDOR_ID_UNISYS:
2752ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		switch (pdev->device) {
2762ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR:
2772ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			tag_map = ioat_tag_map_UNISYS;
2782ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			break;
2792ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		}
2802ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		break;
2812ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	}
2822ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (tag_map == NULL)
2832ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return NULL;
2842ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2857f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	version = readb(iobase + IOAT_VER_OFFSET);
2867f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (version == IOAT_VER_3_0)
2877f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		max_requesters = IOAT3_DCA_MAX_REQ;
2887f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	else
2897f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		max_requesters = IOAT_DCA_MAX_REQ;
2907f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
2912ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	dca = alloc_dca_provider(&ioat_dca_ops,
2922ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson			sizeof(*ioatdca) +
2937f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			(sizeof(struct ioat_dca_slot) * max_requesters));
2942ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (!dca)
2952ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return NULL;
2962ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
2972ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	ioatdca = dca_priv(dca);
2987f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	ioatdca->max_requesters = max_requesters;
2992ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	ioatdca->dca_base = iobase + 0x54;
3002ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
3012ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	/* copy over the APIC ID to DCA tag mapping */
3022ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	for (i = 0; i < IOAT_TAG_MAP_LEN; i++)
3032ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		ioatdca->tag_map[i] = tag_map[i];
3042ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
3052ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	err = register_dca_provider(dca, &pdev->dev);
3062ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	if (err) {
3072ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		free_dca_provider(dca);
3082ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson		return NULL;
3092ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	}
3102ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
3112ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson	return dca;
3122ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson}
3132ed6dc34f9ed39bb8e4c81ea1056f0ba56315841Shannon Nelson
3147bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3157bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelsonstatic int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev)
3167bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson{
3177bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct ioat_dca_priv *ioatdca = dca_priv(dca);
3187bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct pci_dev *pdev;
3197bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int i;
3207bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 id;
3217bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 global_req_table;
3227bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3237bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* This implementation only supports PCI-Express */
3247bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (dev->bus != &pci_bus_type)
3257bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return -ENODEV;
3267bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	pdev = to_pci_dev(dev);
3277bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	id = dcaid_from_pcidev(pdev);
3287bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3297bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (ioatdca->requester_count == ioatdca->max_requesters)
3307bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return -ENODEV;
3317bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3327bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	for (i = 0; i < ioatdca->max_requesters; i++) {
3337bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		if (ioatdca->req_slots[i].pdev == NULL) {
3347bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			/* found an empty slot */
3357bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->requester_count++;
3367bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->req_slots[i].pdev = pdev;
3377bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->req_slots[i].rid = id;
3387bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			global_req_table =
3397bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			      readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
3407bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			writel(id | IOAT_DCA_GREQID_VALID,
3417bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			       ioatdca->iobase + global_req_table + (i * 4));
3427bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			return i;
3437bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		}
3447bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
3457bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* Error, ioatdma->requester_count is out of whack */
3467bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	return -EFAULT;
3477bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson}
3487bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3497bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelsonstatic int ioat2_dca_remove_requester(struct dca_provider *dca,
3507bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson				      struct device *dev)
3517bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson{
3527bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct ioat_dca_priv *ioatdca = dca_priv(dca);
3537bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct pci_dev *pdev;
3547bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int i;
3557bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 global_req_table;
3567bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3577bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* This implementation only supports PCI-Express */
3587bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (dev->bus != &pci_bus_type)
3597bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return -ENODEV;
3607bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	pdev = to_pci_dev(dev);
3617bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3627bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	for (i = 0; i < ioatdca->max_requesters; i++) {
3637bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		if (ioatdca->req_slots[i].pdev == pdev) {
3647bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			global_req_table =
3657bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			      readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
3667bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			writel(0, ioatdca->iobase + global_req_table + (i * 4));
3677bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->req_slots[i].pdev = NULL;
3687bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->req_slots[i].rid = 0;
3697bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->requester_count--;
3707bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			return i;
3717bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		}
3727bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
3737bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	return -ENODEV;
3747bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson}
3757bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3767f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic u8 ioat2_dca_get_tag(struct dca_provider *dca,
3777f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			    struct device *dev,
3787f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			    int cpu)
3797bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson{
3807bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u8 tag;
3817bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3827f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	tag = ioat_dca_get_tag(dca, dev, cpu);
3837bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	tag = (~tag) & 0x1F;
3847bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	return tag;
3857bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson}
3867bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
3877bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelsonstatic struct dca_ops ioat2_dca_ops = {
3887bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	.add_requester		= ioat2_dca_add_requester,
3897bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	.remove_requester	= ioat2_dca_remove_requester,
3907bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	.get_tag		= ioat2_dca_get_tag,
3917f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.dev_managed		= ioat_dca_dev_managed,
3927bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson};
3937bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
39453a0c98e117272125183138aefc6b13b4a5f38a1Al Virostatic int ioat2_dca_count_dca_slots(void __iomem *iobase, u16 dca_offset)
3957bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson{
3967bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int slots = 0;
3977bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u32 req;
3987bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 global_req_table;
3997bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4007bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	global_req_table = readw(iobase + dca_offset + IOAT_DCA_GREQID_OFFSET);
4017bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (global_req_table == 0)
4027bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return 0;
4037bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	do {
4047bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		req = readl(iobase + global_req_table + (slots * sizeof(u32)));
4057bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		slots++;
4067bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	} while ((req & IOAT_DCA_GREQID_LASTID) == 0);
4077bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4087bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	return slots;
4097bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson}
4107bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
411345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsstruct dca_provider * __devinit
412345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
4137bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson{
4147bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct dca_provider *dca;
4157bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	struct ioat_dca_priv *ioatdca;
4167bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int slots;
4177bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int i;
4187bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	int err;
4197bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u32 tag_map;
4207bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 dca_offset;
4217bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 csi_fsb_control;
4227bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u16 pcie_control;
4237bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	u8 bit;
4247bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4257bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (!system_has_dca_enabled(pdev))
4267bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return NULL;
4277bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4287bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET);
4297bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (dca_offset == 0)
4307bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return NULL;
4317bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4327bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	slots = ioat2_dca_count_dca_slots(iobase, dca_offset);
4337bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (slots == 0)
4347bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return NULL;
4357bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4367bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	dca = alloc_dca_provider(&ioat2_dca_ops,
4377bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson				 sizeof(*ioatdca)
4387bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson				      + (sizeof(struct ioat_dca_slot) * slots));
4397bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (!dca)
4407bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return NULL;
4417bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4427bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	ioatdca = dca_priv(dca);
4437bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	ioatdca->iobase = iobase;
4447bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	ioatdca->dca_base = iobase + dca_offset;
4457bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	ioatdca->max_requesters = slots;
4467bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4477bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* some bios might not know to turn these on */
4487bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	csi_fsb_control = readw(ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
4497bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if ((csi_fsb_control & IOAT_FSB_CAP_ENABLE_PREFETCH) == 0) {
4507bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		csi_fsb_control |= IOAT_FSB_CAP_ENABLE_PREFETCH;
4517bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		writew(csi_fsb_control,
4527bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		       ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
4537bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
4547bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	pcie_control = readw(ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
4557bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if ((pcie_control & IOAT_PCI_CAP_ENABLE_MEMWR) == 0) {
4567bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		pcie_control |= IOAT_PCI_CAP_ENABLE_MEMWR;
4577bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		writew(pcie_control,
4587bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		       ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
4597bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
4607bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4617bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4627bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* TODO version, compatibility and configuration checks */
4637bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4647bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	/* copy out the APIC to DCA tag map */
4657bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	tag_map = readl(ioatdca->dca_base + IOAT_APICID_TAG_MAP_OFFSET);
4667bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	for (i = 0; i < 5; i++) {
4677bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		bit = (tag_map >> (4 * i)) & 0x0f;
4687bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		if (bit < 8)
4697bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->tag_map[i] = bit | DCA_TAG_MAP_VALID;
4707bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		else
4717bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson			ioatdca->tag_map[i] = 0;
4727bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
4737bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
47449bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski	if (!dca2_tag_map_valid(ioatdca->tag_map)) {
47549bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, "
47649bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski			"disabling DCA\n");
47749bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		free_dca_provider(dca);
47849bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski		return NULL;
47949bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski	}
48049bc46360d68156ce82b2b1a12badb80078453a0Maciej Sosnowski
4817bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	err = register_dca_provider(dca, &pdev->dev);
4827bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	if (err) {
4837bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		free_dca_provider(dca);
4847bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson		return NULL;
4857bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	}
4867bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson
4877bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson	return dca;
4887bb67c14fd3778504fb77da30ce11582336dfcedShannon Nelson}
4897f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
4907f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev)
4917f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
4927f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct ioat_dca_priv *ioatdca = dca_priv(dca);
4937f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct pci_dev *pdev;
4947f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int i;
4957f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 id;
4967f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 global_req_table;
4977f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
4987f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* This implementation only supports PCI-Express */
4997f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (dev->bus != &pci_bus_type)
5007f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return -ENODEV;
5017f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	pdev = to_pci_dev(dev);
5027f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	id = dcaid_from_pcidev(pdev);
5037f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5047f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (ioatdca->requester_count == ioatdca->max_requesters)
5057f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return -ENODEV;
5067f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5077f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	for (i = 0; i < ioatdca->max_requesters; i++) {
5087f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		if (ioatdca->req_slots[i].pdev == NULL) {
5097f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			/* found an empty slot */
5107f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->requester_count++;
5117f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->req_slots[i].pdev = pdev;
5127f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->req_slots[i].rid = id;
5137f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			global_req_table =
5147f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			      readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET);
5157f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			writel(id | IOAT_DCA_GREQID_VALID,
5167f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			       ioatdca->iobase + global_req_table + (i * 4));
5177f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			return i;
5187f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		}
5197f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
5207f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* Error, ioatdma->requester_count is out of whack */
5217f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return -EFAULT;
5227f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
5237f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5247f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic int ioat3_dca_remove_requester(struct dca_provider *dca,
5257f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski				      struct device *dev)
5267f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
5277f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct ioat_dca_priv *ioatdca = dca_priv(dca);
5287f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct pci_dev *pdev;
5297f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int i;
5307f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 global_req_table;
5317f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5327f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* This implementation only supports PCI-Express */
5337f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (dev->bus != &pci_bus_type)
5347f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return -ENODEV;
5357f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	pdev = to_pci_dev(dev);
5367f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5377f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	for (i = 0; i < ioatdca->max_requesters; i++) {
5387f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		if (ioatdca->req_slots[i].pdev == pdev) {
5397f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			global_req_table =
5407f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			      readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET);
5417f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			writel(0, ioatdca->iobase + global_req_table + (i * 4));
5427f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->req_slots[i].pdev = NULL;
5437f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->req_slots[i].rid = 0;
5447f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			ioatdca->requester_count--;
5457f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			return i;
5467f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		}
5477f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
5487f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return -ENODEV;
5497f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
5507f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5517f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic u8 ioat3_dca_get_tag(struct dca_provider *dca,
5527f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			    struct device *dev,
5537f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			    int cpu)
5547f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
5557f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u8 tag;
5567f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5577f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct ioat_dca_priv *ioatdca = dca_priv(dca);
5587f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int i, apic_id, bit, value;
5597f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u8 entry;
5607f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5617f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	tag = 0;
5627f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	apic_id = cpu_physical_id(cpu);
5637f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5647f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	for (i = 0; i < IOAT_TAG_MAP_LEN; i++) {
5657f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		entry = ioatdca->tag_map[i];
5667f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		if (entry & DCA3_TAG_MAP_BIT_TO_SEL) {
5677f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			bit = entry &
5687f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski				~(DCA3_TAG_MAP_BIT_TO_SEL | DCA3_TAG_MAP_BIT_TO_INV);
5697f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			value = (apic_id & (1 << bit)) ? 1 : 0;
5707f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		} else if (entry & DCA3_TAG_MAP_BIT_TO_INV) {
5717f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			bit = entry & ~DCA3_TAG_MAP_BIT_TO_INV;
5727f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			value = (apic_id & (1 << bit)) ? 0 : 1;
5737f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		} else {
5747f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			value = (entry & DCA3_TAG_MAP_LITERAL_VAL) ? 1 : 0;
5757f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		}
5767f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		tag |= (value << i);
5777f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
5787f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5797f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return tag;
5807f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
5817f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5827f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic struct dca_ops ioat3_dca_ops = {
5837f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.add_requester		= ioat3_dca_add_requester,
5847f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.remove_requester	= ioat3_dca_remove_requester,
5857f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.get_tag		= ioat3_dca_get_tag,
5867f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	.dev_managed		= ioat_dca_dev_managed,
5877f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski};
5887f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5897f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowskistatic int ioat3_dca_count_dca_slots(void *iobase, u16 dca_offset)
5907f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
5917f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int slots = 0;
5927f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u32 req;
5937f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 global_req_table;
5947f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5957f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	global_req_table = readw(iobase + dca_offset + IOAT3_DCA_GREQID_OFFSET);
5967f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (global_req_table == 0)
5977f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return 0;
5987f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
5997f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	do {
6007f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		req = readl(iobase + global_req_table + (slots * sizeof(u32)));
6017f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		slots++;
6027f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	} while ((req & IOAT_DCA_GREQID_LASTID) == 0);
6037f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6047f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return slots;
6057f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
6067f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
607345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsstruct dca_provider * __devinit
608345d852391cf3fdc73f23a9ca522c6e7b5eb5a52Dan Williamsioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
6097f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski{
6107f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct dca_provider *dca;
6117f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	struct ioat_dca_priv *ioatdca;
6127f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int slots;
6137f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int i;
6147f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	int err;
6157f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 dca_offset;
6167f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 csi_fsb_control;
6177f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u16 pcie_control;
6187f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	u8 bit;
6197f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6207f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	union {
6217f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		u64 full;
6227f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		struct {
6237f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			u32 low;
6247f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski			u32 high;
6257f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		};
6267f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	} tag_map;
6277f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6287f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (!system_has_dca_enabled(pdev))
6297f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return NULL;
6307f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6317f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET);
6327f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (dca_offset == 0)
6337f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return NULL;
6347f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6357f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	slots = ioat3_dca_count_dca_slots(iobase, dca_offset);
6367f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (slots == 0)
6377f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return NULL;
6387f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6397f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	dca = alloc_dca_provider(&ioat3_dca_ops,
6407f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski				 sizeof(*ioatdca)
6417f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski				      + (sizeof(struct ioat_dca_slot) * slots));
6427f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (!dca)
6437f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return NULL;
6447f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6457f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	ioatdca = dca_priv(dca);
6467f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	ioatdca->iobase = iobase;
6477f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	ioatdca->dca_base = iobase + dca_offset;
6487f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	ioatdca->max_requesters = slots;
6497f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6507f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* some bios might not know to turn these on */
6517f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	csi_fsb_control = readw(ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET);
6527f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if ((csi_fsb_control & IOAT3_CSI_CONTROL_PREFETCH) == 0) {
6537f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		csi_fsb_control |= IOAT3_CSI_CONTROL_PREFETCH;
6547f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		writew(csi_fsb_control,
6557f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		       ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET);
6567f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
6577f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	pcie_control = readw(ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET);
6587f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if ((pcie_control & IOAT3_PCI_CONTROL_MEMWR) == 0) {
6597f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		pcie_control |= IOAT3_PCI_CONTROL_MEMWR;
6607f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		writew(pcie_control,
6617f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		       ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET);
6627f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
6637f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6647f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6657f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* TODO version, compatibility and configuration checks */
6667f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6677f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	/* copy out the APIC to DCA tag map */
6687f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	tag_map.low =
6697f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_LOW);
6707f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	tag_map.high =
6717f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_HIGH);
6727f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	for (i = 0; i < 8; i++) {
6737f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		bit = tag_map.full >> (8 * i);
6747f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		ioatdca->tag_map[i] = bit & DCA_TAG_MAP_MASK;
6757f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
6767f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6777f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	err = register_dca_provider(dca, &pdev->dev);
6787f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	if (err) {
6797f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		free_dca_provider(dca);
6807f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski		return NULL;
6817f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	}
6827f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski
6837f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski	return dca;
6847f1b358a236ee9c19657a619ac6f2dcabcaa0924Maciej Sosnowski}
685