1fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel/* 2fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. 3fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * Author: Joerg Roedel <joerg.roedel@amd.com> 4fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * 5fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * This program is free software; you can redistribute it and/or modify it 6fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * under the terms of the GNU General Public License version 2 as published 7fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * by the Free Software Foundation. 8fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * 9fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * This program is distributed in the hope that it will be useful, 10fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * but WITHOUT ANY WARRANTY; without even the implied warranty of 11fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * GNU General Public License for more details. 13fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * 14fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * You should have received a copy of the GNU General Public License 15fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * along with this program; if not, write to the Free Software 16fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel */ 18fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 197d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen#define pr_fmt(fmt) "%s: " fmt, __func__ 207d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 21905d66c1e5dc8149e111f04a32bb193f25da1d53Joerg Roedel#include <linux/device.h> 224099818842abd98ef2b18a8ac7a2e2ad3bc3d7c2Ohad Ben-Cohen#include <linux/kernel.h> 23fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel#include <linux/bug.h> 24fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel#include <linux/types.h> 2560db402780ec257b287de591d65157575952bb4aAndrew Morton#include <linux/module.h> 2660db402780ec257b287de591d65157575952bb4aAndrew Morton#include <linux/slab.h> 27fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel#include <linux/errno.h> 28fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel#include <linux/iommu.h> 29fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 301460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic ssize_t show_iommu_group(struct device *dev, 311460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson struct device_attribute *attr, char *buf) 321460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson{ 331460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson unsigned int groupid; 341460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 351460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson if (iommu_device_group(dev, &groupid)) 361460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return 0; 371460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 381460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return sprintf(buf, "%u", groupid); 391460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson} 401460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL); 411460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 421460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic int add_iommu_group(struct device *dev, void *data) 431460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson{ 441460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson unsigned int groupid; 451460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 461460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson if (iommu_device_group(dev, &groupid) == 0) 471460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return device_create_file(dev, &dev_attr_iommu_group); 481460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 491460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return 0; 501460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson} 511460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 521460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic int remove_iommu_group(struct device *dev) 531460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson{ 541460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson unsigned int groupid; 551460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 561460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson if (iommu_device_group(dev, &groupid) == 0) 571460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson device_remove_file(dev, &dev_attr_iommu_group); 581460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 591460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return 0; 601460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson} 611460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 621460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic int iommu_device_notifier(struct notifier_block *nb, 631460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson unsigned long action, void *data) 641460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson{ 651460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson struct device *dev = data; 661460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 671460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson if (action == BUS_NOTIFY_ADD_DEVICE) 681460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return add_iommu_group(dev, NULL); 691460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson else if (action == BUS_NOTIFY_DEL_DEVICE) 701460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return remove_iommu_group(dev); 711460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 721460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return 0; 731460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson} 741460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 751460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonstatic struct notifier_block iommu_device_nb = { 761460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson .notifier_call = iommu_device_notifier, 771460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson}; 781460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 79ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedelstatic void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) 80ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel{ 811460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson bus_register_notifier(bus, &iommu_device_nb); 821460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson bus_for_each_dev(bus, NULL, NULL, add_iommu_group); 83ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel} 84fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 85ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel/** 86ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * bus_set_iommu - set iommu-callbacks for the bus 87ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * @bus: bus. 88ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * @ops: the callbacks provided by the iommu-driver 89ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * 90ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * This function is called by an iommu driver to set the iommu methods 91ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * used for a particular bus. Drivers for devices on that bus can use 92ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * the iommu-api after these ops are registered. 93ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * This special function is needed because IOMMUs are usually devices on 94ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * the bus itself, so the iommu drivers are not initialized when the bus 95ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * is set up. With this function the iommu-driver can set the iommu-ops 96ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel * afterwards. 97ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel */ 98ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedelint bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops) 99fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 100ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel if (bus->iommu_ops != NULL) 101ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel return -EBUSY; 102fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 103ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel bus->iommu_ops = ops; 104ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel 105ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel /* Do IOMMU specific setup for this bus-type */ 106ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel iommu_bus_init(bus, ops); 107fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 108ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg Roedel return 0; 109fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 110ff21776d12ff7993a6b236b8273ef62777d25dfbJoerg RoedelEXPORT_SYMBOL_GPL(bus_set_iommu); 111fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 112a1b60c1cd913c5ccfb38c717ba0bd22622425fa7Joerg Roedelbool iommu_present(struct bus_type *bus) 113fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 11494441c3bd99287b9d84f148a08cc9a44675ec749Joerg Roedel return bus->iommu_ops != NULL; 115fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 116a1b60c1cd913c5ccfb38c717ba0bd22622425fa7Joerg RoedelEXPORT_SYMBOL_GPL(iommu_present); 117fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 1184f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen/** 1194f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen * iommu_set_fault_handler() - set a fault handler for an iommu domain 1204f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen * @domain: iommu domain 1214f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen * @handler: fault handler 1220ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * 1230ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * This function should be used by IOMMU users which want to be notified 1240ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * whenever an IOMMU fault happens. 1250ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * 1260ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * The fault handler itself should return 0 on success, and an appropriate 1270ed6d2d27bcc2ace454a8c55446e1bc3efd2d529Ohad Ben-Cohen * error code otherwise. 1284f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen */ 1294f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohenvoid iommu_set_fault_handler(struct iommu_domain *domain, 1304f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen iommu_fault_handler_t handler) 1314f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen{ 1324f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen BUG_ON(!domain); 1334f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen 1344f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen domain->handler = handler; 1354f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen} 13630bd918c7132adddd370c79fd5619bf108efd702Ohad Ben-CohenEXPORT_SYMBOL_GPL(iommu_set_fault_handler); 1374f3f8d9db359bbc780d482849f2a9c8b12f910b6Ohad Ben-Cohen 138905d66c1e5dc8149e111f04a32bb193f25da1d53Joerg Roedelstruct iommu_domain *iommu_domain_alloc(struct bus_type *bus) 139fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 140fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel struct iommu_domain *domain; 141fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel int ret; 142fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 14394441c3bd99287b9d84f148a08cc9a44675ec749Joerg Roedel if (bus == NULL || bus->iommu_ops == NULL) 144905d66c1e5dc8149e111f04a32bb193f25da1d53Joerg Roedel return NULL; 145905d66c1e5dc8149e111f04a32bb193f25da1d53Joerg Roedel 1468bd6960c6ae65d7f92bfb708154ee813417d7b26KyongHo Cho domain = kzalloc(sizeof(*domain), GFP_KERNEL); 147fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel if (!domain) 148fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel return NULL; 149fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 15094441c3bd99287b9d84f148a08cc9a44675ec749Joerg Roedel domain->ops = bus->iommu_ops; 151905d66c1e5dc8149e111f04a32bb193f25da1d53Joerg Roedel 15294441c3bd99287b9d84f148a08cc9a44675ec749Joerg Roedel ret = domain->ops->domain_init(domain); 153fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel if (ret) 154fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel goto out_free; 155fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 156fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel return domain; 157fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 158fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedelout_free: 159fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel kfree(domain); 160fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 161fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel return NULL; 162fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 163fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg RoedelEXPORT_SYMBOL_GPL(iommu_domain_alloc); 164fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 165fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedelvoid iommu_domain_free(struct iommu_domain *domain) 166fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 167e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (likely(domain->ops->domain_destroy != NULL)) 168e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel domain->ops->domain_destroy(domain); 169e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 170fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel kfree(domain); 171fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 172fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg RoedelEXPORT_SYMBOL_GPL(iommu_domain_free); 173fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 174fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedelint iommu_attach_device(struct iommu_domain *domain, struct device *dev) 175fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 176e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->attach_dev == NULL)) 177e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return -ENODEV; 178e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 179e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return domain->ops->attach_dev(domain, dev); 180fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 181fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg RoedelEXPORT_SYMBOL_GPL(iommu_attach_device); 182fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 183fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedelvoid iommu_detach_device(struct iommu_domain *domain, struct device *dev) 184fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 185e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->detach_dev == NULL)) 186e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return; 187e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 188e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel domain->ops->detach_dev(domain, dev); 189fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 190fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg RoedelEXPORT_SYMBOL_GPL(iommu_detach_device); 191fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel 192fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedelphys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, 193fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel unsigned long iova) 194fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel{ 195e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->iova_to_phys == NULL)) 196e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return 0; 197e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 198e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return domain->ops->iova_to_phys(domain, iova); 199fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg Roedel} 200fc2100eb4d0960b56c2c705a97941c08fb1c0fd4Joerg RoedelEXPORT_SYMBOL_GPL(iommu_iova_to_phys); 201dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng Yang 202dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng Yangint iommu_domain_has_cap(struct iommu_domain *domain, 203dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng Yang unsigned long cap) 204dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng Yang{ 205e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->domain_has_cap == NULL)) 206e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return 0; 207e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 208e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return domain->ops->domain_has_cap(domain, cap); 209dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng Yang} 210dbb9fd8630e95b6155aff658a2b5f80e95ca2bc6Sheng YangEXPORT_SYMBOL_GPL(iommu_domain_has_cap); 211cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 212cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedelint iommu_map(struct iommu_domain *domain, unsigned long iova, 2137d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen phys_addr_t paddr, size_t size, int prot) 214cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel{ 2157d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned long orig_iova = iova; 2167d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned int min_pagesz; 2177d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen size_t orig_size = size; 2187d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen int ret = 0; 219cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 220e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->map == NULL)) 221e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return -ENODEV; 222cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 2237d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* find out the minimum page size supported */ 2247d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap); 2257d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2267d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* 2277d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * both the virtual address and the physical one, as well as 2287d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * the size of the mapping, must be aligned (at least) to the 2297d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * size of the smallest page supported by the hardware 2307d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen */ 2317d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { 2327d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz " 2337d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen "0x%x\n", iova, (unsigned long)paddr, 2347d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen (unsigned long)size, min_pagesz); 2357d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen return -EINVAL; 2367d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen } 2377d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2387d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova, 2397d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen (unsigned long)paddr, (unsigned long)size); 2407d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2417d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen while (size) { 2427d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned long pgsize, addr_merge = iova | paddr; 2437d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned int pgsize_idx; 2447d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2457d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* Max page size that still fits into 'size' */ 2467d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize_idx = __fls(size); 2477d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2487d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* need to consider alignment requirements ? */ 2497d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (likely(addr_merge)) { 2507d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* Max page size allowed by both iova and paddr */ 2517d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned int align_pgsize_idx = __ffs(addr_merge); 2527d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2537d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize_idx = min(pgsize_idx, align_pgsize_idx); 2547d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen } 2557d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2567d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* build a mask of acceptable page sizes */ 2577d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize = (1UL << (pgsize_idx + 1)) - 1; 2587d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2597d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* throw away page sizes not supported by the hardware */ 2607d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize &= domain->ops->pgsize_bitmap; 261cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 2627d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* make sure we're still sane */ 2637d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen BUG_ON(!pgsize); 264cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 2657d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* pick the biggest page */ 2667d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize_idx = __fls(pgsize); 2677d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pgsize = 1UL << pgsize_idx; 2687d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2697d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova, 2707d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen (unsigned long)paddr, pgsize); 2717d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2727d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen ret = domain->ops->map(domain, iova, paddr, pgsize, prot); 2737d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (ret) 2747d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen break; 2757d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2767d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen iova += pgsize; 2777d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen paddr += pgsize; 2787d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen size -= pgsize; 2797d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen } 2807d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2817d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* unroll mapping in case something went wrong */ 2827d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (ret) 2837d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen iommu_unmap(domain, orig_iova, orig_size - size); 2847d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 2857d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen return ret; 286cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel} 287cefc53c7f494240d4813c80154c7617452d1904dJoerg RoedelEXPORT_SYMBOL_GPL(iommu_map); 288cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 2897d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohensize_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) 290cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel{ 2917d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen size_t unmapped_page, unmapped = 0; 2927d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unsigned int min_pagesz; 293cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel 294e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel if (unlikely(domain->ops->unmap == NULL)) 295e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel return -ENODEV; 296e5aa7f00776f2d73f410ede5c1f68246cdc83de1Joerg Roedel 2977d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* find out the minimum page size supported */ 2987d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap); 2997d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3007d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* 3017d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * The virtual address, as well as the size of the mapping, must be 3027d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * aligned (at least) to the size of the smallest page supported 3037d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * by the hardware 3047d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen */ 3057d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (!IS_ALIGNED(iova | size, min_pagesz)) { 3067d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n", 3077d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen iova, (unsigned long)size, min_pagesz); 3087d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen return -EINVAL; 3097d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen } 3107d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3117d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova, 3127d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen (unsigned long)size); 3137d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3147d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen /* 3157d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * Keep iterating until we either unmap 'size' bytes (or more) 3167d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen * or we hit an area that isn't mapped. 3177d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen */ 3187d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen while (unmapped < size) { 3197d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen size_t left = size - unmapped; 3207d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3217d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unmapped_page = domain->ops->unmap(domain, iova, left); 3227d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen if (!unmapped_page) 3237d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen break; 3247d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3257d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen pr_debug("unmapped: iova 0x%lx size %lx\n", iova, 3267d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen (unsigned long)unmapped_page); 3277d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3287d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen iova += unmapped_page; 3297d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen unmapped += unmapped_page; 3307d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen } 3317d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen 3327d3002cc8c160dbda0e6ab9cd66dc6eb401b8b70Ohad Ben-Cohen return unmapped; 333cefc53c7f494240d4813c80154c7617452d1904dJoerg Roedel} 334cefc53c7f494240d4813c80154c7617452d1904dJoerg RoedelEXPORT_SYMBOL_GPL(iommu_unmap); 3351460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 3361460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamsonint iommu_device_group(struct device *dev, unsigned int *groupid) 3371460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson{ 3381460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group) 3391460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return dev->bus->iommu_ops->device_group(dev, groupid); 3401460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson 3411460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson return -ENODEV; 3421460432cb513f0c16136ed132c20ecfbf8ccf942Alex Williamson} 3431460432cb513f0c16136ed132c20ecfbf8ccf942Alex WilliamsonEXPORT_SYMBOL_GPL(iommu_device_group); 344