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