110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S/* 210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * Copyright (c) 2006, Intel Corporation. 310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * 410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * This program is free software; you can redistribute it and/or modify it 510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * under the terms and conditions of the GNU General Public License, 610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * version 2, as published by the Free Software Foundation. 710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * 810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * This program is distributed in the hope it will be useful, but WITHOUT 910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * more details. 1210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * 1310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * You should have received a copy of the GNU General Public License along with 1410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 1510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * Place - Suite 330, Boston, MA 02111-1307 USA. 1610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * 1798bcef56cadb4da138e2c1a2a0790f372382b236mark gross * Copyright (C) 2006-2008 Intel Corporation 1898bcef56cadb4da138e2c1a2a0790f372382b236mark gross * Author: Ashok Raj <ashok.raj@intel.com> 1998bcef56cadb4da138e2c1a2a0790f372382b236mark gross * Author: Shaohua Li <shaohua.li@intel.com> 2098bcef56cadb4da138e2c1a2a0790f372382b236mark gross * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> 2110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * 22e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha * This file implements early detection/parsing of Remapping Devices 2310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI 2410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * tables. 25e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha * 26e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha * These routines are used by both DMA-remapping and Interrupt-remapping 2710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 2810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 2910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S#include <linux/pci.h> 3010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S#include <linux/dmar.h> 31387179464257921eb9aa3d15cc3ff194f6945a7cKay, Allen M#include <linux/iova.h> 32387179464257921eb9aa3d15cc3ff194f6945a7cKay, Allen M#include <linux/intel-iommu.h> 33fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha#include <linux/timer.h> 340ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha#include <linux/irq.h> 350ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha#include <linux/interrupt.h> 3669575d388603365f2afbf4166df93152df59b165Shane Wang#include <linux/tboot.h> 37eb27cae8adaa658a0bf31631baa1ce29d8183759Len Brown#include <linux/dmi.h> 385a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 394db77ff3237a88ea74f691dd776e92b2f86a8f3fKonrad Rzeszutek Wilk#include <asm/iommu_table.h> 4010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 41a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "DMAR: " 4210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 4310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S/* No locks are needed as DMA remapping hardware unit 4410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * list is constructed at boot time and hotplug of 4510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * these units are not supported by the architecture. 4610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 4710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil SLIST_HEAD(dmar_drhd_units); 4810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 4941750d31fc9599fd81763e685a6b7b42d298c4f8Suresh Siddhastruct acpi_table_header * __initdata dmar_tbl; 508e1568f3500287d0b36c9776132cb53a42d5651dYinghai Lustatic acpi_size dmar_tbl_size; 5110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 5210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sstatic void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) 5310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 5410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S /* 5510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * add INCLUDE_ALL at the tail, so scan the list will find it at 5610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * the very end. 5710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 5810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (drhd->include_all) 5910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S list_add_tail(&drhd->list, &dmar_drhd_units); 6010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S else 6110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S list_add(&drhd->list, &dmar_drhd_units); 6210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 6310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 6410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sstatic int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, 6510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct pci_dev **dev, u16 segment) 6610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 6710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct pci_bus *bus; 6810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct pci_dev *pdev = NULL; 6910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_pci_path *path; 7010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S int count; 7110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 7210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S bus = pci_find_bus(segment, scope->bus); 7310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S path = (struct acpi_dmar_pci_path *)(scope + 1); 7410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S count = (scope->length - sizeof(struct acpi_dmar_device_scope)) 7510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S / sizeof(struct acpi_dmar_pci_path); 7610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 7710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S while (count) { 7810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (pdev) 7910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S pci_dev_put(pdev); 8010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S /* 8110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * Some BIOSes list non-exist devices in DMAR table, just 8210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * ignore it 8310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 8410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!bus) { 8510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING 8610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S PREFIX "Device scope bus [%d] not found\n", 8710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S scope->bus); 8810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 8910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 9010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn)); 9110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!pdev) { 9210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING PREFIX 9310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S "Device scope device [%04x:%02x:%02x.%02x] not found\n", 9410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S segment, bus->number, path->dev, path->fn); 9510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 9610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 9710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S path ++; 9810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S count --; 9910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S bus = pdev->subordinate; 10010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 10110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!pdev) { 10210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING PREFIX 10310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S "Device scope device [%04x:%02x:%02x.%02x] not found\n", 10410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S segment, scope->bus, path->dev, path->fn); 10510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S *dev = NULL; 10610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return 0; 10710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 10810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \ 10910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S pdev->subordinate) || (scope->entry_type == \ 11010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) { 11110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S pci_dev_put(pdev); 11210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING PREFIX 11310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S "Device scope type does not match for %s\n", 11410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S pci_name(pdev)); 11510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -EINVAL; 11610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 11710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S *dev = pdev; 11810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return 0; 11910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 12010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 121318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddhaint __init dmar_parse_dev_scope(void *start, void *end, int *cnt, 122318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha struct pci_dev ***devices, u16 segment) 12310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 12410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_device_scope *scope; 12510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S void * tmp = start; 12610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S int index; 12710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S int ret; 12810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 12910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S *cnt = 0; 13010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S while (start < end) { 13110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S scope = start; 13210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || 13310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) 13410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S (*cnt)++; 1355715f0f9d3814e83e5f2f754d3f7abdfa096a0b9Yinghai Lu else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) { 13610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING PREFIX 1375715f0f9d3814e83e5f2f754d3f7abdfa096a0b9Yinghai Lu "Unsupported device scope\n"); 1385715f0f9d3814e83e5f2f754d3f7abdfa096a0b9Yinghai Lu } 13910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S start += scope->length; 14010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 14110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (*cnt == 0) 14210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return 0; 14310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 14410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); 14510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!*devices) 14610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -ENOMEM; 14710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 14810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S start = tmp; 14910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S index = 0; 15010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S while (start < end) { 15110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S scope = start; 15210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || 15310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) { 15410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S ret = dmar_parse_one_dev_scope(scope, 15510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S &(*devices)[index], segment); 15610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (ret) { 15710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S kfree(*devices); 15810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return ret; 15910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 16010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S index ++; 16110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 16210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S start += scope->length; 16310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 16410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 16510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return 0; 16610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 16710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 16810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S/** 16910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition 17010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * structure which uniquely represent one DMA remapping hardware unit 17110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * present in the platform 17210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 17310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sstatic int __init 17410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sdmar_parse_one_drhd(struct acpi_dmar_header *header) 17510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 17610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_hardware_unit *drhd; 17710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct dmar_drhd_unit *dmaru; 17810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S int ret = 0; 17910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 180e523b38e2f568af58baa13120a994cbf24e6dee0David Woodhouse drhd = (struct acpi_dmar_hardware_unit *)header; 18110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); 18210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!dmaru) 18310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -ENOMEM; 18410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 1851886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha dmaru->hdr = header; 18610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmaru->reg_base_addr = drhd->address; 187276dbf997043cbf38f0087624e0f9c51742c8885David Woodhouse dmaru->segment = drhd->segment; 18810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ 18910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 1901886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha ret = alloc_iommu(dmaru); 1911886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha if (ret) { 1921886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha kfree(dmaru); 1931886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return ret; 1941886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha } 1951886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha dmar_register_drhd_unit(dmaru); 1961886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return 0; 1971886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha} 1981886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 199f82851a8a480a26611175f064f54e17f5f7b01aeDavid Woodhousestatic int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) 2001886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha{ 2011886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha struct acpi_dmar_hardware_unit *drhd; 202f82851a8a480a26611175f064f54e17f5f7b01aeDavid Woodhouse int ret = 0; 2031886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 2041886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; 2051886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 2062e824f79240476d57a8589f46232cabf151efe90Yu Zhao if (dmaru->include_all) 2072e824f79240476d57a8589f46232cabf151efe90Yu Zhao return 0; 2082e824f79240476d57a8589f46232cabf151efe90Yu Zhao 2092e824f79240476d57a8589f46232cabf151efe90Yu Zhao ret = dmar_parse_dev_scope((void *)(drhd + 1), 2101886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha ((void *)drhd) + drhd->header.length, 21110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S &dmaru->devices_cnt, &dmaru->devices, 21210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S drhd->segment); 2131c7d1bcad218808a4f67a4492a5e1d920e85c239Suresh Siddha if (ret) { 2141886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha list_del(&dmaru->list); 21510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S kfree(dmaru); 2161886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha } 21710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return ret; 21810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 21910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 220aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse#ifdef CONFIG_ACPI_NUMA 221ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddhastatic int __init 222ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddhadmar_parse_one_rhsa(struct acpi_dmar_header *header) 223ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha{ 224ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha struct acpi_dmar_rhsa *rhsa; 225ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha struct dmar_drhd_unit *drhd; 226ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha 227ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha rhsa = (struct acpi_dmar_rhsa *)header; 228aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse for_each_drhd_unit(drhd) { 229ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha if (drhd->reg_base_addr == rhsa->base_address) { 230ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha int node = acpi_map_pxm_to_node(rhsa->proximity_domain); 231ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha 232ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha if (!node_online(node)) 233ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha node = -1; 234ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha drhd->iommu->node = node; 235aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse return 0; 236aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse } 237ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha } 238fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings WARN_TAINT( 239fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings 1, TAINT_FIRMWARE_WORKAROUND, 240fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n" 241fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings "BIOS vendor: %s; Ver: %s; Product Version: %s\n", 242fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings drhd->reg_base_addr, 243fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_BIOS_VENDOR), 244fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_BIOS_VERSION), 245fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_PRODUCT_VERSION)); 246ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha 247aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse return 0; 248ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha} 249aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse#endif 250ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha 25110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sstatic void __init 25210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sdmar_table_print_dmar_entry(struct acpi_dmar_header *header) 25310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 25410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_hardware_unit *drhd; 25510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_reserved_memory *rmrr; 256aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao struct acpi_dmar_atsr *atsr; 25717b6097753e926ca546189463070a7e94e7ea9faRoland Dreier struct acpi_dmar_rhsa *rhsa; 25810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 25910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S switch (header->type) { 26010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S case ACPI_DMAR_TYPE_HARDWARE_UNIT: 261aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao drhd = container_of(header, struct acpi_dmar_hardware_unit, 262aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao header); 26310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk (KERN_INFO PREFIX 264aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao "DRHD base: %#016Lx flags: %#x\n", 265aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao (unsigned long long)drhd->address, drhd->flags); 26610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 26710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S case ACPI_DMAR_TYPE_RESERVED_MEMORY: 268aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao rmrr = container_of(header, struct acpi_dmar_reserved_memory, 269aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao header); 27010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk (KERN_INFO PREFIX 271aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao "RMRR base: %#016Lx end: %#016Lx\n", 2725b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu (unsigned long long)rmrr->base_address, 2735b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu (unsigned long long)rmrr->end_address); 27410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 275aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao case ACPI_DMAR_TYPE_ATSR: 276aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao atsr = container_of(header, struct acpi_dmar_atsr, header); 277aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); 278aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao break; 27917b6097753e926ca546189463070a7e94e7ea9faRoland Dreier case ACPI_DMAR_HARDWARE_AFFINITY: 28017b6097753e926ca546189463070a7e94e7ea9faRoland Dreier rhsa = container_of(header, struct acpi_dmar_rhsa, header); 28117b6097753e926ca546189463070a7e94e7ea9faRoland Dreier printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n", 28217b6097753e926ca546189463070a7e94e7ea9faRoland Dreier (unsigned long long)rhsa->base_address, 28317b6097753e926ca546189463070a7e94e7ea9faRoland Dreier rhsa->proximity_domain); 28417b6097753e926ca546189463070a7e94e7ea9faRoland Dreier break; 28510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 28610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 28710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 288f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu/** 289f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu * dmar_table_detect - checks to see if the platform supports DMAR devices 290f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu */ 291f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lustatic int __init dmar_table_detect(void) 292f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu{ 293f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu acpi_status status = AE_OK; 294f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu 295f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu /* if we could find DMAR table, then there are DMAR devices */ 2968e1568f3500287d0b36c9776132cb53a42d5651dYinghai Lu status = acpi_get_table_with_size(ACPI_SIG_DMAR, 0, 2978e1568f3500287d0b36c9776132cb53a42d5651dYinghai Lu (struct acpi_table_header **)&dmar_tbl, 2988e1568f3500287d0b36c9776132cb53a42d5651dYinghai Lu &dmar_tbl_size); 299f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu 300f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu if (ACPI_SUCCESS(status) && !dmar_tbl) { 301f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu printk (KERN_WARNING PREFIX "Unable to map DMAR\n"); 302f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu status = AE_NOT_FOUND; 303f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu } 304f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu 305f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu return (ACPI_SUCCESS(status) ? 1 : 0); 306f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu} 307aaa9d1dd63bf89b62f4ea9f46de376ab1a3fbc6cSuresh Siddha 30810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S/** 30910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S * parse_dmar_table - parses the DMA reporting table 31010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S */ 31110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sstatic int __init 31210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sparse_dmar_table(void) 31310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 31410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_table_dmar *dmar; 31510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S struct acpi_dmar_header *entry_header; 31610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S int ret = 0; 31710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 318f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu /* 319f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu * Do it again, earlier dmar_tbl mapping could be mapped with 320f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu * fixed map. 321f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu */ 322f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu dmar_table_detect(); 323f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu 324a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula /* 325a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula * ACPI tables may not be DMA protected by tboot, so use DMAR copy 326a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula * SINIT saved in SinitMleData in TXT heap (which is DMA protected) 327a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula */ 328a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula dmar_tbl = tboot_get_dmar_table(dmar_tbl); 329a59b50e995465911ba580df0bd10cf64aa81fc43Joseph Cihula 33010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmar = (struct acpi_table_dmar *)dmar_tbl; 33110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (!dmar) 33210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -ENODEV; 33310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 3345b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu if (dmar->width < PAGE_SHIFT - 1) { 335093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); 33610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -EINVAL; 33710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 33810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 33910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk (KERN_INFO PREFIX "Host address width %d\n", 34010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmar->width + 1); 34110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 34210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S entry_header = (struct acpi_dmar_header *)(dmar + 1); 34310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S while (((unsigned long)entry_header) < 34410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S (((unsigned long)dmar) + dmar_tbl->length)) { 345084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby /* Avoid looping forever on bad ACPI tables */ 346084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby if (entry_header->length == 0) { 347084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby printk(KERN_WARNING PREFIX 348084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby "Invalid 0-length structure\n"); 349084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby ret = -EINVAL; 350084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby break; 351084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby } 352084eb960e81505680a9963665722d1bfd94af6a7Tony Battersby 35310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S dmar_table_print_dmar_entry(entry_header); 35410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 35510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S switch (entry_header->type) { 35610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S case ACPI_DMAR_TYPE_HARDWARE_UNIT: 35710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S ret = dmar_parse_one_drhd(entry_header); 35810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 35910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S case ACPI_DMAR_TYPE_RESERVED_MEMORY: 36010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S ret = dmar_parse_one_rmrr(entry_header); 36110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 362aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao case ACPI_DMAR_TYPE_ATSR: 363aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao ret = dmar_parse_one_atsr(entry_header); 364aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7Yu Zhao break; 36517b6097753e926ca546189463070a7e94e7ea9faRoland Dreier case ACPI_DMAR_HARDWARE_AFFINITY: 366aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse#ifdef CONFIG_ACPI_NUMA 367ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha ret = dmar_parse_one_rhsa(entry_header); 368aa697079ee66315c4b9747a5eb3e48487fb1b8beDavid Woodhouse#endif 36917b6097753e926ca546189463070a7e94e7ea9faRoland Dreier break; 37010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S default: 37110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_WARNING PREFIX 3724de75cf9391b538bbfe7dc0a9782f1ebe8e242adRoland Dreier "Unknown DMAR structure type %d\n", 3734de75cf9391b538bbfe7dc0a9782f1ebe8e242adRoland Dreier entry_header->type); 37410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S ret = 0; /* for forward compatibility */ 37510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 37610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 37710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (ret) 37810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S break; 37910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 38010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S entry_header = ((void *)entry_header + entry_header->length); 38110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 38210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return ret; 38310e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 38410e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 385dda565492776b7dff5f8507298d868745e734aabYinghaistatic int dmar_pci_device_match(struct pci_dev *devices[], int cnt, 386e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha struct pci_dev *dev) 387e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha{ 388e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha int index; 389e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 390e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha while (dev) { 391e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha for (index = 0; index < cnt; index++) 392e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha if (dev == devices[index]) 393e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha return 1; 394e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 395e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha /* Check our parent */ 396e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha dev = dev->bus->self; 397e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha } 398e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 399e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha return 0; 400e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha} 401e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 402e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddhastruct dmar_drhd_unit * 403e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddhadmar_find_matched_drhd_unit(struct pci_dev *dev) 404e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha{ 4052e824f79240476d57a8589f46232cabf151efe90Yu Zhao struct dmar_drhd_unit *dmaru = NULL; 4062e824f79240476d57a8589f46232cabf151efe90Yu Zhao struct acpi_dmar_hardware_unit *drhd; 4072e824f79240476d57a8589f46232cabf151efe90Yu Zhao 408dda565492776b7dff5f8507298d868745e734aabYinghai dev = pci_physfn(dev); 409dda565492776b7dff5f8507298d868745e734aabYinghai 4102e824f79240476d57a8589f46232cabf151efe90Yu Zhao list_for_each_entry(dmaru, &dmar_drhd_units, list) { 4112e824f79240476d57a8589f46232cabf151efe90Yu Zhao drhd = container_of(dmaru->hdr, 4122e824f79240476d57a8589f46232cabf151efe90Yu Zhao struct acpi_dmar_hardware_unit, 4132e824f79240476d57a8589f46232cabf151efe90Yu Zhao header); 4142e824f79240476d57a8589f46232cabf151efe90Yu Zhao 4152e824f79240476d57a8589f46232cabf151efe90Yu Zhao if (dmaru->include_all && 4162e824f79240476d57a8589f46232cabf151efe90Yu Zhao drhd->segment == pci_domain_nr(dev->bus)) 4172e824f79240476d57a8589f46232cabf151efe90Yu Zhao return dmaru; 418e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 4192e824f79240476d57a8589f46232cabf151efe90Yu Zhao if (dmar_pci_device_match(dmaru->devices, 4202e824f79240476d57a8589f46232cabf151efe90Yu Zhao dmaru->devices_cnt, dev)) 4212e824f79240476d57a8589f46232cabf151efe90Yu Zhao return dmaru; 422e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha } 423e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 424e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha return NULL; 425e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha} 426e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 4271886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddhaint __init dmar_dev_scope_init(void) 4281886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha{ 429c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha static int dmar_dev_scope_initialized; 43004e2ea67069e285404192a35c24dfe7c53b9c61fSuresh Siddha struct dmar_drhd_unit *drhd, *drhd_n; 4311886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha int ret = -ENODEV; 4321886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 433c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha if (dmar_dev_scope_initialized) 434c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha return dmar_dev_scope_initialized; 435c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha 436318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha if (list_empty(&dmar_drhd_units)) 437318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha goto fail; 438318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha 43904e2ea67069e285404192a35c24dfe7c53b9c61fSuresh Siddha list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { 4401886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha ret = dmar_parse_dev(drhd); 4411886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha if (ret) 442c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha goto fail; 4431886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha } 4441886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 445318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha ret = dmar_parse_rmrr_atsr_dev(); 446318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha if (ret) 447318fe7df9d8456f778451b01913b5d0dc0a25854Suresh Siddha goto fail; 4481886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 449c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha dmar_dev_scope_initialized = 1; 450c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha return 0; 451c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha 452c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddhafail: 453c2c7286ac6d996a8ffc8d391d782ba35570b1236Suresh Siddha dmar_dev_scope_initialized = ret; 4541886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return ret; 4551886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha} 4561886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 45710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 45810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil Sint __init dmar_table_init(void) 45910e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S{ 4601886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha static int dmar_table_initialized; 461093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu int ret; 462093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu 4631886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha if (dmar_table_initialized) 4641886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return 0; 4651886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 4661886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha dmar_table_initialized = 1; 4671886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha 468093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu ret = parse_dmar_table(); 469093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu if (ret) { 4701886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha if (ret != -ENODEV) 4711886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); 472093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu return ret; 473093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu } 474093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu 47510e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S if (list_empty(&dmar_drhd_units)) { 47610e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S printk(KERN_INFO PREFIX "No DMAR devices found\n"); 47710e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return -ENODEV; 47810e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S } 479093f87d279669c74e84530e925e4735c9aae8898Fenghua Yu 48010e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S return 0; 48110e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S} 48210e5247f40f3bf7508a0ed2848c9cae37bddf4bcKeshavamurthy, Anil S 4833a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchingsstatic void warn_invalid_dmar(u64 addr, const char *message) 4843a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings{ 485fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings WARN_TAINT_ONCE( 486fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings 1, TAINT_FIRMWARE_WORKAROUND, 487fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings "Your BIOS is broken; DMAR reported at address %llx%s!\n" 488fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings "BIOS vendor: %s; Ver: %s; Product Version: %s\n", 489fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings addr, message, 490fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_BIOS_VENDOR), 491fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_BIOS_VERSION), 492fd0c8894893cba722bdea12de25b49f980795d06Ben Hutchings dmi_get_system_info(DMI_PRODUCT_VERSION)); 4933a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings} 4946ecbf01c7ce4c0f4c3bdfa0e64ac6258328fda6cDavid Woodhouse 49586cf898e1d0fca245173980e3897580db38569a8David Woodhouseint __init check_zero_address(void) 49686cf898e1d0fca245173980e3897580db38569a8David Woodhouse{ 49786cf898e1d0fca245173980e3897580db38569a8David Woodhouse struct acpi_table_dmar *dmar; 49886cf898e1d0fca245173980e3897580db38569a8David Woodhouse struct acpi_dmar_header *entry_header; 49986cf898e1d0fca245173980e3897580db38569a8David Woodhouse struct acpi_dmar_hardware_unit *drhd; 50086cf898e1d0fca245173980e3897580db38569a8David Woodhouse 50186cf898e1d0fca245173980e3897580db38569a8David Woodhouse dmar = (struct acpi_table_dmar *)dmar_tbl; 50286cf898e1d0fca245173980e3897580db38569a8David Woodhouse entry_header = (struct acpi_dmar_header *)(dmar + 1); 50386cf898e1d0fca245173980e3897580db38569a8David Woodhouse 50486cf898e1d0fca245173980e3897580db38569a8David Woodhouse while (((unsigned long)entry_header) < 50586cf898e1d0fca245173980e3897580db38569a8David Woodhouse (((unsigned long)dmar) + dmar_tbl->length)) { 50686cf898e1d0fca245173980e3897580db38569a8David Woodhouse /* Avoid looping forever on bad ACPI tables */ 50786cf898e1d0fca245173980e3897580db38569a8David Woodhouse if (entry_header->length == 0) { 50886cf898e1d0fca245173980e3897580db38569a8David Woodhouse printk(KERN_WARNING PREFIX 50986cf898e1d0fca245173980e3897580db38569a8David Woodhouse "Invalid 0-length structure\n"); 51086cf898e1d0fca245173980e3897580db38569a8David Woodhouse return 0; 51186cf898e1d0fca245173980e3897580db38569a8David Woodhouse } 51286cf898e1d0fca245173980e3897580db38569a8David Woodhouse 51386cf898e1d0fca245173980e3897580db38569a8David Woodhouse if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { 5142c99220810c1c79322034628b993573b088ff2daChris Wright void __iomem *addr; 5152c99220810c1c79322034628b993573b088ff2daChris Wright u64 cap, ecap; 5162c99220810c1c79322034628b993573b088ff2daChris Wright 51786cf898e1d0fca245173980e3897580db38569a8David Woodhouse drhd = (void *)entry_header; 51886cf898e1d0fca245173980e3897580db38569a8David Woodhouse if (!drhd->address) { 5193a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings warn_invalid_dmar(0, ""); 5202c99220810c1c79322034628b993573b088ff2daChris Wright goto failed; 5212c99220810c1c79322034628b993573b088ff2daChris Wright } 5222c99220810c1c79322034628b993573b088ff2daChris Wright 5232c99220810c1c79322034628b993573b088ff2daChris Wright addr = early_ioremap(drhd->address, VTD_PAGE_SIZE); 5242c99220810c1c79322034628b993573b088ff2daChris Wright if (!addr ) { 5252c99220810c1c79322034628b993573b088ff2daChris Wright printk("IOMMU: can't validate: %llx\n", drhd->address); 5262c99220810c1c79322034628b993573b088ff2daChris Wright goto failed; 5272c99220810c1c79322034628b993573b088ff2daChris Wright } 5282c99220810c1c79322034628b993573b088ff2daChris Wright cap = dmar_readq(addr + DMAR_CAP_REG); 5292c99220810c1c79322034628b993573b088ff2daChris Wright ecap = dmar_readq(addr + DMAR_ECAP_REG); 5302c99220810c1c79322034628b993573b088ff2daChris Wright early_iounmap(addr, VTD_PAGE_SIZE); 5312c99220810c1c79322034628b993573b088ff2daChris Wright if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) { 5323a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings warn_invalid_dmar(drhd->address, 5333a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings " returns all ones"); 5342c99220810c1c79322034628b993573b088ff2daChris Wright goto failed; 53586cf898e1d0fca245173980e3897580db38569a8David Woodhouse } 53686cf898e1d0fca245173980e3897580db38569a8David Woodhouse } 53786cf898e1d0fca245173980e3897580db38569a8David Woodhouse 53886cf898e1d0fca245173980e3897580db38569a8David Woodhouse entry_header = ((void *)entry_header + entry_header->length); 53986cf898e1d0fca245173980e3897580db38569a8David Woodhouse } 54086cf898e1d0fca245173980e3897580db38569a8David Woodhouse return 1; 5412c99220810c1c79322034628b993573b088ff2daChris Wright 5422c99220810c1c79322034628b993573b088ff2daChris Wrightfailed: 5432c99220810c1c79322034628b993573b088ff2daChris Wright return 0; 54486cf898e1d0fca245173980e3897580db38569a8David Woodhouse} 54586cf898e1d0fca245173980e3897580db38569a8David Woodhouse 546480125ba49ba62be93beea37770f266846e077abKonrad Rzeszutek Wilkint __init detect_intel_iommu(void) 5472ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha{ 5482ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha int ret; 5492ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha 550f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu ret = dmar_table_detect(); 55186cf898e1d0fca245173980e3897580db38569a8David Woodhouse if (ret) 55286cf898e1d0fca245173980e3897580db38569a8David Woodhouse ret = check_zero_address(); 5532ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha { 5541cb11583a6c4ceda7426eb36f7bf0419da8dfbc2Suresh Siddha struct acpi_table_dmar *dmar; 555b3a530e4e734cab7043a3ab7d135f539042443a7Jan Kiszka 5561cb11583a6c4ceda7426eb36f7bf0419da8dfbc2Suresh Siddha dmar = (struct acpi_table_dmar *) dmar_tbl; 557f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha 558f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha if (ret && intr_remapping_enabled && cpu_has_x2apic && 559f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha dmar->flags & 0x1) 5601cb11583a6c4ceda7426eb36f7bf0419da8dfbc2Suresh Siddha printk(KERN_INFO 561f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); 562f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha 56311bd04f6f35621193311c32e0721142b073a7794Linus Torvalds if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { 5642ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha iommu_detected = 1; 5655d990b627537e59a3a2f039ff588a4750e9c1a6aChris Wright /* Make sure ACS will be enabled */ 5665d990b627537e59a3a2f039ff588a4750e9c1a6aChris Wright pci_request_acs(); 5675d990b627537e59a3a2f039ff588a4750e9c1a6aChris Wright } 568f5d1b97bcdd8ac195f48c645bffcb88bcea533e4Suresh Siddha 5699d5ce73a64be2be8112147a3e0b551ad9cd1247bFUJITA Tomonori#ifdef CONFIG_X86 5709d5ce73a64be2be8112147a3e0b551ad9cd1247bFUJITA Tomonori if (ret) 5719d5ce73a64be2be8112147a3e0b551ad9cd1247bFUJITA Tomonori x86_init.iommu.iommu_init = intel_iommu_init; 5729d5ce73a64be2be8112147a3e0b551ad9cd1247bFUJITA Tomonori#endif 573cacd4213d8ffed83676f38d5d8e93c673e0f1af7Youquan Song } 5748e1568f3500287d0b36c9776132cb53a42d5651dYinghai Lu early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); 575f6dd5c3106fb283e37d915eeb33019ef40510f85Yinghai Lu dmar_tbl = NULL; 576480125ba49ba62be93beea37770f266846e077abKonrad Rzeszutek Wilk 5774db77ff3237a88ea74f691dd776e92b2f86a8f3fKonrad Rzeszutek Wilk return ret ? 1 : -ENODEV; 5782ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha} 5792ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha 5802ae21010694e56461a63bfc80e960090ce0a5ed9Suresh Siddha 5811886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddhaint alloc_iommu(struct dmar_drhd_unit *drhd) 582e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha{ 583c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha struct intel_iommu *iommu; 584e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha int map_size; 585e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha u32 ver; 586c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha static int iommu_allocated = 0; 58743f7392ba9e2585bf34f21399b1ed78692b5d437Joerg Roedel int agaw = 0; 5884ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu int msagaw = 0; 589c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha 5906ecbf01c7ce4c0f4c3bdfa0e64ac6258328fda6cDavid Woodhouse if (!drhd->reg_base_addr) { 5913a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings warn_invalid_dmar(0, ""); 5926ecbf01c7ce4c0f4c3bdfa0e64ac6258328fda6cDavid Woodhouse return -EINVAL; 5936ecbf01c7ce4c0f4c3bdfa0e64ac6258328fda6cDavid Woodhouse } 5946ecbf01c7ce4c0f4c3bdfa0e64ac6258328fda6cDavid Woodhouse 595c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); 596c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha if (!iommu) 5971886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return -ENOMEM; 598c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha 599c42d9f32443397aed2d37d37df161392e6a5862fSuresh Siddha iommu->seq_id = iommu_allocated++; 6009d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha sprintf (iommu->name, "dmar%d", iommu->seq_id); 601e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 6025b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE); 603e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha if (!iommu->reg) { 604e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha printk(KERN_ERR "IOMMU: can't map the region\n"); 605e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha goto error; 606e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha } 607e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); 608e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); 609e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 6100815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { 6113a8663ee6171e1e61f5c139ed65aa0a769380f00Ben Hutchings warn_invalid_dmar(drhd->reg_base_addr, " returns all ones"); 6120815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse goto err_unmap; 6130815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse } 6140815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse 6151b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han agaw = iommu_calculate_agaw(iommu); 6161b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han if (agaw < 0) { 6171b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han printk(KERN_ERR 6184ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu "Cannot get a valid agaw for iommu (seq_id = %d)\n", 6194ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu iommu->seq_id); 6200815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse goto err_unmap; 6214ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu } 6224ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu msagaw = iommu_calculate_max_sagaw(iommu); 6234ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu if (msagaw < 0) { 6244ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu printk(KERN_ERR 6254ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu "Cannot get a valid max agaw for iommu (seq_id = %d)\n", 6261b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han iommu->seq_id); 6270815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse goto err_unmap; 6281b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han } 6291b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han iommu->agaw = agaw; 6304ed0d3e6c64cfd9ba4ceb2099b10d1cf8ece4320Fenghua Yu iommu->msagaw = msagaw; 6311b5736839ae13dadc5947940144f95dd0f4a4a8cWeidong Han 632ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha iommu->node = -1; 633ee34b32d8c2950f66038c8975747ef9aec855289Suresh Siddha 634e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha /* the registers might be more than one page */ 635e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), 636e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha cap_max_fault_reg_offset(iommu->cap)); 6375b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu map_size = VTD_PAGE_ALIGN(map_size); 6385b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu if (map_size > VTD_PAGE_SIZE) { 639e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha iounmap(iommu->reg); 640e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha iommu->reg = ioremap(drhd->reg_base_addr, map_size); 641e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha if (!iommu->reg) { 642e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha printk(KERN_ERR "IOMMU: can't map the region\n"); 643e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha goto error; 644e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha } 645e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha } 646e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 647e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha ver = readl(iommu->reg + DMAR_VER_REG); 648680a7524622356f5476e8fad2fe32b2b68b432c0Yinghai Lu pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n", 649680a7524622356f5476e8fad2fe32b2b68b432c0Yinghai Lu iommu->seq_id, 6505b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu (unsigned long long)drhd->reg_base_addr, 6515b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), 6525b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu (unsigned long long)iommu->cap, 6535b6985ce8ec7127b4d60ad450b64ca8b82748a3bFenghua Yu (unsigned long long)iommu->ecap); 654e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 6551f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_init(&iommu->register_lock); 656e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 657e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha drhd->iommu = iommu; 6581886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return 0; 6590815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse 6600815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse err_unmap: 6610815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse iounmap(iommu->reg); 6620815565adfe3f4c369110c57d8ffe83caefeed68David Woodhouse error: 663e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha kfree(iommu); 6641886e8a90a580f3ad343f2065c84c1b9e1dac9efSuresh Siddha return -1; 665e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha} 666e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 667e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddhavoid free_iommu(struct intel_iommu *iommu) 668e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha{ 669e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha if (!iommu) 670e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha return; 671e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 672e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha free_dmar_iommu(iommu); 673e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha 674e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha if (iommu->reg) 675e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha iounmap(iommu->reg); 676e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha kfree(iommu); 677e61d98d8dad0048619bb138b0ff996422ffae53bSuresh Siddha} 678fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 679fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha/* 680fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * Reclaim all the submitted descriptors which have completed its work. 681fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 682fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddhastatic inline void reclaim_free_desc(struct q_inval *qi) 683fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha{ 6846ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao while (qi->desc_status[qi->free_tail] == QI_DONE || 6856ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao qi->desc_status[qi->free_tail] == QI_ABORT) { 686fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->desc_status[qi->free_tail] = QI_FREE; 687fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_tail = (qi->free_tail + 1) % QI_LENGTH; 688fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_cnt++; 689fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha } 690fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha} 691fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 692704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhaostatic int qi_check_fault(struct intel_iommu *iommu, int index) 693704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao{ 694704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao u32 fault; 6956ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao int head, tail; 696704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao struct q_inval *qi = iommu->qi; 697704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao int wait_index = (index + 1) % QI_LENGTH; 698704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 6996ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (qi->desc_status[wait_index] == QI_ABORT) 7006ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao return -EAGAIN; 7016ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 702704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao fault = readl(iommu->reg + DMAR_FSTS_REG); 703704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 704704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao /* 705704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao * If IQE happens, the head points to the descriptor associated 706704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao * with the error. No new descriptors are fetched until the IQE 707704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao * is cleared. 708704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao */ 709704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao if (fault & DMA_FSTS_IQE) { 710704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao head = readl(iommu->reg + DMAR_IQH_REG); 7116ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if ((head >> DMAR_IQ_SHIFT) == index) { 7126ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao printk(KERN_ERR "VT-d detected invalid descriptor: " 7136ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao "low=%llx, high=%llx\n", 7146ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao (unsigned long long)qi->desc[index].low, 7156ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao (unsigned long long)qi->desc[index].high); 716704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao memcpy(&qi->desc[index], &qi->desc[wait_index], 717704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao sizeof(struct qi_desc)); 718704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao __iommu_flush_cache(iommu, &qi->desc[index], 719704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao sizeof(struct qi_desc)); 720704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao writel(DMA_FSTS_IQE, iommu->reg + DMAR_FSTS_REG); 721704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao return -EINVAL; 722704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao } 723704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao } 724704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 7256ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao /* 7266ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao * If ITE happens, all pending wait_desc commands are aborted. 7276ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao * No new descriptors are fetched until the ITE is cleared. 7286ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao */ 7296ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (fault & DMA_FSTS_ITE) { 7306ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao head = readl(iommu->reg + DMAR_IQH_REG); 7316ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao head = ((head >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH; 7326ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao head |= 1; 7336ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao tail = readl(iommu->reg + DMAR_IQT_REG); 7346ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao tail = ((tail >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH; 7356ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 7366ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao writel(DMA_FSTS_ITE, iommu->reg + DMAR_FSTS_REG); 7376ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 7386ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao do { 7396ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (qi->desc_status[head] == QI_IN_USE) 7406ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao qi->desc_status[head] = QI_ABORT; 7416ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao head = (head - 2 + QI_LENGTH) % QI_LENGTH; 7426ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao } while (head != tail); 7436ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 7446ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (qi->desc_status[wait_index] == QI_ABORT) 7456ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao return -EAGAIN; 7466ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao } 7476ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 7486ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (fault & DMA_FSTS_ICE) 7496ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao writel(DMA_FSTS_ICE, iommu->reg + DMAR_FSTS_REG); 7506ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 751704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao return 0; 752704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao} 753704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 754fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha/* 755fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * Submit the queued invalidation descriptor to the remapping 756fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * hardware unit and wait for its completion. 757fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 758704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhaoint qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) 759fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha{ 7606ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao int rc; 761fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha struct q_inval *qi = iommu->qi; 762fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha struct qi_desc *hw, wait_desc; 763fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha int wait_index, index; 764fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha unsigned long flags; 765fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 766fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha if (!qi) 767704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao return 0; 768fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 769fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha hw = qi->desc; 770fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 7716ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhaorestart: 7726ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao rc = 0; 7736ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 7743b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_lock_irqsave(&qi->q_lock, flags); 775fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha while (qi->free_cnt < 3) { 7763b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_unlock_irqrestore(&qi->q_lock, flags); 777fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha cpu_relax(); 7783b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_lock_irqsave(&qi->q_lock, flags); 779fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha } 780fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 781fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha index = qi->free_head; 782fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha wait_index = (index + 1) % QI_LENGTH; 783fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 784fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->desc_status[index] = qi->desc_status[wait_index] = QI_IN_USE; 785fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 786fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha hw[index] = *desc; 787fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 788704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao wait_desc.low = QI_IWD_STATUS_DATA(QI_DONE) | 789704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao QI_IWD_STATUS_WRITE | QI_IWD_TYPE; 790fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]); 791fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 792fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha hw[wait_index] = wait_desc; 793fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 794fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha __iommu_flush_cache(iommu, &hw[index], sizeof(struct qi_desc)); 795fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha __iommu_flush_cache(iommu, &hw[wait_index], sizeof(struct qi_desc)); 796fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 797fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_head = (qi->free_head + 2) % QI_LENGTH; 798fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_cnt -= 2; 799fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 800fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha /* 801fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * update the HW tail register indicating the presence of 802fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * new descriptors. 803fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 8046ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao writel(qi->free_head << DMAR_IQ_SHIFT, iommu->reg + DMAR_IQT_REG); 805fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 806fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha while (qi->desc_status[wait_index] != QI_DONE) { 807f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha /* 808f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha * We will leave the interrupts disabled, to prevent interrupt 809f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha * context to queue another cmd while a cmd is already submitted 810f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha * and waiting for completion on this cpu. This is to avoid 811f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha * a deadlock where the interrupt context can wait indefinitely 812f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha * for free slots in the queue. 813f05810c9962bba3e809f07619bda1bfdebbfbfb9Suresh Siddha */ 814704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao rc = qi_check_fault(iommu, index); 815704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao if (rc) 8166ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao break; 817704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 8183b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_unlock(&qi->q_lock); 819fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha cpu_relax(); 8203b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_lock(&qi->q_lock); 821fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha } 8226ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 8236ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao qi->desc_status[index] = QI_DONE; 824fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 825fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha reclaim_free_desc(qi); 8263b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_unlock_irqrestore(&qi->q_lock, flags); 827704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao 8286ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (rc == -EAGAIN) 8296ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao goto restart; 8306ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 831704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao return rc; 832fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha} 833fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 834fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha/* 835fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * Flush the global interrupt entry cache. 836fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 837fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddhavoid qi_global_iec(struct intel_iommu *iommu) 838fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha{ 839fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha struct qi_desc desc; 840fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 841fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha desc.low = QI_IEC_TYPE; 842fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha desc.high = 0; 843fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 844704126ad81b8cb7d3d70adb9ecb143f4d3fb38afYu Zhao /* should never fail */ 845fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi_submit_sync(&desc, iommu); 846fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha} 847fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 8484c25a2c1b90bf785fc2e2f0f0c74a80b3e070d39David Woodhousevoid qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, 8494c25a2c1b90bf785fc2e2f0f0c74a80b3e070d39David Woodhouse u64 type) 8503481f21097cb560392c411377893b5109fbde557Youquan Song{ 8513481f21097cb560392c411377893b5109fbde557Youquan Song struct qi_desc desc; 8523481f21097cb560392c411377893b5109fbde557Youquan Song 8533481f21097cb560392c411377893b5109fbde557Youquan Song desc.low = QI_CC_FM(fm) | QI_CC_SID(sid) | QI_CC_DID(did) 8543481f21097cb560392c411377893b5109fbde557Youquan Song | QI_CC_GRAN(type) | QI_CC_TYPE; 8553481f21097cb560392c411377893b5109fbde557Youquan Song desc.high = 0; 8563481f21097cb560392c411377893b5109fbde557Youquan Song 8574c25a2c1b90bf785fc2e2f0f0c74a80b3e070d39David Woodhouse qi_submit_sync(&desc, iommu); 8583481f21097cb560392c411377893b5109fbde557Youquan Song} 8593481f21097cb560392c411377893b5109fbde557Youquan Song 8601f0ef2aa18802a8ce7eb5a5164aaaf4d59073801David Woodhousevoid qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, 8611f0ef2aa18802a8ce7eb5a5164aaaf4d59073801David Woodhouse unsigned int size_order, u64 type) 8623481f21097cb560392c411377893b5109fbde557Youquan Song{ 8633481f21097cb560392c411377893b5109fbde557Youquan Song u8 dw = 0, dr = 0; 8643481f21097cb560392c411377893b5109fbde557Youquan Song 8653481f21097cb560392c411377893b5109fbde557Youquan Song struct qi_desc desc; 8663481f21097cb560392c411377893b5109fbde557Youquan Song int ih = 0; 8673481f21097cb560392c411377893b5109fbde557Youquan Song 8683481f21097cb560392c411377893b5109fbde557Youquan Song if (cap_write_drain(iommu->cap)) 8693481f21097cb560392c411377893b5109fbde557Youquan Song dw = 1; 8703481f21097cb560392c411377893b5109fbde557Youquan Song 8713481f21097cb560392c411377893b5109fbde557Youquan Song if (cap_read_drain(iommu->cap)) 8723481f21097cb560392c411377893b5109fbde557Youquan Song dr = 1; 8733481f21097cb560392c411377893b5109fbde557Youquan Song 8743481f21097cb560392c411377893b5109fbde557Youquan Song desc.low = QI_IOTLB_DID(did) | QI_IOTLB_DR(dr) | QI_IOTLB_DW(dw) 8753481f21097cb560392c411377893b5109fbde557Youquan Song | QI_IOTLB_GRAN(type) | QI_IOTLB_TYPE; 8763481f21097cb560392c411377893b5109fbde557Youquan Song desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) 8773481f21097cb560392c411377893b5109fbde557Youquan Song | QI_IOTLB_AM(size_order); 8783481f21097cb560392c411377893b5109fbde557Youquan Song 8791f0ef2aa18802a8ce7eb5a5164aaaf4d59073801David Woodhouse qi_submit_sync(&desc, iommu); 8803481f21097cb560392c411377893b5109fbde557Youquan Song} 8813481f21097cb560392c411377893b5109fbde557Youquan Song 8826ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhaovoid qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, 8836ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao u64 addr, unsigned mask) 8846ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao{ 8856ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao struct qi_desc desc; 8866ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 8876ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (mask) { 8886ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); 8896ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao addr |= (1 << (VTD_PAGE_SHIFT + mask - 1)) - 1; 8906ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE; 8916ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao } else 8926ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao desc.high = QI_DEV_IOTLB_ADDR(addr); 8936ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 8946ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao if (qdep >= QI_DEV_IOTLB_MAX_INVS) 8956ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao qdep = 0; 8966ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 8976ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) | 8986ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao QI_DIOTLB_TYPE; 8996ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 9006ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao qi_submit_sync(&desc, iommu); 9016ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao} 9026ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695Yu Zhao 903fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha/* 904eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha * Disable Queued Invalidation interface. 905eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha */ 906eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddhavoid dmar_disable_qi(struct intel_iommu *iommu) 907eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha{ 908eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha unsigned long flags; 909eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha u32 sts; 910eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha cycles_t start_time = get_cycles(); 911eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 912eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha if (!ecap_qis(iommu->ecap)) 913eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha return; 914eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 9151f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flags); 916eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 917eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); 918eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha if (!(sts & DMA_GSTS_QIES)) 919eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha goto end; 920eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 921eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha /* 922eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha * Give a chance to HW to complete the pending invalidation requests. 923eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha */ 924eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha while ((readl(iommu->reg + DMAR_IQT_REG) != 925eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha readl(iommu->reg + DMAR_IQH_REG)) && 926eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha (DMAR_OPERATION_TIMEOUT > (get_cycles() - start_time))) 927eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha cpu_relax(); 928eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 929eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha iommu->gcmd &= ~DMA_GCMD_QIE; 930eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); 931eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 932eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, 933eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha !(sts & DMA_GSTS_QIES), sts); 934eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddhaend: 9351f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flags); 936eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha} 937eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha 938eba67e5da6e971993b2899d2cdf459ce77d3dbc5Suresh Siddha/* 939eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * Enable queued invalidation. 940eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu */ 941eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yustatic void __dmar_enable_qi(struct intel_iommu *iommu) 942eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu{ 943c416daa98a584596df21ee2c26fac6579ee58f57David Woodhouse u32 sts; 944eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu unsigned long flags; 945eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu struct q_inval *qi = iommu->qi; 946eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 947eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu qi->free_head = qi->free_tail = 0; 948eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu qi->free_cnt = QI_LENGTH; 949eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 9501f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flags); 951eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 952eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu /* write zero to the tail reg */ 953eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu writel(0, iommu->reg + DMAR_IQT_REG); 954eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 955eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc)); 956eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 957eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu iommu->gcmd |= DMA_GCMD_QIE; 958c416daa98a584596df21ee2c26fac6579ee58f57David Woodhouse writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); 959eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 960eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu /* Make sure hardware complete it */ 961eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts); 962eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 9631f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flags); 964eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu} 965eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 966eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu/* 967fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * Enable Queued Invalidation interface. This is a must to support 968fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * interrupt-remapping. Also used by DMA-remapping, which replaces 969fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * register based IOTLB invalidation. 970fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 971fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddhaint dmar_enable_qi(struct intel_iommu *iommu) 972fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha{ 973fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha struct q_inval *qi; 974751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha struct page *desc_page; 975fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 976fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha if (!ecap_qis(iommu->ecap)) 977fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return -ENOENT; 978fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 979fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha /* 980fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha * queued invalidation is already setup and enabled. 981fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha */ 982fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha if (iommu->qi) 983fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return 0; 984fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 985fa4b57cc045d6134b9862b2873f9c8ba9ed53ffeSuresh Siddha iommu->qi = kmalloc(sizeof(*qi), GFP_ATOMIC); 986fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha if (!iommu->qi) 987fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return -ENOMEM; 988fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 989fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi = iommu->qi; 990fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 991751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha 992751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); 993751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha if (!desc_page) { 994fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha kfree(qi); 995fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha iommu->qi = 0; 996fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return -ENOMEM; 997fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha } 998fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 999751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha qi->desc = page_address(desc_page); 1000751cafe3aeceb9ff887c97237f6daaf596c9e547Suresh Siddha 1001fa4b57cc045d6134b9862b2873f9c8ba9ed53ffeSuresh Siddha qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); 1002fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha if (!qi->desc_status) { 1003fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha free_page((unsigned long) qi->desc); 1004fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha kfree(qi); 1005fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha iommu->qi = 0; 1006fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return -ENOMEM; 1007fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha } 1008fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 1009fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_head = qi->free_tail = 0; 1010fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha qi->free_cnt = QI_LENGTH; 1011fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 10123b8f40481513a7b6123def5a02db4cff96ae2198Thomas Gleixner raw_spin_lock_init(&qi->q_lock); 1013fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 1014eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu __dmar_enable_qi(iommu); 1015fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha 1016fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha return 0; 1017fe962e90cb17a8426e144dee970e77ed789d98eeSuresh Siddha} 10180ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10190ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha/* iommu interrupt handling. Most stuff are MSI-like. */ 10200ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10219d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhaenum faulttype { 10229d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha DMA_REMAP, 10239d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha INTR_REMAP, 10249d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha UNKNOWN, 10259d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha}; 10269d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 10279d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhastatic const char *dma_remap_fault_reasons[] = 10280ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 10290ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Software", 10300ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Present bit in root entry is clear", 10310ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Present bit in context entry is clear", 10320ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Invalid context entry", 10330ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Access beyond MGAW", 10340ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "PTE Write access is not set", 10350ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "PTE Read access is not set", 10360ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Next page table ptr is invalid", 10370ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Root table address invalid", 10380ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "Context table ptr is invalid", 10390ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "non-zero reserved fields in RTP", 10400ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "non-zero reserved fields in CTP", 10410ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha "non-zero reserved fields in PTE", 10420ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha}; 10439d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 10449d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhastatic const char *intr_remap_fault_reasons[] = 10459d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha{ 10469d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Detected reserved fields in the decoded interrupt-remapped request", 10479d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Interrupt index exceeded the interrupt-remapping table size", 10489d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Present field in the IRTE entry is clear", 10499d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Error accessing interrupt-remapping table pointed by IRTA_REG", 10509d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Detected reserved fields in the IRTE entry", 10519d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Blocked a compatibility format interrupt request", 10529d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "Blocked an interrupt request due to source-id verification failure", 10539d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha}; 10549d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 10550ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) 10560ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10579d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhaconst char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) 10580ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 1059dcff6a45745b9df7f2c9255fc4998be8d52ea67cDan Carpenter if (fault_reason >= 0x20 && (fault_reason - 0x20 < 1060dcff6a45745b9df7f2c9255fc4998be8d52ea67cDan Carpenter ARRAY_SIZE(intr_remap_fault_reasons))) { 10619d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha *fault_type = INTR_REMAP; 10629d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha return intr_remap_fault_reasons[fault_reason - 0x20]; 10639d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) { 10649d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha *fault_type = DMA_REMAP; 10659d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha return dma_remap_fault_reasons[fault_reason]; 10669d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha } else { 10679d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha *fault_type = UNKNOWN; 10680ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha return "Unknown"; 10699d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha } 10700ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 10710ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10725c2837fbaa609e615ef9a1c58a4cd26ce90be35bThomas Gleixnervoid dmar_msi_unmask(struct irq_data *data) 10730ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 1074dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); 10750ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha unsigned long flag; 10760ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10770ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* unmask it */ 10781f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 10790ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(0, iommu->reg + DMAR_FECTL_REG); 10800ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* Read a reg to force flush the post write */ 10810ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha readl(iommu->reg + DMAR_FECTL_REG); 10821f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 10830ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 10840ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10855c2837fbaa609e615ef9a1c58a4cd26ce90be35bThomas Gleixnervoid dmar_msi_mask(struct irq_data *data) 10860ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 10870ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha unsigned long flag; 1088dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); 10890ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10900ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* mask it */ 10911f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 10920ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG); 10930ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* Read a reg to force flush the post write */ 10940ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha readl(iommu->reg + DMAR_FECTL_REG); 10951f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 10960ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 10970ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 10980ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddhavoid dmar_msi_write(int irq, struct msi_msg *msg) 10990ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 1100dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner struct intel_iommu *iommu = irq_get_handler_data(irq); 11010ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha unsigned long flag; 11020ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11031f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 11040ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(msg->data, iommu->reg + DMAR_FEDATA_REG); 11050ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG); 11060ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG); 11071f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 11080ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 11090ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11100ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddhavoid dmar_msi_read(int irq, struct msi_msg *msg) 11110ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 1112dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner struct intel_iommu *iommu = irq_get_handler_data(irq); 11130ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha unsigned long flag; 11140ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11151f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 11160ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha msg->data = readl(iommu->reg + DMAR_FEDATA_REG); 11170ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG); 11180ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG); 11191f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 11200ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 11210ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11220ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddhastatic int dmar_fault_do_one(struct intel_iommu *iommu, int type, 11230ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u8 fault_reason, u16 source_id, unsigned long long addr) 11240ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 11250ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha const char *reason; 11269d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha int fault_type; 11270ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11289d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha reason = dmar_get_fault_reason(fault_reason, &fault_type); 11290ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11309d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha if (fault_type == INTR_REMAP) 11319d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] " 11329d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "fault index %llx\n" 11339d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "INTR-REMAP:[fault reason %02d] %s\n", 11349d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha (source_id >> 8), PCI_SLOT(source_id & 0xFF), 11359d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha PCI_FUNC(source_id & 0xFF), addr >> 48, 11369d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha fault_reason, reason); 11379d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha else 11389d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha printk(KERN_ERR 11399d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "DMAR:[%s] Request device [%02x:%02x.%d] " 11409d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "fault addr %llx \n" 11419d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha "DMAR:[fault reason %02d] %s\n", 11429d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha (type ? "DMA Read" : "DMA Write"), 11439d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha (source_id >> 8), PCI_SLOT(source_id & 0xFF), 11449d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason); 11450ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha return 0; 11460ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 11470ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11480ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha#define PRIMARY_FAULT_REG_LEN (16) 11491531a6a6b81a4e6f9eec9a5608758a6ea14b96e0Suresh Siddhairqreturn_t dmar_fault(int irq, void *dev_id) 11500ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 11510ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha struct intel_iommu *iommu = dev_id; 11520ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha int reg, fault_index; 11530ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u32 fault_status; 11540ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha unsigned long flag; 11550ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11561f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 11570ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_status = readl(iommu->reg + DMAR_FSTS_REG); 11589d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha if (fault_status) 11599d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha printk(KERN_ERR "DRHD: handling fault status reg %x\n", 11609d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha fault_status); 11610ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11620ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* TBD: ignore advanced fault log currently */ 11630ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha if (!(fault_status & DMA_FSTS_PPF)) 11649d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha goto clear_rest; 11650ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11660ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index = dma_fsts_fault_record_index(fault_status); 11670ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha reg = cap_fault_reg_offset(iommu->cap); 11680ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha while (1) { 11690ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u8 fault_reason; 11700ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u16 source_id; 11710ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u64 guest_addr; 11720ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha int type; 11730ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha u32 data; 11740ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11750ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* highest 32 bits */ 11760ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha data = readl(iommu->reg + reg + 11770ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index * PRIMARY_FAULT_REG_LEN + 12); 11780ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha if (!(data & DMA_FRCD_F)) 11790ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha break; 11800ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11810ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_reason = dma_frcd_fault_reason(data); 11820ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha type = dma_frcd_type(data); 11830ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11840ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha data = readl(iommu->reg + reg + 11850ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index * PRIMARY_FAULT_REG_LEN + 8); 11860ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha source_id = dma_frcd_source_id(data); 11870ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11880ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha guest_addr = dmar_readq(iommu->reg + reg + 11890ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index * PRIMARY_FAULT_REG_LEN); 11900ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha guest_addr = dma_frcd_page_addr(guest_addr); 11910ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha /* clear the fault */ 11920ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha writel(DMA_FRCD_F, iommu->reg + reg + 11930ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index * PRIMARY_FAULT_REG_LEN + 12); 11940ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11951f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 11960ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 11970ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha dmar_fault_do_one(iommu, type, fault_reason, 11980ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha source_id, guest_addr); 11990ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 12000ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index++; 12018211a7b5857914058c52ae977c96463e419b37abTroy Heber if (fault_index >= cap_num_fault_regs(iommu->cap)) 12020ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_index = 0; 12031f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_lock_irqsave(&iommu->register_lock, flag); 12040ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha } 12059d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhaclear_rest: 12069d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha /* clear all the other faults */ 12070ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha fault_status = readl(iommu->reg + DMAR_FSTS_REG); 12089d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha writel(fault_status, iommu->reg + DMAR_FSTS_REG); 12090ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 12101f5b3c3fd2d73d6b30e9ef6dcbf131a791d5cbbdThomas Gleixner raw_spin_unlock_irqrestore(&iommu->register_lock, flag); 12110ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha return IRQ_HANDLED; 12120ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 12130ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 12140ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddhaint dmar_set_interrupt(struct intel_iommu *iommu) 12150ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha{ 12160ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha int irq, ret; 12170ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 12189d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha /* 12199d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha * Check if the fault interrupt is already initialized. 12209d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha */ 12219d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha if (iommu->irq) 12229d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha return 0; 12239d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 12240ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha irq = create_irq(); 12250ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha if (!irq) { 12260ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha printk(KERN_ERR "IOMMU: no free vectors\n"); 12270ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha return -EINVAL; 12280ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha } 12290ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 1230dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner irq_set_handler_data(irq, iommu); 12310ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha iommu->irq = irq; 12320ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 12330ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha ret = arch_setup_dmar_msi(irq); 12340ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha if (ret) { 1235dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner irq_set_handler_data(irq, NULL); 12360ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha iommu->irq = 0; 12370ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha destroy_irq(irq); 1238dd7264355a203c3456dbba04db471947d3b55e7eChris Wright return ret; 12390ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha } 12400ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha 1241477694e71113fd0694b6bb0bcc2d006b8ac62691Thomas Gleixner ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu); 12420ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha if (ret) 12430ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha printk(KERN_ERR "IOMMU: can't request irq\n"); 12440ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha return ret; 12450ac2491f57af5644f88383d28809760902d6f4d7Suresh Siddha} 12469d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 12479d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddhaint __init enable_drhd_fault_handling(void) 12489d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha{ 12499d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha struct dmar_drhd_unit *drhd; 12509d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 12519d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha /* 12529d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha * Enable fault control interrupt. 12539d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha */ 12549d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha for_each_drhd_unit(drhd) { 12559d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha int ret; 12569d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha struct intel_iommu *iommu = drhd->iommu; 12579d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha ret = dmar_set_interrupt(iommu); 12589d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 12599d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha if (ret) { 12609d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha printk(KERN_ERR "DRHD %Lx: failed to enable fault, " 12619d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha " interrupt, ret %d\n", 12629d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha (unsigned long long)drhd->reg_base_addr, ret); 12639d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha return -1; 12649d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha } 12657f99d946e71e71d484b7543b49e990508e70d0c0Suresh Siddha 12667f99d946e71e71d484b7543b49e990508e70d0c0Suresh Siddha /* 12677f99d946e71e71d484b7543b49e990508e70d0c0Suresh Siddha * Clear any previous faults. 12687f99d946e71e71d484b7543b49e990508e70d0c0Suresh Siddha */ 12697f99d946e71e71d484b7543b49e990508e70d0c0Suresh Siddha dmar_fault(iommu->irq, iommu); 12709d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha } 12719d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha 12729d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha return 0; 12739d783ba042771284fb4ee5013c3d94220755ae7fSuresh Siddha} 1274eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 1275eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu/* 1276eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * Re-enable Queued Invalidation interface. 1277eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu */ 1278eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yuint dmar_reenable_qi(struct intel_iommu *iommu) 1279eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu{ 1280eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu if (!ecap_qis(iommu->ecap)) 1281eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu return -ENOENT; 1282eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 1283eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu if (!iommu->qi) 1284eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu return -ENOENT; 1285eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 1286eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu /* 1287eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * First disable queued invalidation. 1288eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu */ 1289eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu dmar_disable_qi(iommu); 1290eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu /* 1291eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * Then enable queued invalidation again. Since there is no pending 1292eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * invalidation requests now, it's safe to re-enable queued 1293eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu * invalidation. 1294eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu */ 1295eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu __dmar_enable_qi(iommu); 1296eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu 1297eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu return 0; 1298eb4a52bc660ea835482c582eaaf4893742cbd160Fenghua Yu} 1299074835f0143b83845af5044af2739c52c9f53808Youquan Song 1300074835f0143b83845af5044af2739c52c9f53808Youquan Song/* 1301074835f0143b83845af5044af2739c52c9f53808Youquan Song * Check interrupt remapping support in DMAR table description. 1302074835f0143b83845af5044af2739c52c9f53808Youquan Song */ 13030b8973a81876d90f916507ac40d1381068dc986aTony Luckint __init dmar_ir_support(void) 1304074835f0143b83845af5044af2739c52c9f53808Youquan Song{ 1305074835f0143b83845af5044af2739c52c9f53808Youquan Song struct acpi_table_dmar *dmar; 1306074835f0143b83845af5044af2739c52c9f53808Youquan Song dmar = (struct acpi_table_dmar *)dmar_tbl; 13074f506e07e0a3dff34427cece255a8f390a78d5a0Arnaud Patard if (!dmar) 13084f506e07e0a3dff34427cece255a8f390a78d5a0Arnaud Patard return 0; 1309074835f0143b83845af5044af2739c52c9f53808Youquan Song return dmar->flags & 0x1; 1310074835f0143b83845af5044af2739c52c9f53808Youquan Song} 13114db77ff3237a88ea74f691dd776e92b2f86a8f3fKonrad Rzeszutek WilkIOMMU_INIT_POST(detect_intel_iommu); 1312