1584ec227SDan Williams /* 2584ec227SDan Williams * Intel I/OAT DMA Linux driver 3584ec227SDan Williams * Copyright(c) 2007 - 2009 Intel Corporation. 4584ec227SDan Williams * 5584ec227SDan Williams * This program is free software; you can redistribute it and/or modify it 6584ec227SDan Williams * under the terms and conditions of the GNU General Public License, 7584ec227SDan Williams * version 2, as published by the Free Software Foundation. 8584ec227SDan Williams * 9584ec227SDan Williams * This program is distributed in the hope that it will be useful, but WITHOUT 10584ec227SDan Williams * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11584ec227SDan Williams * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12584ec227SDan Williams * more details. 13584ec227SDan Williams * 14584ec227SDan Williams * You should have received a copy of the GNU General Public License along with 15584ec227SDan Williams * this program; if not, write to the Free Software Foundation, Inc., 16584ec227SDan Williams * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17584ec227SDan Williams * 18584ec227SDan Williams * The full GNU General Public License is included in this distribution in 19584ec227SDan Williams * the file called "COPYING". 20584ec227SDan Williams * 21584ec227SDan Williams */ 22584ec227SDan Williams 23584ec227SDan Williams #include <linux/kernel.h> 24584ec227SDan Williams #include <linux/pci.h> 25584ec227SDan Williams #include <linux/smp.h> 26584ec227SDan Williams #include <linux/interrupt.h> 27584ec227SDan Williams #include <linux/dca.h> 28584ec227SDan Williams 29584ec227SDan Williams /* either a kernel change is needed, or we need something like this in kernel */ 30584ec227SDan Williams #ifndef CONFIG_SMP 31584ec227SDan Williams #include <asm/smp.h> 32584ec227SDan Williams #undef cpu_physical_id 33584ec227SDan Williams #define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24) 34584ec227SDan Williams #endif 35584ec227SDan Williams 36584ec227SDan Williams #include "dma.h" 37584ec227SDan Williams #include "registers.h" 38584ec227SDan Williams 39584ec227SDan Williams /* 40584ec227SDan Williams * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6 41584ec227SDan Williams * contain the bit number of the APIC ID to map into the DCA tag. If the valid 42584ec227SDan Williams * bit is not set, then the value must be 0 or 1 and defines the bit in the tag. 43584ec227SDan Williams */ 44584ec227SDan Williams #define DCA_TAG_MAP_VALID 0x80 45584ec227SDan Williams 46584ec227SDan Williams #define DCA3_TAG_MAP_BIT_TO_INV 0x80 47584ec227SDan Williams #define DCA3_TAG_MAP_BIT_TO_SEL 0x40 48584ec227SDan Williams #define DCA3_TAG_MAP_LITERAL_VAL 0x1 49584ec227SDan Williams 50584ec227SDan Williams #define DCA_TAG_MAP_MASK 0xDF 51584ec227SDan Williams 52584ec227SDan Williams /* expected tag map bytes for I/OAT ver.2 */ 53584ec227SDan Williams #define DCA2_TAG_MAP_BYTE0 0x80 54584ec227SDan Williams #define DCA2_TAG_MAP_BYTE1 0x0 55584ec227SDan Williams #define DCA2_TAG_MAP_BYTE2 0x81 56584ec227SDan Williams #define DCA2_TAG_MAP_BYTE3 0x82 57584ec227SDan Williams #define DCA2_TAG_MAP_BYTE4 0x82 58584ec227SDan Williams 59584ec227SDan Williams /* verify if tag map matches expected values */ 60584ec227SDan Williams static inline int dca2_tag_map_valid(u8 *tag_map) 61584ec227SDan Williams { 62584ec227SDan Williams return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) && 63584ec227SDan Williams (tag_map[1] == DCA2_TAG_MAP_BYTE1) && 64584ec227SDan Williams (tag_map[2] == DCA2_TAG_MAP_BYTE2) && 65584ec227SDan Williams (tag_map[3] == DCA2_TAG_MAP_BYTE3) && 66584ec227SDan Williams (tag_map[4] == DCA2_TAG_MAP_BYTE4)); 67584ec227SDan Williams } 68584ec227SDan Williams 69584ec227SDan Williams /* 70584ec227SDan Williams * "Legacy" DCA systems do not implement the DCA register set in the 71584ec227SDan Williams * I/OAT device. Software needs direct support for their tag mappings. 72584ec227SDan Williams */ 73584ec227SDan Williams 74584ec227SDan Williams #define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x)) 75584ec227SDan Williams #define IOAT_TAG_MAP_LEN 8 76584ec227SDan Williams 77584ec227SDan Williams static u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = { 78584ec227SDan Williams 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; 79584ec227SDan Williams static u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = { 80584ec227SDan Williams 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; 81584ec227SDan Williams static u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = { 82584ec227SDan Williams 1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), }; 83584ec227SDan Williams static u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 }; 84584ec227SDan Williams 85584ec227SDan Williams /* pack PCI B/D/F into a u16 */ 86584ec227SDan Williams static inline u16 dcaid_from_pcidev(struct pci_dev *pci) 87584ec227SDan Williams { 88584ec227SDan Williams return (pci->bus->number << 8) | pci->devfn; 89584ec227SDan Williams } 90584ec227SDan Williams 91584ec227SDan Williams static int dca_enabled_in_bios(struct pci_dev *pdev) 92584ec227SDan Williams { 93584ec227SDan Williams /* CPUID level 9 returns DCA configuration */ 94584ec227SDan Williams /* Bit 0 indicates DCA enabled by the BIOS */ 95584ec227SDan Williams unsigned long cpuid_level_9; 96584ec227SDan Williams int res; 97584ec227SDan Williams 98584ec227SDan Williams cpuid_level_9 = cpuid_eax(9); 99584ec227SDan Williams res = test_bit(0, &cpuid_level_9); 100584ec227SDan Williams if (!res) 101e22dde99SDan Williams dev_dbg(&pdev->dev, "DCA is disabled in BIOS\n"); 102584ec227SDan Williams 103584ec227SDan Williams return res; 104584ec227SDan Williams } 105584ec227SDan Williams 106*228c4f5cSDan Williams int system_has_dca_enabled(struct pci_dev *pdev) 107584ec227SDan Williams { 108584ec227SDan Williams if (boot_cpu_has(X86_FEATURE_DCA)) 109584ec227SDan Williams return dca_enabled_in_bios(pdev); 110584ec227SDan Williams 111e22dde99SDan Williams dev_dbg(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n"); 112584ec227SDan Williams return 0; 113584ec227SDan Williams } 114584ec227SDan Williams 115584ec227SDan Williams struct ioat_dca_slot { 116584ec227SDan Williams struct pci_dev *pdev; /* requester device */ 117584ec227SDan Williams u16 rid; /* requester id, as used by IOAT */ 118584ec227SDan Williams }; 119584ec227SDan Williams 120584ec227SDan Williams #define IOAT_DCA_MAX_REQ 6 121584ec227SDan Williams #define IOAT3_DCA_MAX_REQ 2 122584ec227SDan Williams 123584ec227SDan Williams struct ioat_dca_priv { 124584ec227SDan Williams void __iomem *iobase; 125584ec227SDan Williams void __iomem *dca_base; 126584ec227SDan Williams int max_requesters; 127584ec227SDan Williams int requester_count; 128584ec227SDan Williams u8 tag_map[IOAT_TAG_MAP_LEN]; 129584ec227SDan Williams struct ioat_dca_slot req_slots[0]; 130584ec227SDan Williams }; 131584ec227SDan Williams 132584ec227SDan Williams /* 5000 series chipset DCA Port Requester ID Table Entry Format 133584ec227SDan Williams * [15:8] PCI-Express Bus Number 134584ec227SDan Williams * [7:3] PCI-Express Device Number 135584ec227SDan Williams * [2:0] PCI-Express Function Number 136584ec227SDan Williams * 137584ec227SDan Williams * 5000 series chipset DCA control register format 138584ec227SDan Williams * [7:1] Reserved (0) 139584ec227SDan Williams * [0] Ignore Function Number 140584ec227SDan Williams */ 141584ec227SDan Williams 142584ec227SDan Williams static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) 143584ec227SDan Williams { 144584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 145584ec227SDan Williams struct pci_dev *pdev; 146584ec227SDan Williams int i; 147584ec227SDan Williams u16 id; 148584ec227SDan Williams 149584ec227SDan Williams /* This implementation only supports PCI-Express */ 150584ec227SDan Williams if (dev->bus != &pci_bus_type) 151584ec227SDan Williams return -ENODEV; 152584ec227SDan Williams pdev = to_pci_dev(dev); 153584ec227SDan Williams id = dcaid_from_pcidev(pdev); 154584ec227SDan Williams 155584ec227SDan Williams if (ioatdca->requester_count == ioatdca->max_requesters) 156584ec227SDan Williams return -ENODEV; 157584ec227SDan Williams 158584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 159584ec227SDan Williams if (ioatdca->req_slots[i].pdev == NULL) { 160584ec227SDan Williams /* found an empty slot */ 161584ec227SDan Williams ioatdca->requester_count++; 162584ec227SDan Williams ioatdca->req_slots[i].pdev = pdev; 163584ec227SDan Williams ioatdca->req_slots[i].rid = id; 164584ec227SDan Williams writew(id, ioatdca->dca_base + (i * 4)); 165584ec227SDan Williams /* make sure the ignore function bit is off */ 166584ec227SDan Williams writeb(0, ioatdca->dca_base + (i * 4) + 2); 167584ec227SDan Williams return i; 168584ec227SDan Williams } 169584ec227SDan Williams } 170584ec227SDan Williams /* Error, ioatdma->requester_count is out of whack */ 171584ec227SDan Williams return -EFAULT; 172584ec227SDan Williams } 173584ec227SDan Williams 174584ec227SDan Williams static int ioat_dca_remove_requester(struct dca_provider *dca, 175584ec227SDan Williams struct device *dev) 176584ec227SDan Williams { 177584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 178584ec227SDan Williams struct pci_dev *pdev; 179584ec227SDan Williams int i; 180584ec227SDan Williams 181584ec227SDan Williams /* This implementation only supports PCI-Express */ 182584ec227SDan Williams if (dev->bus != &pci_bus_type) 183584ec227SDan Williams return -ENODEV; 184584ec227SDan Williams pdev = to_pci_dev(dev); 185584ec227SDan Williams 186584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 187584ec227SDan Williams if (ioatdca->req_slots[i].pdev == pdev) { 188584ec227SDan Williams writew(0, ioatdca->dca_base + (i * 4)); 189584ec227SDan Williams ioatdca->req_slots[i].pdev = NULL; 190584ec227SDan Williams ioatdca->req_slots[i].rid = 0; 191584ec227SDan Williams ioatdca->requester_count--; 192584ec227SDan Williams return i; 193584ec227SDan Williams } 194584ec227SDan Williams } 195584ec227SDan Williams return -ENODEV; 196584ec227SDan Williams } 197584ec227SDan Williams 198584ec227SDan Williams static u8 ioat_dca_get_tag(struct dca_provider *dca, 199584ec227SDan Williams struct device *dev, 200584ec227SDan Williams int cpu) 201584ec227SDan Williams { 202584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 203584ec227SDan Williams int i, apic_id, bit, value; 204584ec227SDan Williams u8 entry, tag; 205584ec227SDan Williams 206584ec227SDan Williams tag = 0; 207584ec227SDan Williams apic_id = cpu_physical_id(cpu); 208584ec227SDan Williams 209584ec227SDan Williams for (i = 0; i < IOAT_TAG_MAP_LEN; i++) { 210584ec227SDan Williams entry = ioatdca->tag_map[i]; 211584ec227SDan Williams if (entry & DCA_TAG_MAP_VALID) { 212584ec227SDan Williams bit = entry & ~DCA_TAG_MAP_VALID; 213584ec227SDan Williams value = (apic_id & (1 << bit)) ? 1 : 0; 214584ec227SDan Williams } else { 215584ec227SDan Williams value = entry ? 1 : 0; 216584ec227SDan Williams } 217584ec227SDan Williams tag |= (value << i); 218584ec227SDan Williams } 219584ec227SDan Williams return tag; 220584ec227SDan Williams } 221584ec227SDan Williams 222584ec227SDan Williams static int ioat_dca_dev_managed(struct dca_provider *dca, 223584ec227SDan Williams struct device *dev) 224584ec227SDan Williams { 225584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 226584ec227SDan Williams struct pci_dev *pdev; 227584ec227SDan Williams int i; 228584ec227SDan Williams 229584ec227SDan Williams pdev = to_pci_dev(dev); 230584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 231584ec227SDan Williams if (ioatdca->req_slots[i].pdev == pdev) 232584ec227SDan Williams return 1; 233584ec227SDan Williams } 234584ec227SDan Williams return 0; 235584ec227SDan Williams } 236584ec227SDan Williams 237584ec227SDan Williams static struct dca_ops ioat_dca_ops = { 238584ec227SDan Williams .add_requester = ioat_dca_add_requester, 239584ec227SDan Williams .remove_requester = ioat_dca_remove_requester, 240584ec227SDan Williams .get_tag = ioat_dca_get_tag, 241584ec227SDan Williams .dev_managed = ioat_dca_dev_managed, 242584ec227SDan Williams }; 243584ec227SDan Williams 244584ec227SDan Williams 245345d8523SDan Williams struct dca_provider * __devinit 246345d8523SDan Williams ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) 247584ec227SDan Williams { 248584ec227SDan Williams struct dca_provider *dca; 249584ec227SDan Williams struct ioat_dca_priv *ioatdca; 250584ec227SDan Williams u8 *tag_map = NULL; 251584ec227SDan Williams int i; 252584ec227SDan Williams int err; 253584ec227SDan Williams u8 version; 254584ec227SDan Williams u8 max_requesters; 255584ec227SDan Williams 256584ec227SDan Williams if (!system_has_dca_enabled(pdev)) 257584ec227SDan Williams return NULL; 258584ec227SDan Williams 259584ec227SDan Williams /* I/OAT v1 systems must have a known tag_map to support DCA */ 260584ec227SDan Williams switch (pdev->vendor) { 261584ec227SDan Williams case PCI_VENDOR_ID_INTEL: 262584ec227SDan Williams switch (pdev->device) { 263584ec227SDan Williams case PCI_DEVICE_ID_INTEL_IOAT: 264584ec227SDan Williams tag_map = ioat_tag_map_BNB; 265584ec227SDan Williams break; 266584ec227SDan Williams case PCI_DEVICE_ID_INTEL_IOAT_CNB: 267584ec227SDan Williams tag_map = ioat_tag_map_CNB; 268584ec227SDan Williams break; 269584ec227SDan Williams case PCI_DEVICE_ID_INTEL_IOAT_SCNB: 270584ec227SDan Williams tag_map = ioat_tag_map_SCNB; 271584ec227SDan Williams break; 272584ec227SDan Williams } 273584ec227SDan Williams break; 274584ec227SDan Williams case PCI_VENDOR_ID_UNISYS: 275584ec227SDan Williams switch (pdev->device) { 276584ec227SDan Williams case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR: 277584ec227SDan Williams tag_map = ioat_tag_map_UNISYS; 278584ec227SDan Williams break; 279584ec227SDan Williams } 280584ec227SDan Williams break; 281584ec227SDan Williams } 282584ec227SDan Williams if (tag_map == NULL) 283584ec227SDan Williams return NULL; 284584ec227SDan Williams 285584ec227SDan Williams version = readb(iobase + IOAT_VER_OFFSET); 286584ec227SDan Williams if (version == IOAT_VER_3_0) 287584ec227SDan Williams max_requesters = IOAT3_DCA_MAX_REQ; 288584ec227SDan Williams else 289584ec227SDan Williams max_requesters = IOAT_DCA_MAX_REQ; 290584ec227SDan Williams 291584ec227SDan Williams dca = alloc_dca_provider(&ioat_dca_ops, 292584ec227SDan Williams sizeof(*ioatdca) + 293584ec227SDan Williams (sizeof(struct ioat_dca_slot) * max_requesters)); 294584ec227SDan Williams if (!dca) 295584ec227SDan Williams return NULL; 296584ec227SDan Williams 297584ec227SDan Williams ioatdca = dca_priv(dca); 298584ec227SDan Williams ioatdca->max_requesters = max_requesters; 299584ec227SDan Williams ioatdca->dca_base = iobase + 0x54; 300584ec227SDan Williams 301584ec227SDan Williams /* copy over the APIC ID to DCA tag mapping */ 302584ec227SDan Williams for (i = 0; i < IOAT_TAG_MAP_LEN; i++) 303584ec227SDan Williams ioatdca->tag_map[i] = tag_map[i]; 304584ec227SDan Williams 305584ec227SDan Williams err = register_dca_provider(dca, &pdev->dev); 306584ec227SDan Williams if (err) { 307584ec227SDan Williams free_dca_provider(dca); 308584ec227SDan Williams return NULL; 309584ec227SDan Williams } 310584ec227SDan Williams 311584ec227SDan Williams return dca; 312584ec227SDan Williams } 313584ec227SDan Williams 314584ec227SDan Williams 315584ec227SDan Williams static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev) 316584ec227SDan Williams { 317584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 318584ec227SDan Williams struct pci_dev *pdev; 319584ec227SDan Williams int i; 320584ec227SDan Williams u16 id; 321584ec227SDan Williams u16 global_req_table; 322584ec227SDan Williams 323584ec227SDan Williams /* This implementation only supports PCI-Express */ 324584ec227SDan Williams if (dev->bus != &pci_bus_type) 325584ec227SDan Williams return -ENODEV; 326584ec227SDan Williams pdev = to_pci_dev(dev); 327584ec227SDan Williams id = dcaid_from_pcidev(pdev); 328584ec227SDan Williams 329584ec227SDan Williams if (ioatdca->requester_count == ioatdca->max_requesters) 330584ec227SDan Williams return -ENODEV; 331584ec227SDan Williams 332584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 333584ec227SDan Williams if (ioatdca->req_slots[i].pdev == NULL) { 334584ec227SDan Williams /* found an empty slot */ 335584ec227SDan Williams ioatdca->requester_count++; 336584ec227SDan Williams ioatdca->req_slots[i].pdev = pdev; 337584ec227SDan Williams ioatdca->req_slots[i].rid = id; 338584ec227SDan Williams global_req_table = 339584ec227SDan Williams readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET); 340584ec227SDan Williams writel(id | IOAT_DCA_GREQID_VALID, 341584ec227SDan Williams ioatdca->iobase + global_req_table + (i * 4)); 342584ec227SDan Williams return i; 343584ec227SDan Williams } 344584ec227SDan Williams } 345584ec227SDan Williams /* Error, ioatdma->requester_count is out of whack */ 346584ec227SDan Williams return -EFAULT; 347584ec227SDan Williams } 348584ec227SDan Williams 349584ec227SDan Williams static int ioat2_dca_remove_requester(struct dca_provider *dca, 350584ec227SDan Williams struct device *dev) 351584ec227SDan Williams { 352584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 353584ec227SDan Williams struct pci_dev *pdev; 354584ec227SDan Williams int i; 355584ec227SDan Williams u16 global_req_table; 356584ec227SDan Williams 357584ec227SDan Williams /* This implementation only supports PCI-Express */ 358584ec227SDan Williams if (dev->bus != &pci_bus_type) 359584ec227SDan Williams return -ENODEV; 360584ec227SDan Williams pdev = to_pci_dev(dev); 361584ec227SDan Williams 362584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 363584ec227SDan Williams if (ioatdca->req_slots[i].pdev == pdev) { 364584ec227SDan Williams global_req_table = 365584ec227SDan Williams readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET); 366584ec227SDan Williams writel(0, ioatdca->iobase + global_req_table + (i * 4)); 367584ec227SDan Williams ioatdca->req_slots[i].pdev = NULL; 368584ec227SDan Williams ioatdca->req_slots[i].rid = 0; 369584ec227SDan Williams ioatdca->requester_count--; 370584ec227SDan Williams return i; 371584ec227SDan Williams } 372584ec227SDan Williams } 373584ec227SDan Williams return -ENODEV; 374584ec227SDan Williams } 375584ec227SDan Williams 376584ec227SDan Williams static u8 ioat2_dca_get_tag(struct dca_provider *dca, 377584ec227SDan Williams struct device *dev, 378584ec227SDan Williams int cpu) 379584ec227SDan Williams { 380584ec227SDan Williams u8 tag; 381584ec227SDan Williams 382584ec227SDan Williams tag = ioat_dca_get_tag(dca, dev, cpu); 383584ec227SDan Williams tag = (~tag) & 0x1F; 384584ec227SDan Williams return tag; 385584ec227SDan Williams } 386584ec227SDan Williams 387584ec227SDan Williams static struct dca_ops ioat2_dca_ops = { 388584ec227SDan Williams .add_requester = ioat2_dca_add_requester, 389584ec227SDan Williams .remove_requester = ioat2_dca_remove_requester, 390584ec227SDan Williams .get_tag = ioat2_dca_get_tag, 391584ec227SDan Williams .dev_managed = ioat_dca_dev_managed, 392584ec227SDan Williams }; 393584ec227SDan Williams 394584ec227SDan Williams static int ioat2_dca_count_dca_slots(void __iomem *iobase, u16 dca_offset) 395584ec227SDan Williams { 396584ec227SDan Williams int slots = 0; 397584ec227SDan Williams u32 req; 398584ec227SDan Williams u16 global_req_table; 399584ec227SDan Williams 400584ec227SDan Williams global_req_table = readw(iobase + dca_offset + IOAT_DCA_GREQID_OFFSET); 401584ec227SDan Williams if (global_req_table == 0) 402584ec227SDan Williams return 0; 403584ec227SDan Williams do { 404584ec227SDan Williams req = readl(iobase + global_req_table + (slots * sizeof(u32))); 405584ec227SDan Williams slots++; 406584ec227SDan Williams } while ((req & IOAT_DCA_GREQID_LASTID) == 0); 407584ec227SDan Williams 408584ec227SDan Williams return slots; 409584ec227SDan Williams } 410584ec227SDan Williams 411345d8523SDan Williams struct dca_provider * __devinit 412345d8523SDan Williams ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase) 413584ec227SDan Williams { 414584ec227SDan Williams struct dca_provider *dca; 415584ec227SDan Williams struct ioat_dca_priv *ioatdca; 416584ec227SDan Williams int slots; 417584ec227SDan Williams int i; 418584ec227SDan Williams int err; 419584ec227SDan Williams u32 tag_map; 420584ec227SDan Williams u16 dca_offset; 421584ec227SDan Williams u16 csi_fsb_control; 422584ec227SDan Williams u16 pcie_control; 423584ec227SDan Williams u8 bit; 424584ec227SDan Williams 425584ec227SDan Williams if (!system_has_dca_enabled(pdev)) 426584ec227SDan Williams return NULL; 427584ec227SDan Williams 428584ec227SDan Williams dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET); 429584ec227SDan Williams if (dca_offset == 0) 430584ec227SDan Williams return NULL; 431584ec227SDan Williams 432584ec227SDan Williams slots = ioat2_dca_count_dca_slots(iobase, dca_offset); 433584ec227SDan Williams if (slots == 0) 434584ec227SDan Williams return NULL; 435584ec227SDan Williams 436584ec227SDan Williams dca = alloc_dca_provider(&ioat2_dca_ops, 437584ec227SDan Williams sizeof(*ioatdca) 438584ec227SDan Williams + (sizeof(struct ioat_dca_slot) * slots)); 439584ec227SDan Williams if (!dca) 440584ec227SDan Williams return NULL; 441584ec227SDan Williams 442584ec227SDan Williams ioatdca = dca_priv(dca); 443584ec227SDan Williams ioatdca->iobase = iobase; 444584ec227SDan Williams ioatdca->dca_base = iobase + dca_offset; 445584ec227SDan Williams ioatdca->max_requesters = slots; 446584ec227SDan Williams 447584ec227SDan Williams /* some bios might not know to turn these on */ 448584ec227SDan Williams csi_fsb_control = readw(ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET); 449584ec227SDan Williams if ((csi_fsb_control & IOAT_FSB_CAP_ENABLE_PREFETCH) == 0) { 450584ec227SDan Williams csi_fsb_control |= IOAT_FSB_CAP_ENABLE_PREFETCH; 451584ec227SDan Williams writew(csi_fsb_control, 452584ec227SDan Williams ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET); 453584ec227SDan Williams } 454584ec227SDan Williams pcie_control = readw(ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET); 455584ec227SDan Williams if ((pcie_control & IOAT_PCI_CAP_ENABLE_MEMWR) == 0) { 456584ec227SDan Williams pcie_control |= IOAT_PCI_CAP_ENABLE_MEMWR; 457584ec227SDan Williams writew(pcie_control, 458584ec227SDan Williams ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET); 459584ec227SDan Williams } 460584ec227SDan Williams 461584ec227SDan Williams 462584ec227SDan Williams /* TODO version, compatibility and configuration checks */ 463584ec227SDan Williams 464584ec227SDan Williams /* copy out the APIC to DCA tag map */ 465584ec227SDan Williams tag_map = readl(ioatdca->dca_base + IOAT_APICID_TAG_MAP_OFFSET); 466584ec227SDan Williams for (i = 0; i < 5; i++) { 467584ec227SDan Williams bit = (tag_map >> (4 * i)) & 0x0f; 468584ec227SDan Williams if (bit < 8) 469584ec227SDan Williams ioatdca->tag_map[i] = bit | DCA_TAG_MAP_VALID; 470584ec227SDan Williams else 471584ec227SDan Williams ioatdca->tag_map[i] = 0; 472584ec227SDan Williams } 473584ec227SDan Williams 474584ec227SDan Williams if (!dca2_tag_map_valid(ioatdca->tag_map)) { 475584ec227SDan Williams dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, " 476584ec227SDan Williams "disabling DCA\n"); 477584ec227SDan Williams free_dca_provider(dca); 478584ec227SDan Williams return NULL; 479584ec227SDan Williams } 480584ec227SDan Williams 481584ec227SDan Williams err = register_dca_provider(dca, &pdev->dev); 482584ec227SDan Williams if (err) { 483584ec227SDan Williams free_dca_provider(dca); 484584ec227SDan Williams return NULL; 485584ec227SDan Williams } 486584ec227SDan Williams 487584ec227SDan Williams return dca; 488584ec227SDan Williams } 489584ec227SDan Williams 490584ec227SDan Williams static int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev) 491584ec227SDan Williams { 492584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 493584ec227SDan Williams struct pci_dev *pdev; 494584ec227SDan Williams int i; 495584ec227SDan Williams u16 id; 496584ec227SDan Williams u16 global_req_table; 497584ec227SDan Williams 498584ec227SDan Williams /* This implementation only supports PCI-Express */ 499584ec227SDan Williams if (dev->bus != &pci_bus_type) 500584ec227SDan Williams return -ENODEV; 501584ec227SDan Williams pdev = to_pci_dev(dev); 502584ec227SDan Williams id = dcaid_from_pcidev(pdev); 503584ec227SDan Williams 504584ec227SDan Williams if (ioatdca->requester_count == ioatdca->max_requesters) 505584ec227SDan Williams return -ENODEV; 506584ec227SDan Williams 507584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 508584ec227SDan Williams if (ioatdca->req_slots[i].pdev == NULL) { 509584ec227SDan Williams /* found an empty slot */ 510584ec227SDan Williams ioatdca->requester_count++; 511584ec227SDan Williams ioatdca->req_slots[i].pdev = pdev; 512584ec227SDan Williams ioatdca->req_slots[i].rid = id; 513584ec227SDan Williams global_req_table = 514584ec227SDan Williams readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET); 515584ec227SDan Williams writel(id | IOAT_DCA_GREQID_VALID, 516584ec227SDan Williams ioatdca->iobase + global_req_table + (i * 4)); 517584ec227SDan Williams return i; 518584ec227SDan Williams } 519584ec227SDan Williams } 520584ec227SDan Williams /* Error, ioatdma->requester_count is out of whack */ 521584ec227SDan Williams return -EFAULT; 522584ec227SDan Williams } 523584ec227SDan Williams 524584ec227SDan Williams static int ioat3_dca_remove_requester(struct dca_provider *dca, 525584ec227SDan Williams struct device *dev) 526584ec227SDan Williams { 527584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 528584ec227SDan Williams struct pci_dev *pdev; 529584ec227SDan Williams int i; 530584ec227SDan Williams u16 global_req_table; 531584ec227SDan Williams 532584ec227SDan Williams /* This implementation only supports PCI-Express */ 533584ec227SDan Williams if (dev->bus != &pci_bus_type) 534584ec227SDan Williams return -ENODEV; 535584ec227SDan Williams pdev = to_pci_dev(dev); 536584ec227SDan Williams 537584ec227SDan Williams for (i = 0; i < ioatdca->max_requesters; i++) { 538584ec227SDan Williams if (ioatdca->req_slots[i].pdev == pdev) { 539584ec227SDan Williams global_req_table = 540584ec227SDan Williams readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET); 541584ec227SDan Williams writel(0, ioatdca->iobase + global_req_table + (i * 4)); 542584ec227SDan Williams ioatdca->req_slots[i].pdev = NULL; 543584ec227SDan Williams ioatdca->req_slots[i].rid = 0; 544584ec227SDan Williams ioatdca->requester_count--; 545584ec227SDan Williams return i; 546584ec227SDan Williams } 547584ec227SDan Williams } 548584ec227SDan Williams return -ENODEV; 549584ec227SDan Williams } 550584ec227SDan Williams 551584ec227SDan Williams static u8 ioat3_dca_get_tag(struct dca_provider *dca, 552584ec227SDan Williams struct device *dev, 553584ec227SDan Williams int cpu) 554584ec227SDan Williams { 555584ec227SDan Williams u8 tag; 556584ec227SDan Williams 557584ec227SDan Williams struct ioat_dca_priv *ioatdca = dca_priv(dca); 558584ec227SDan Williams int i, apic_id, bit, value; 559584ec227SDan Williams u8 entry; 560584ec227SDan Williams 561584ec227SDan Williams tag = 0; 562584ec227SDan Williams apic_id = cpu_physical_id(cpu); 563584ec227SDan Williams 564584ec227SDan Williams for (i = 0; i < IOAT_TAG_MAP_LEN; i++) { 565584ec227SDan Williams entry = ioatdca->tag_map[i]; 566584ec227SDan Williams if (entry & DCA3_TAG_MAP_BIT_TO_SEL) { 567584ec227SDan Williams bit = entry & 568584ec227SDan Williams ~(DCA3_TAG_MAP_BIT_TO_SEL | DCA3_TAG_MAP_BIT_TO_INV); 569584ec227SDan Williams value = (apic_id & (1 << bit)) ? 1 : 0; 570584ec227SDan Williams } else if (entry & DCA3_TAG_MAP_BIT_TO_INV) { 571584ec227SDan Williams bit = entry & ~DCA3_TAG_MAP_BIT_TO_INV; 572584ec227SDan Williams value = (apic_id & (1 << bit)) ? 0 : 1; 573584ec227SDan Williams } else { 574584ec227SDan Williams value = (entry & DCA3_TAG_MAP_LITERAL_VAL) ? 1 : 0; 575584ec227SDan Williams } 576584ec227SDan Williams tag |= (value << i); 577584ec227SDan Williams } 578584ec227SDan Williams 579584ec227SDan Williams return tag; 580584ec227SDan Williams } 581584ec227SDan Williams 582584ec227SDan Williams static struct dca_ops ioat3_dca_ops = { 583584ec227SDan Williams .add_requester = ioat3_dca_add_requester, 584584ec227SDan Williams .remove_requester = ioat3_dca_remove_requester, 585584ec227SDan Williams .get_tag = ioat3_dca_get_tag, 586584ec227SDan Williams .dev_managed = ioat_dca_dev_managed, 587584ec227SDan Williams }; 588584ec227SDan Williams 589584ec227SDan Williams static int ioat3_dca_count_dca_slots(void *iobase, u16 dca_offset) 590584ec227SDan Williams { 591584ec227SDan Williams int slots = 0; 592584ec227SDan Williams u32 req; 593584ec227SDan Williams u16 global_req_table; 594584ec227SDan Williams 595584ec227SDan Williams global_req_table = readw(iobase + dca_offset + IOAT3_DCA_GREQID_OFFSET); 596584ec227SDan Williams if (global_req_table == 0) 597584ec227SDan Williams return 0; 598584ec227SDan Williams 599584ec227SDan Williams do { 600584ec227SDan Williams req = readl(iobase + global_req_table + (slots * sizeof(u32))); 601584ec227SDan Williams slots++; 602584ec227SDan Williams } while ((req & IOAT_DCA_GREQID_LASTID) == 0); 603584ec227SDan Williams 604584ec227SDan Williams return slots; 605584ec227SDan Williams } 606584ec227SDan Williams 607345d8523SDan Williams struct dca_provider * __devinit 608345d8523SDan Williams ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase) 609584ec227SDan Williams { 610584ec227SDan Williams struct dca_provider *dca; 611584ec227SDan Williams struct ioat_dca_priv *ioatdca; 612584ec227SDan Williams int slots; 613584ec227SDan Williams int i; 614584ec227SDan Williams int err; 615584ec227SDan Williams u16 dca_offset; 616584ec227SDan Williams u16 csi_fsb_control; 617584ec227SDan Williams u16 pcie_control; 618584ec227SDan Williams u8 bit; 619584ec227SDan Williams 620584ec227SDan Williams union { 621584ec227SDan Williams u64 full; 622584ec227SDan Williams struct { 623584ec227SDan Williams u32 low; 624584ec227SDan Williams u32 high; 625584ec227SDan Williams }; 626584ec227SDan Williams } tag_map; 627584ec227SDan Williams 628584ec227SDan Williams if (!system_has_dca_enabled(pdev)) 629584ec227SDan Williams return NULL; 630584ec227SDan Williams 631584ec227SDan Williams dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET); 632584ec227SDan Williams if (dca_offset == 0) 633584ec227SDan Williams return NULL; 634584ec227SDan Williams 635584ec227SDan Williams slots = ioat3_dca_count_dca_slots(iobase, dca_offset); 636584ec227SDan Williams if (slots == 0) 637584ec227SDan Williams return NULL; 638584ec227SDan Williams 639584ec227SDan Williams dca = alloc_dca_provider(&ioat3_dca_ops, 640584ec227SDan Williams sizeof(*ioatdca) 641584ec227SDan Williams + (sizeof(struct ioat_dca_slot) * slots)); 642584ec227SDan Williams if (!dca) 643584ec227SDan Williams return NULL; 644584ec227SDan Williams 645584ec227SDan Williams ioatdca = dca_priv(dca); 646584ec227SDan Williams ioatdca->iobase = iobase; 647584ec227SDan Williams ioatdca->dca_base = iobase + dca_offset; 648584ec227SDan Williams ioatdca->max_requesters = slots; 649584ec227SDan Williams 650584ec227SDan Williams /* some bios might not know to turn these on */ 651584ec227SDan Williams csi_fsb_control = readw(ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET); 652584ec227SDan Williams if ((csi_fsb_control & IOAT3_CSI_CONTROL_PREFETCH) == 0) { 653584ec227SDan Williams csi_fsb_control |= IOAT3_CSI_CONTROL_PREFETCH; 654584ec227SDan Williams writew(csi_fsb_control, 655584ec227SDan Williams ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET); 656584ec227SDan Williams } 657584ec227SDan Williams pcie_control = readw(ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET); 658584ec227SDan Williams if ((pcie_control & IOAT3_PCI_CONTROL_MEMWR) == 0) { 659584ec227SDan Williams pcie_control |= IOAT3_PCI_CONTROL_MEMWR; 660584ec227SDan Williams writew(pcie_control, 661584ec227SDan Williams ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET); 662584ec227SDan Williams } 663584ec227SDan Williams 664584ec227SDan Williams 665584ec227SDan Williams /* TODO version, compatibility and configuration checks */ 666584ec227SDan Williams 667584ec227SDan Williams /* copy out the APIC to DCA tag map */ 668584ec227SDan Williams tag_map.low = 669584ec227SDan Williams readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_LOW); 670584ec227SDan Williams tag_map.high = 671584ec227SDan Williams readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_HIGH); 672584ec227SDan Williams for (i = 0; i < 8; i++) { 673584ec227SDan Williams bit = tag_map.full >> (8 * i); 674584ec227SDan Williams ioatdca->tag_map[i] = bit & DCA_TAG_MAP_MASK; 675584ec227SDan Williams } 676584ec227SDan Williams 677584ec227SDan Williams err = register_dca_provider(dca, &pdev->dev); 678584ec227SDan Williams if (err) { 679584ec227SDan Williams free_dca_provider(dca); 680584ec227SDan Williams return NULL; 681584ec227SDan Williams } 682584ec227SDan Williams 683584ec227SDan Williams return dca; 684584ec227SDan Williams } 685