diff --git a/[refs] b/[refs] index 0fde5eddbf2c..d3b87d68bd53 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 7d43c2e42cb1e436f97c1763150e4e1122ae0d57 +refs/heads/master: 4e0ee78f2af96676c9dca898c13250f62c513058 diff --git a/trunk/Documentation/ABI/testing/sysfs-kernel-iommu_groups b/trunk/Documentation/ABI/testing/sysfs-kernel-iommu_groups deleted file mode 100644 index 9b31556cfdda..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-kernel-iommu_groups +++ /dev/null @@ -1,14 +0,0 @@ -What: /sys/kernel/iommu_groups/ -Date: May 2012 -KernelVersion: v3.5 -Contact: Alex Williamson -Description: /sys/kernel/iommu_groups/ contains a number of sub- - directories, each representing an IOMMU group. The - name of the sub-directory matches the iommu_group_id() - for the group, which is an integer value. Within each - subdirectory is another directory named "devices" with - links to the sysfs devices contained in this group. - The group directory also optionally contains a "name" - file if the IOMMU driver has chosen to register a more - common name for the group. -Users: diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index d2f4f7acc435..a92c5ebf373e 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1134,6 +1134,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. forcesac soft pt [x86, IA-64] + group_mf [x86, IA-64] io7= [HW] IO7 for Marvel based alpha systems diff --git a/trunk/arch/ia64/include/asm/iommu.h b/trunk/arch/ia64/include/asm/iommu.h index 105c93b00b1b..b6a809fa2995 100644 --- a/trunk/arch/ia64/include/asm/iommu.h +++ b/trunk/arch/ia64/include/asm/iommu.h @@ -11,10 +11,12 @@ extern void no_iommu_init(void); extern int force_iommu, no_iommu; extern int iommu_pass_through; extern int iommu_detected; +extern int iommu_group_mf; #else #define iommu_pass_through (0) #define no_iommu (1) #define iommu_detected (0) +#define iommu_group_mf (0) #endif extern void iommu_dma_init(void); extern void machvec_init(const char *name); diff --git a/trunk/arch/ia64/kernel/pci-dma.c b/trunk/arch/ia64/kernel/pci-dma.c index 1ddcfe5ef353..7cdc89b2483c 100644 --- a/trunk/arch/ia64/kernel/pci-dma.c +++ b/trunk/arch/ia64/kernel/pci-dma.c @@ -32,6 +32,7 @@ int force_iommu __read_mostly; #endif int iommu_pass_through; +int iommu_group_mf; /* Dummy device used for NULL arguments (normally ISA). Better would be probably a smaller DMA mask, but this is bug-to-bug compatible diff --git a/trunk/arch/x86/include/asm/iommu.h b/trunk/arch/x86/include/asm/iommu.h index 345c99cef152..dffc38ee6255 100644 --- a/trunk/arch/x86/include/asm/iommu.h +++ b/trunk/arch/x86/include/asm/iommu.h @@ -5,6 +5,7 @@ extern struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; extern int iommu_detected; extern int iommu_pass_through; +extern int iommu_group_mf; /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) diff --git a/trunk/arch/x86/kernel/pci-dma.c b/trunk/arch/x86/kernel/pci-dma.c index de2b7ad70273..c0f420f76cd3 100644 --- a/trunk/arch/x86/kernel/pci-dma.c +++ b/trunk/arch/x86/kernel/pci-dma.c @@ -45,6 +45,15 @@ int iommu_detected __read_mostly = 0; */ int iommu_pass_through __read_mostly; +/* + * Group multi-function PCI devices into a single device-group for the + * iommu_device_group interface. This tells the iommu driver to pretend + * it cannot distinguish between functions of a device, exposing only one + * group for the device. Useful for disallowing use of individual PCI + * functions from userspace drivers. + */ +int iommu_group_mf __read_mostly; + extern struct iommu_table_entry __iommu_table[], __iommu_table_end[]; /* Dummy device used for NULL arguments (normally ISA). */ @@ -185,6 +194,8 @@ static __init int iommu_setup(char *p) #endif if (!strncmp(p, "pt", 2)) iommu_pass_through = 1; + if (!strncmp(p, "group_mf", 8)) + iommu_group_mf = 1; gart_parse_options(p); diff --git a/trunk/drivers/iommu/Kconfig b/trunk/drivers/iommu/Kconfig index 340893727538..4826af62a9de 100644 --- a/trunk/drivers/iommu/Kconfig +++ b/trunk/drivers/iommu/Kconfig @@ -13,6 +13,10 @@ menuconfig IOMMU_SUPPORT if IOMMU_SUPPORT +config OF_IOMMU + def_bool y + depends on OF + # MSM IOMMU support config MSM_IOMMU bool "MSM IOMMU Support" diff --git a/trunk/drivers/iommu/Makefile b/trunk/drivers/iommu/Makefile index 76e54ef796de..14a4d5fc94fa 100644 --- a/trunk/drivers/iommu/Makefile +++ b/trunk/drivers/iommu/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_IOMMU_API) += iommu.o +obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o diff --git a/trunk/drivers/iommu/amd_iommu.c b/trunk/drivers/iommu/amd_iommu.c index 49172393d6ec..a2e418cba0ff 100644 --- a/trunk/drivers/iommu/amd_iommu.c +++ b/trunk/drivers/iommu/amd_iommu.c @@ -254,21 +254,11 @@ static bool check_device(struct device *dev) return true; } -static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) -{ - pci_dev_put(*from); - *from = to; -} - -#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) - static int iommu_init_device(struct device *dev) { - struct pci_dev *dma_pdev, *pdev = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); struct iommu_dev_data *dev_data; - struct iommu_group *group; u16 alias; - int ret; if (dev->archdata.iommu) return 0; @@ -289,43 +279,8 @@ static int iommu_init_device(struct device *dev) return -ENOTSUPP; } dev_data->alias_data = alias_data; - - dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); - } else - dma_pdev = pci_dev_get(pdev); - - swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); - - if (dma_pdev->multifunction && - !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) - swap_pci_ref(&dma_pdev, - pci_get_slot(dma_pdev->bus, - PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), - 0))); - - while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) - break; - - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); } - group = iommu_group_get(&dma_pdev->dev); - pci_dev_put(dma_pdev); - if (!group) { - group = iommu_group_alloc(); - if (IS_ERR(group)) - return PTR_ERR(group); - } - - ret = iommu_group_add_device(group, dev); - - iommu_group_put(group); - - if (ret) - return ret; - if (pci_iommuv2_capable(pdev)) { struct amd_iommu *iommu; @@ -354,8 +309,6 @@ static void iommu_ignore_device(struct device *dev) static void iommu_uninit_device(struct device *dev) { - iommu_group_remove_device(dev); - /* * Nothing to do here - we keep dev_data around for unplugged devices * and reuse it when the device is re-plugged - not doing so would @@ -3274,6 +3227,26 @@ static int amd_iommu_domain_has_cap(struct iommu_domain *domain, return 0; } +static int amd_iommu_device_group(struct device *dev, unsigned int *groupid) +{ + struct iommu_dev_data *dev_data = dev->archdata.iommu; + struct pci_dev *pdev = to_pci_dev(dev); + u16 devid; + + if (!dev_data) + return -ENODEV; + + if (pdev->is_virtfn || !iommu_group_mf) + devid = dev_data->devid; + else + devid = calc_devid(pdev->bus->number, + PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + + *groupid = amd_iommu_alias_table[devid]; + + return 0; +} + static struct iommu_ops amd_iommu_ops = { .domain_init = amd_iommu_domain_init, .domain_destroy = amd_iommu_domain_destroy, @@ -3283,6 +3256,7 @@ static struct iommu_ops amd_iommu_ops = { .unmap = amd_iommu_unmap, .iova_to_phys = amd_iommu_iova_to_phys, .domain_has_cap = amd_iommu_domain_has_cap, + .device_group = amd_iommu_device_group, .pgsize_bitmap = AMD_IOMMU_PGSIZES, }; diff --git a/trunk/drivers/iommu/intel-iommu.c b/trunk/drivers/iommu/intel-iommu.c index ebf2b310cdde..b12af2ff8c54 100644 --- a/trunk/drivers/iommu/intel-iommu.c +++ b/trunk/drivers/iommu/intel-iommu.c @@ -4090,70 +4090,52 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain, return 0; } -static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) +/* + * Group numbers are arbitrary. Device with the same group number + * indicate the iommu cannot differentiate between them. To avoid + * tracking used groups we just use the seg|bus|devfn of the lowest + * level we're able to differentiate devices + */ +static int intel_iommu_device_group(struct device *dev, unsigned int *groupid) { - pci_dev_put(*from); - *from = to; -} + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev *bridge; + union { + struct { + u8 devfn; + u8 bus; + u16 segment; + } pci; + u32 group; + } id; -#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) + if (iommu_no_mapping(dev)) + return -ENODEV; -static int intel_iommu_add_device(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct pci_dev *bridge, *dma_pdev; - struct iommu_group *group; - int ret; + id.pci.segment = pci_domain_nr(pdev->bus); + id.pci.bus = pdev->bus->number; + id.pci.devfn = pdev->devfn; - if (!device_to_iommu(pci_domain_nr(pdev->bus), - pdev->bus->number, pdev->devfn)) + if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn)) return -ENODEV; bridge = pci_find_upstream_pcie_bridge(pdev); if (bridge) { - if (pci_is_pcie(bridge)) - dma_pdev = pci_get_domain_bus_and_slot( - pci_domain_nr(pdev->bus), - bridge->subordinate->number, 0); - else - dma_pdev = pci_dev_get(bridge); - } else - dma_pdev = pci_dev_get(pdev); - - swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); - - if (dma_pdev->multifunction && - !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) - swap_pci_ref(&dma_pdev, - pci_get_slot(dma_pdev->bus, - PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), - 0))); - - while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) - break; - - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); - } - - group = iommu_group_get(&dma_pdev->dev); - pci_dev_put(dma_pdev); - if (!group) { - group = iommu_group_alloc(); - if (IS_ERR(group)) - return PTR_ERR(group); + if (pci_is_pcie(bridge)) { + id.pci.bus = bridge->subordinate->number; + id.pci.devfn = 0; + } else { + id.pci.bus = bridge->bus->number; + id.pci.devfn = bridge->devfn; + } } - ret = iommu_group_add_device(group, dev); + if (!pdev->is_virtfn && iommu_group_mf) + id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0); - iommu_group_put(group); - return ret; -} + *groupid = id.group; -static void intel_iommu_remove_device(struct device *dev) -{ - iommu_group_remove_device(dev); + return 0; } static struct iommu_ops intel_iommu_ops = { @@ -4165,8 +4147,7 @@ static struct iommu_ops intel_iommu_ops = { .unmap = intel_iommu_unmap, .iova_to_phys = intel_iommu_iova_to_phys, .domain_has_cap = intel_iommu_domain_has_cap, - .add_device = intel_iommu_add_device, - .remove_device = intel_iommu_remove_device, + .device_group = intel_iommu_device_group, .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; diff --git a/trunk/drivers/iommu/iommu.c b/trunk/drivers/iommu/iommu.c index 0e928acd7dcf..8b9ded88e6f5 100644 --- a/trunk/drivers/iommu/iommu.c +++ b/trunk/drivers/iommu/iommu.c @@ -26,535 +26,60 @@ #include #include #include -#include -#include -#include - -static struct kset *iommu_group_kset; -static struct ida iommu_group_ida; -static struct mutex iommu_group_mutex; - -struct iommu_group { - struct kobject kobj; - struct kobject *devices_kobj; - struct list_head devices; - struct mutex mutex; - struct blocking_notifier_head notifier; - void *iommu_data; - void (*iommu_data_release)(void *iommu_data); - char *name; - int id; -}; - -struct iommu_device { - struct list_head list; - struct device *dev; - char *name; -}; - -struct iommu_group_attribute { - struct attribute attr; - ssize_t (*show)(struct iommu_group *group, char *buf); - ssize_t (*store)(struct iommu_group *group, - const char *buf, size_t count); -}; - -#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ -struct iommu_group_attribute iommu_group_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -#define to_iommu_group_attr(_attr) \ - container_of(_attr, struct iommu_group_attribute, attr) -#define to_iommu_group(_kobj) \ - container_of(_kobj, struct iommu_group, kobj) - -static ssize_t iommu_group_attr_show(struct kobject *kobj, - struct attribute *__attr, char *buf) -{ - struct iommu_group_attribute *attr = to_iommu_group_attr(__attr); - struct iommu_group *group = to_iommu_group(kobj); - ssize_t ret = -EIO; - - if (attr->show) - ret = attr->show(group, buf); - return ret; -} - -static ssize_t iommu_group_attr_store(struct kobject *kobj, - struct attribute *__attr, - const char *buf, size_t count) -{ - struct iommu_group_attribute *attr = to_iommu_group_attr(__attr); - struct iommu_group *group = to_iommu_group(kobj); - ssize_t ret = -EIO; - - if (attr->store) - ret = attr->store(group, buf, count); - return ret; -} - -static const struct sysfs_ops iommu_group_sysfs_ops = { - .show = iommu_group_attr_show, - .store = iommu_group_attr_store, -}; - -static int iommu_group_create_file(struct iommu_group *group, - struct iommu_group_attribute *attr) -{ - return sysfs_create_file(&group->kobj, &attr->attr); -} - -static void iommu_group_remove_file(struct iommu_group *group, - struct iommu_group_attribute *attr) -{ - sysfs_remove_file(&group->kobj, &attr->attr); -} - -static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf) -{ - return sprintf(buf, "%s\n", group->name); -} - -static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); - -static void iommu_group_release(struct kobject *kobj) -{ - struct iommu_group *group = to_iommu_group(kobj); - - if (group->iommu_data_release) - group->iommu_data_release(group->iommu_data); - - mutex_lock(&iommu_group_mutex); - ida_remove(&iommu_group_ida, group->id); - mutex_unlock(&iommu_group_mutex); - - kfree(group->name); - kfree(group); -} - -static struct kobj_type iommu_group_ktype = { - .sysfs_ops = &iommu_group_sysfs_ops, - .release = iommu_group_release, -}; -/** - * iommu_group_alloc - Allocate a new group - * @name: Optional name to associate with group, visible in sysfs - * - * This function is called by an iommu driver to allocate a new iommu - * group. The iommu group represents the minimum granularity of the iommu. - * Upon successful return, the caller holds a reference to the supplied - * group in order to hold the group until devices are added. Use - * iommu_group_put() to release this extra reference count, allowing the - * group to be automatically reclaimed once it has no devices or external - * references. - */ -struct iommu_group *iommu_group_alloc(void) +static ssize_t show_iommu_group(struct device *dev, + struct device_attribute *attr, char *buf) { - struct iommu_group *group; - int ret; - - group = kzalloc(sizeof(*group), GFP_KERNEL); - if (!group) - return ERR_PTR(-ENOMEM); - - group->kobj.kset = iommu_group_kset; - mutex_init(&group->mutex); - INIT_LIST_HEAD(&group->devices); - BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier); - - mutex_lock(&iommu_group_mutex); - -again: - if (unlikely(0 == ida_pre_get(&iommu_group_ida, GFP_KERNEL))) { - kfree(group); - mutex_unlock(&iommu_group_mutex); - return ERR_PTR(-ENOMEM); - } - - if (-EAGAIN == ida_get_new(&iommu_group_ida, &group->id)) - goto again; - - mutex_unlock(&iommu_group_mutex); + unsigned int groupid; - ret = kobject_init_and_add(&group->kobj, &iommu_group_ktype, - NULL, "%d", group->id); - if (ret) { - mutex_lock(&iommu_group_mutex); - ida_remove(&iommu_group_ida, group->id); - mutex_unlock(&iommu_group_mutex); - kfree(group); - return ERR_PTR(ret); - } - - group->devices_kobj = kobject_create_and_add("devices", &group->kobj); - if (!group->devices_kobj) { - kobject_put(&group->kobj); /* triggers .release & free */ - return ERR_PTR(-ENOMEM); - } - - /* - * The devices_kobj holds a reference on the group kobject, so - * as long as that exists so will the group. We can therefore - * use the devices_kobj for reference counting. - */ - kobject_put(&group->kobj); - - return group; -} -EXPORT_SYMBOL_GPL(iommu_group_alloc); + if (iommu_device_group(dev, &groupid)) + return 0; -/** - * iommu_group_get_iommudata - retrieve iommu_data registered for a group - * @group: the group - * - * iommu drivers can store data in the group for use when doing iommu - * operations. This function provides a way to retrieve it. Caller - * should hold a group reference. - */ -void *iommu_group_get_iommudata(struct iommu_group *group) -{ - return group->iommu_data; + return sprintf(buf, "%u", groupid); } -EXPORT_SYMBOL_GPL(iommu_group_get_iommudata); +static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL); -/** - * iommu_group_set_iommudata - set iommu_data for a group - * @group: the group - * @iommu_data: new data - * @release: release function for iommu_data - * - * iommu drivers can store data in the group for use when doing iommu - * operations. This function provides a way to set the data after - * the group has been allocated. Caller should hold a group reference. - */ -void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data, - void (*release)(void *iommu_data)) +static int add_iommu_group(struct device *dev, void *data) { - group->iommu_data = iommu_data; - group->iommu_data_release = release; -} -EXPORT_SYMBOL_GPL(iommu_group_set_iommudata); + unsigned int groupid; -/** - * iommu_group_set_name - set name for a group - * @group: the group - * @name: name - * - * Allow iommu driver to set a name for a group. When set it will - * appear in a name attribute file under the group in sysfs. - */ -int iommu_group_set_name(struct iommu_group *group, const char *name) -{ - int ret; - - if (group->name) { - iommu_group_remove_file(group, &iommu_group_attr_name); - kfree(group->name); - group->name = NULL; - if (!name) - return 0; - } - - group->name = kstrdup(name, GFP_KERNEL); - if (!group->name) - return -ENOMEM; - - ret = iommu_group_create_file(group, &iommu_group_attr_name); - if (ret) { - kfree(group->name); - group->name = NULL; - return ret; - } + if (iommu_device_group(dev, &groupid) == 0) + return device_create_file(dev, &dev_attr_iommu_group); return 0; } -EXPORT_SYMBOL_GPL(iommu_group_set_name); -/** - * iommu_group_add_device - add a device to an iommu group - * @group: the group into which to add the device (reference should be held) - * @dev: the device - * - * This function is called by an iommu driver to add a device into a - * group. Adding a device increments the group reference count. - */ -int iommu_group_add_device(struct iommu_group *group, struct device *dev) +static int remove_iommu_group(struct device *dev) { - int ret, i = 0; - struct iommu_device *device; - - device = kzalloc(sizeof(*device), GFP_KERNEL); - if (!device) - return -ENOMEM; - - device->dev = dev; + unsigned int groupid; - ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group"); - if (ret) { - kfree(device); - return ret; - } - - device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj)); -rename: - if (!device->name) { - sysfs_remove_link(&dev->kobj, "iommu_group"); - kfree(device); - return -ENOMEM; - } + if (iommu_device_group(dev, &groupid) == 0) + device_remove_file(dev, &dev_attr_iommu_group); - ret = sysfs_create_link_nowarn(group->devices_kobj, - &dev->kobj, device->name); - if (ret) { - kfree(device->name); - if (ret == -EEXIST && i >= 0) { - /* - * Account for the slim chance of collision - * and append an instance to the name. - */ - device->name = kasprintf(GFP_KERNEL, "%s.%d", - kobject_name(&dev->kobj), i++); - goto rename; - } - - sysfs_remove_link(&dev->kobj, "iommu_group"); - kfree(device); - return ret; - } - - kobject_get(group->devices_kobj); - - dev->iommu_group = group; - - mutex_lock(&group->mutex); - list_add_tail(&device->list, &group->devices); - mutex_unlock(&group->mutex); - - /* Notify any listeners about change to group. */ - blocking_notifier_call_chain(&group->notifier, - IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev); return 0; } -EXPORT_SYMBOL_GPL(iommu_group_add_device); -/** - * iommu_group_remove_device - remove a device from it's current group - * @dev: device to be removed - * - * This function is called by an iommu driver to remove the device from - * it's current group. This decrements the iommu group reference count. - */ -void iommu_group_remove_device(struct device *dev) -{ - struct iommu_group *group = dev->iommu_group; - struct iommu_device *tmp_device, *device = NULL; - - /* Pre-notify listeners that a device is being removed. */ - blocking_notifier_call_chain(&group->notifier, - IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev); - - mutex_lock(&group->mutex); - list_for_each_entry(tmp_device, &group->devices, list) { - if (tmp_device->dev == dev) { - device = tmp_device; - list_del(&device->list); - break; - } - } - mutex_unlock(&group->mutex); - - if (!device) - return; - - sysfs_remove_link(group->devices_kobj, device->name); - sysfs_remove_link(&dev->kobj, "iommu_group"); - - kfree(device->name); - kfree(device); - dev->iommu_group = NULL; - kobject_put(group->devices_kobj); -} -EXPORT_SYMBOL_GPL(iommu_group_remove_device); - -/** - * iommu_group_for_each_dev - iterate over each device in the group - * @group: the group - * @data: caller opaque data to be passed to callback function - * @fn: caller supplied callback function - * - * This function is called by group users to iterate over group devices. - * Callers should hold a reference count to the group during callback. - * The group->mutex is held across callbacks, which will block calls to - * iommu_group_add/remove_device. - */ -int iommu_group_for_each_dev(struct iommu_group *group, void *data, - int (*fn)(struct device *, void *)) -{ - struct iommu_device *device; - int ret = 0; - - mutex_lock(&group->mutex); - list_for_each_entry(device, &group->devices, list) { - ret = fn(device->dev, data); - if (ret) - break; - } - mutex_unlock(&group->mutex); - return ret; -} -EXPORT_SYMBOL_GPL(iommu_group_for_each_dev); - -/** - * iommu_group_get - Return the group for a device and increment reference - * @dev: get the group that this device belongs to - * - * This function is called by iommu drivers and users to get the group - * for the specified device. If found, the group is returned and the group - * reference in incremented, else NULL. - */ -struct iommu_group *iommu_group_get(struct device *dev) -{ - struct iommu_group *group = dev->iommu_group; - - if (group) - kobject_get(group->devices_kobj); - - return group; -} -EXPORT_SYMBOL_GPL(iommu_group_get); - -/** - * iommu_group_put - Decrement group reference - * @group: the group to use - * - * This function is called by iommu drivers and users to release the - * iommu group. Once the reference count is zero, the group is released. - */ -void iommu_group_put(struct iommu_group *group) -{ - if (group) - kobject_put(group->devices_kobj); -} -EXPORT_SYMBOL_GPL(iommu_group_put); - -/** - * iommu_group_register_notifier - Register a notifier for group changes - * @group: the group to watch - * @nb: notifier block to signal - * - * This function allows iommu group users to track changes in a group. - * See include/linux/iommu.h for actions sent via this notifier. Caller - * should hold a reference to the group throughout notifier registration. - */ -int iommu_group_register_notifier(struct iommu_group *group, - struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&group->notifier, nb); -} -EXPORT_SYMBOL_GPL(iommu_group_register_notifier); - -/** - * iommu_group_unregister_notifier - Unregister a notifier - * @group: the group to watch - * @nb: notifier block to signal - * - * Unregister a previously registered group notifier block. - */ -int iommu_group_unregister_notifier(struct iommu_group *group, - struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&group->notifier, nb); -} -EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier); - -/** - * iommu_group_id - Return ID for a group - * @group: the group to ID - * - * Return the unique ID for the group matching the sysfs group number. - */ -int iommu_group_id(struct iommu_group *group) -{ - return group->id; -} -EXPORT_SYMBOL_GPL(iommu_group_id); - -static int add_iommu_group(struct device *dev, void *data) -{ - struct iommu_ops *ops = data; - - if (!ops->add_device) - return -ENODEV; - - WARN_ON(dev->iommu_group); - - ops->add_device(dev); - - return 0; -} - -static int iommu_bus_notifier(struct notifier_block *nb, - unsigned long action, void *data) +static int iommu_device_notifier(struct notifier_block *nb, + unsigned long action, void *data) { struct device *dev = data; - struct iommu_ops *ops = dev->bus->iommu_ops; - struct iommu_group *group; - unsigned long group_action = 0; - - /* - * ADD/DEL call into iommu driver ops if provided, which may - * result in ADD/DEL notifiers to group->notifier - */ - if (action == BUS_NOTIFY_ADD_DEVICE) { - if (ops->add_device) - return ops->add_device(dev); - } else if (action == BUS_NOTIFY_DEL_DEVICE) { - if (ops->remove_device && dev->iommu_group) { - ops->remove_device(dev); - return 0; - } - } - /* - * Remaining BUS_NOTIFYs get filtered and republished to the - * group, if anyone is listening - */ - group = iommu_group_get(dev); - if (!group) - return 0; + if (action == BUS_NOTIFY_ADD_DEVICE) + return add_iommu_group(dev, NULL); + else if (action == BUS_NOTIFY_DEL_DEVICE) + return remove_iommu_group(dev); - switch (action) { - case BUS_NOTIFY_BIND_DRIVER: - group_action = IOMMU_GROUP_NOTIFY_BIND_DRIVER; - break; - case BUS_NOTIFY_BOUND_DRIVER: - group_action = IOMMU_GROUP_NOTIFY_BOUND_DRIVER; - break; - case BUS_NOTIFY_UNBIND_DRIVER: - group_action = IOMMU_GROUP_NOTIFY_UNBIND_DRIVER; - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - group_action = IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER; - break; - } - - if (group_action) - blocking_notifier_call_chain(&group->notifier, - group_action, dev); - - iommu_group_put(group); return 0; } -static struct notifier_block iommu_bus_nb = { - .notifier_call = iommu_bus_notifier, +static struct notifier_block iommu_device_nb = { + .notifier_call = iommu_device_notifier, }; static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) { - bus_register_notifier(bus, &iommu_bus_nb); - bus_for_each_dev(bus, NULL, ops, add_iommu_group); + bus_register_notifier(bus, &iommu_device_nb); + bus_for_each_dev(bus, NULL, NULL, add_iommu_group); } /** @@ -667,45 +192,6 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) } EXPORT_SYMBOL_GPL(iommu_detach_device); -/* - * IOMMU groups are really the natrual working unit of the IOMMU, but - * the IOMMU API works on domains and devices. Bridge that gap by - * iterating over the devices in a group. Ideally we'd have a single - * device which represents the requestor ID of the group, but we also - * allow IOMMU drivers to create policy defined minimum sets, where - * the physical hardware may be able to distiguish members, but we - * wish to group them at a higher level (ex. untrusted multi-function - * PCI devices). Thus we attach each device. - */ -static int iommu_group_do_attach_device(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - - return iommu_attach_device(domain, dev); -} - -int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group) -{ - return iommu_group_for_each_dev(group, domain, - iommu_group_do_attach_device); -} -EXPORT_SYMBOL_GPL(iommu_attach_group); - -static int iommu_group_do_detach_device(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - - iommu_detach_device(domain, dev); - - return 0; -} - -void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group) -{ - iommu_group_for_each_dev(group, domain, iommu_group_do_detach_device); -} -EXPORT_SYMBOL_GPL(iommu_detach_group); - phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova) { @@ -850,15 +336,11 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) } EXPORT_SYMBOL_GPL(iommu_unmap); -static int __init iommu_init(void) +int iommu_device_group(struct device *dev, unsigned int *groupid) { - iommu_group_kset = kset_create_and_add("iommu_groups", - NULL, kernel_kobj); - ida_init(&iommu_group_ida); - mutex_init(&iommu_group_mutex); + if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group) + return dev->bus->iommu_ops->device_group(dev, groupid); - BUG_ON(!iommu_group_kset); - - return 0; + return -ENODEV; } -subsys_initcall(iommu_init); +EXPORT_SYMBOL_GPL(iommu_device_group); diff --git a/trunk/drivers/iommu/of_iommu.c b/trunk/drivers/iommu/of_iommu.c new file mode 100644 index 000000000000..ee249bc959f8 --- /dev/null +++ b/trunk/drivers/iommu/of_iommu.c @@ -0,0 +1,90 @@ +/* + * OF helpers for IOMMU + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +/** + * of_get_dma_window - Parse *dma-window property and returns 0 if found. + * + * @dn: device node + * @prefix: prefix for property name if any + * @index: index to start to parse + * @busno: Returns busno if supported. Otherwise pass NULL + * @addr: Returns address that DMA starts + * @size: Returns the range that DMA can handle + * + * This supports different formats flexibly. "prefix" can be + * configured if any. "busno" and "index" are optionally + * specified. Set 0(or NULL) if not used. + */ +int of_get_dma_window(struct device_node *dn, const char *prefix, int index, + unsigned long *busno, dma_addr_t *addr, size_t *size) +{ + const __be32 *dma_window, *end; + int bytes, cur_index = 0; + char propname[NAME_MAX], addrname[NAME_MAX], sizename[NAME_MAX]; + + if (!dn || !addr || !size) + return -EINVAL; + + if (!prefix) + prefix = ""; + + snprintf(propname, sizeof(propname), "%sdma-window", prefix); + snprintf(addrname, sizeof(addrname), "%s#dma-address-cells", prefix); + snprintf(sizename, sizeof(sizename), "%s#dma-size-cells", prefix); + + dma_window = of_get_property(dn, propname, &bytes); + if (!dma_window) + return -ENODEV; + end = dma_window + bytes / sizeof(*dma_window); + + while (dma_window < end) { + u32 cells; + const void *prop; + + /* busno is one cell if supported */ + if (busno) + *busno = be32_to_cpup(dma_window++); + + prop = of_get_property(dn, addrname, NULL); + if (!prop) + prop = of_get_property(dn, "#address-cells", NULL); + + cells = prop ? be32_to_cpup(prop) : of_n_addr_cells(dn); + if (!cells) + return -EINVAL; + *addr = of_read_number(dma_window, cells); + dma_window += cells; + + prop = of_get_property(dn, sizename, NULL); + cells = prop ? be32_to_cpup(prop) : of_n_size_cells(dn); + if (!cells) + return -EINVAL; + *size = of_read_number(dma_window, cells); + dma_window += cells; + + if (cur_index++ == index) + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(of_get_dma_window); diff --git a/trunk/drivers/pci/access.c b/trunk/drivers/pci/access.c index ba91a7e17519..2a581642c237 100644 --- a/trunk/drivers/pci/access.c +++ b/trunk/drivers/pci/access.c @@ -162,8 +162,7 @@ int pci_user_read_config_##size \ if (ret > 0) \ ret = -EINVAL; \ return ret; \ -} \ -EXPORT_SYMBOL_GPL(pci_user_read_config_##size); +} /* Returns 0 on success, negative values indicate error. */ #define PCI_USER_WRITE_CONFIG(size,type) \ @@ -182,8 +181,7 @@ int pci_user_write_config_##size \ if (ret > 0) \ ret = -EINVAL; \ return ret; \ -} \ -EXPORT_SYMBOL_GPL(pci_user_write_config_##size); +} PCI_USER_READ_CONFIG(byte, u8) PCI_USER_READ_CONFIG(word, u16) diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index bdd16cfca33f..77cb54a65cde 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -2364,75 +2364,6 @@ void pci_enable_acs(struct pci_dev *dev) pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); } -/** - * pci_acs_enabled - test ACS against required flags for a given device - * @pdev: device to test - * @acs_flags: required PCI ACS flags - * - * Return true if the device supports the provided flags. Automatically - * filters out flags that are not implemented on multifunction devices. - */ -bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) -{ - int pos, ret; - u16 ctrl; - - ret = pci_dev_specific_acs_enabled(pdev, acs_flags); - if (ret >= 0) - return ret > 0; - - if (!pci_is_pcie(pdev)) - return false; - - /* Filter out flags not applicable to multifunction */ - if (pdev->multifunction) - acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | - PCI_ACS_EC | PCI_ACS_DT); - - if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM || - pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || - pdev->multifunction) { - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS); - if (!pos) - return false; - - pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); - if ((ctrl & acs_flags) != acs_flags) - return false; - } - - return true; -} - -/** - * pci_acs_path_enable - test ACS flags from start to end in a hierarchy - * @start: starting downstream device - * @end: ending upstream device or NULL to search to the root bus - * @acs_flags: required flags - * - * Walk up a device tree from start to end testing PCI ACS support. If - * any step along the way does not support the required flags, return false. - */ -bool pci_acs_path_enabled(struct pci_dev *start, - struct pci_dev *end, u16 acs_flags) -{ - struct pci_dev *pdev, *parent = start; - - do { - pdev = parent; - - if (!pci_acs_enabled(pdev, acs_flags)) - return false; - - if (pci_is_root_bus(pdev->bus)) - return (end == NULL); - - parent = pdev->bus->self; - } while (pdev != end); - - return true; -} - /** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index f2dcc46bdece..e4943479b234 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -86,6 +86,13 @@ static inline bool pci_is_bridge(struct pci_dev *pci_dev) return !!(pci_dev->subordinate); } +extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); +extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); +extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); +extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); +extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); +extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); + struct pci_vpd_ops { ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index 667643374155..194b243a2817 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -3205,87 +3205,3 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) return -ENOTTY; } - -static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) -{ - if (!PCI_FUNC(dev->devfn)) - return pci_dev_get(dev); - - return pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); -} - -static const struct pci_dev_dma_source { - u16 vendor; - u16 device; - struct pci_dev *(*dma_source)(struct pci_dev *dev); -} pci_dev_dma_source[] = { - /* - * https://bugzilla.redhat.com/show_bug.cgi?id=605888 - * - * Some Ricoh devices use the function 0 source ID for DMA on - * other functions of a multifunction device. The DMA devices - * is therefore function 0, which will have implications of the - * iommu grouping of these devices. - */ - { PCI_VENDOR_ID_RICOH, 0xe822, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe230, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe832, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe476, pci_func_0_dma_source }, - { 0 } -}; - -/* - * IOMMUs with isolation capabilities need to be programmed with the - * correct source ID of a device. In most cases, the source ID matches - * the device doing the DMA, but sometimes hardware is broken and will - * tag the DMA as being sourced from a different device. This function - * allows that translation. Note that the reference count of the - * returned device is incremented on all paths. - */ -struct pci_dev *pci_get_dma_source(struct pci_dev *dev) -{ - const struct pci_dev_dma_source *i; - - for (i = pci_dev_dma_source; i->dma_source; i++) { - if ((i->vendor == dev->vendor || - i->vendor == (u16)PCI_ANY_ID) && - (i->device == dev->device || - i->device == (u16)PCI_ANY_ID)) - return i->dma_source(dev); - } - - return pci_dev_get(dev); -} - -static const struct pci_dev_acs_enabled { - u16 vendor; - u16 device; - int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags); -} pci_dev_acs_enabled[] = { - { 0 } -}; - -int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) -{ - const struct pci_dev_acs_enabled *i; - int ret; - - /* - * Allow devices that do not expose standard PCIe ACS capabilities - * or control to indicate their support here. Multi-function express - * devices which do not allow internal peer-to-peer between functions, - * but do not implement PCIe ACS may wish to return true here. - */ - for (i = pci_dev_acs_enabled; i->acs_enabled; i++) { - if ((i->vendor == dev->vendor || - i->vendor == (u16)PCI_ANY_ID) && - (i->device == dev->device || - i->device == (u16)PCI_ANY_ID)) { - ret = i->acs_enabled(dev, acs_flags); - if (ret >= 0) - return ret; - } - } - - return -ENOTTY; -} diff --git a/trunk/drivers/xen/xen-pciback/conf_space.c b/trunk/drivers/xen/xen-pciback/conf_space.c index 46ae0f9f02ad..30d7be026c18 100644 --- a/trunk/drivers/xen/xen-pciback/conf_space.c +++ b/trunk/drivers/xen/xen-pciback/conf_space.c @@ -124,7 +124,7 @@ static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask, return val; } -static int xen_pcibios_err_to_errno(int err) +static int pcibios_err_to_errno(int err) { switch (err) { case PCIBIOS_SUCCESSFUL: @@ -202,7 +202,7 @@ int xen_pcibk_config_read(struct pci_dev *dev, int offset, int size, pci_name(dev), size, offset, value); *ret_val = value; - return xen_pcibios_err_to_errno(err); + return pcibios_err_to_errno(err); } int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value) @@ -290,7 +290,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value) } } - return xen_pcibios_err_to_errno(err); + return pcibios_err_to_errno(err); } void xen_pcibk_config_free_dyn_fields(struct pci_dev *dev) diff --git a/trunk/include/linux/device.h b/trunk/include/linux/device.h index d0e4d99405ae..161d96241b1b 100644 --- a/trunk/include/linux/device.h +++ b/trunk/include/linux/device.h @@ -36,7 +36,6 @@ struct subsys_private; struct bus_type; struct device_node; struct iommu_ops; -struct iommu_group; struct bus_attribute { struct attribute attr; @@ -688,7 +687,6 @@ struct device { const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev); - struct iommu_group *iommu_group; }; /* Get the wakeup routines, which depend on struct device */ diff --git a/trunk/include/linux/iommu.h b/trunk/include/linux/iommu.h index a71df92be992..450293f6d68b 100644 --- a/trunk/include/linux/iommu.h +++ b/trunk/include/linux/iommu.h @@ -26,7 +26,6 @@ #define IOMMU_CACHE (4) /* DMA cache coherency */ struct iommu_ops; -struct iommu_group; struct bus_type; struct device; struct iommu_domain; @@ -61,8 +60,6 @@ struct iommu_domain { * @iova_to_phys: translate iova to physical address * @domain_has_cap: domain capabilities query * @commit: commit iommu domain - * @add_device: add device to iommu grouping - * @remove_device: remove device from iommu grouping * @pgsize_bitmap: bitmap of supported page sizes */ struct iommu_ops { @@ -78,18 +75,10 @@ struct iommu_ops { unsigned long iova); int (*domain_has_cap)(struct iommu_domain *domain, unsigned long cap); - int (*add_device)(struct device *dev); - void (*remove_device)(struct device *dev); + int (*device_group)(struct device *dev, unsigned int *groupid); unsigned long pgsize_bitmap; }; -#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */ -#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */ -#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */ -#define IOMMU_GROUP_NOTIFY_BOUND_DRIVER 4 /* Post Driver bind */ -#define IOMMU_GROUP_NOTIFY_UNBIND_DRIVER 5 /* Pre Driver unbind */ -#define IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER 6 /* Post Driver unbind */ - extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops); extern bool iommu_present(struct bus_type *bus); extern struct iommu_domain *iommu_domain_alloc(struct bus_type *bus); @@ -108,29 +97,7 @@ extern int iommu_domain_has_cap(struct iommu_domain *domain, unsigned long cap); extern void iommu_set_fault_handler(struct iommu_domain *domain, iommu_fault_handler_t handler, void *token); - -extern int iommu_attach_group(struct iommu_domain *domain, - struct iommu_group *group); -extern void iommu_detach_group(struct iommu_domain *domain, - struct iommu_group *group); -extern struct iommu_group *iommu_group_alloc(void); -extern void *iommu_group_get_iommudata(struct iommu_group *group); -extern void iommu_group_set_iommudata(struct iommu_group *group, - void *iommu_data, - void (*release)(void *iommu_data)); -extern int iommu_group_set_name(struct iommu_group *group, const char *name); -extern int iommu_group_add_device(struct iommu_group *group, - struct device *dev); -extern void iommu_group_remove_device(struct device *dev); -extern int iommu_group_for_each_dev(struct iommu_group *group, void *data, - int (*fn)(struct device *, void *)); -extern struct iommu_group *iommu_group_get(struct device *dev); -extern void iommu_group_put(struct iommu_group *group); -extern int iommu_group_register_notifier(struct iommu_group *group, - struct notifier_block *nb); -extern int iommu_group_unregister_notifier(struct iommu_group *group, - struct notifier_block *nb); -extern int iommu_group_id(struct iommu_group *group); +extern int iommu_device_group(struct device *dev, unsigned int *groupid); /** * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework @@ -175,7 +142,6 @@ static inline int report_iommu_fault(struct iommu_domain *domain, #else /* CONFIG_IOMMU_API */ struct iommu_ops {}; -struct iommu_group {}; static inline bool iommu_present(struct bus_type *bus) { @@ -231,75 +197,11 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain, { } -int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group) -{ - return -ENODEV; -} - -void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group) -{ -} - -struct iommu_group *iommu_group_alloc(void) -{ - return ERR_PTR(-ENODEV); -} - -void *iommu_group_get_iommudata(struct iommu_group *group) -{ - return NULL; -} - -void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data, - void (*release)(void *iommu_data)) -{ -} - -int iommu_group_set_name(struct iommu_group *group, const char *name) -{ - return -ENODEV; -} - -int iommu_group_add_device(struct iommu_group *group, struct device *dev) -{ - return -ENODEV; -} - -void iommu_group_remove_device(struct device *dev) -{ -} - -int iommu_group_for_each_dev(struct iommu_group *group, void *data, - int (*fn)(struct device *, void *)) -{ - return -ENODEV; -} - -struct iommu_group *iommu_group_get(struct device *dev) -{ - return NULL; -} - -void iommu_group_put(struct iommu_group *group) -{ -} - -int iommu_group_register_notifier(struct iommu_group *group, - struct notifier_block *nb) +static inline int iommu_device_group(struct device *dev, unsigned int *groupid) { return -ENODEV; } -int iommu_group_unregister_notifier(struct iommu_group *group, - struct notifier_block *nb) -{ - return 0; -} - -int iommu_group_id(struct iommu_group *group) -{ - return -ENODEV; -} #endif /* CONFIG_IOMMU_API */ #endif /* __LINUX_IOMMU_H */ diff --git a/trunk/include/linux/of_iommu.h b/trunk/include/linux/of_iommu.h new file mode 100644 index 000000000000..51a560f34bca --- /dev/null +++ b/trunk/include/linux/of_iommu.h @@ -0,0 +1,21 @@ +#ifndef __OF_IOMMU_H +#define __OF_IOMMU_H + +#ifdef CONFIG_OF_IOMMU + +extern int of_get_dma_window(struct device_node *dn, const char *prefix, + int index, unsigned long *busno, dma_addr_t *addr, + size_t *size); + +#else + +static inline int of_get_dma_window(struct device_node *dn, const char *prefix, + int index, unsigned long *busno, dma_addr_t *addr, + size_t *size) +{ + return -EINVAL; +} + +#endif /* CONFIG_OF_IOMMU */ + +#endif /* __OF_IOMMU_H */ diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 91f9b801515d..fefb4e19bf6a 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -476,32 +476,6 @@ static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { return false; #define PCIBIOS_SET_FAILED 0x88 #define PCIBIOS_BUFFER_TOO_SMALL 0x89 -/* - * Translate above to generic errno for passing back through non-pci. - */ -static inline int pcibios_err_to_errno(int err) -{ - if (err <= PCIBIOS_SUCCESSFUL) - return err; /* Assume already errno */ - - switch (err) { - case PCIBIOS_FUNC_NOT_SUPPORTED: - return -ENOENT; - case PCIBIOS_BAD_VENDOR_ID: - return -EINVAL; - case PCIBIOS_DEVICE_NOT_FOUND: - return -ENODEV; - case PCIBIOS_BAD_REGISTER_NUMBER: - return -EFAULT; - case PCIBIOS_SET_FAILED: - return -EIO; - case PCIBIOS_BUFFER_TOO_SMALL: - return -ENOSPC; - } - - return -ENOTTY; -} - /* Low-level architecture-dependent routines */ struct pci_ops { @@ -805,14 +779,6 @@ static inline int pci_write_config_dword(const struct pci_dev *dev, int where, return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); } -/* user-space driven config access */ -int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); -int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); -int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); -int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); -int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); -int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); - int __must_check pci_enable_device(struct pci_dev *dev); int __must_check pci_enable_device_io(struct pci_dev *dev); int __must_check pci_enable_device_mem(struct pci_dev *dev); @@ -1368,9 +1334,6 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) -{ return NULL; } - #define dev_is_pci(d) (false) #define dev_is_pf(d) (false) #define dev_num_vf(d) (0) @@ -1525,20 +1488,9 @@ enum pci_fixup_pass { #ifdef CONFIG_PCI_QUIRKS void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); -struct pci_dev *pci_get_dma_source(struct pci_dev *dev); -int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); #else static inline void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} -static inline struct pci_dev *pci_get_dma_source(struct pci_dev *dev) -{ - return pci_dev_get(dev); -} -static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, - u16 acs_flags) -{ - return -ENOTTY; -} #endif void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); @@ -1641,9 +1593,7 @@ static inline bool pci_is_pcie(struct pci_dev *dev) } void pci_request_acs(void); -bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags); -bool pci_acs_path_enabled(struct pci_dev *start, - struct pci_dev *end, u16 acs_flags); + #define PCI_VPD_LRDT 0x80 /* Large Resource Data Type */ #define PCI_VPD_LRDT_ID(x) (x | PCI_VPD_LRDT) diff --git a/trunk/include/linux/pci_regs.h b/trunk/include/linux/pci_regs.h index 526d2c4bc3a6..4b608f543412 100644 --- a/trunk/include/linux/pci_regs.h +++ b/trunk/include/linux/pci_regs.h @@ -26,7 +26,6 @@ * Under PCI, each device has 256 bytes of configuration address space, * of which the first 64 bytes are standardized as follows: */ -#define PCI_STD_HEADER_SIZEOF 64 #define PCI_VENDOR_ID 0x00 /* 16 bits */ #define PCI_DEVICE_ID 0x02 /* 16 bits */ #define PCI_COMMAND 0x04 /* 16 bits */ @@ -210,12 +209,9 @@ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ -#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ #define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ -#define PCI_CAP_ID_MAX PCI_CAP_ID_AF #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ #define PCI_CAP_SIZEOF 4 @@ -280,7 +276,6 @@ #define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ #define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ #define PCI_VPD_DATA 4 /* 32-bits of data returned here */ -#define PCI_CAP_VPD_SIZEOF 8 /* Slot Identification */ @@ -302,10 +297,8 @@ #define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ #define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ #define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ -#define PCI_MSI_PENDING_32 16 /* Pending intrs for 32-bit devices */ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ #define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ -#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */ /* MSI-X registers */ #define PCI_MSIX_FLAGS 2 @@ -315,7 +308,6 @@ #define PCI_MSIX_TABLE 4 #define PCI_MSIX_PBA 8 #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) -#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */ /* MSI-X entry's format */ #define PCI_MSIX_ENTRY_SIZE 16 @@ -346,7 +338,6 @@ #define PCI_AF_CTRL_FLR 0x01 #define PCI_AF_STATUS 5 #define PCI_AF_STATUS_TP 0x01 -#define PCI_CAP_AF_SIZEOF 6 /* size of AF registers */ /* PCI-X registers */ @@ -383,10 +374,6 @@ #define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ #define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ #define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ -#define PCI_X_ECC_CSR 8 /* ECC control and status */ -#define PCI_CAP_PCIX_SIZEOF_V0 8 /* size of registers for Version 0 */ -#define PCI_CAP_PCIX_SIZEOF_V1 24 /* size for Version 1 */ -#define PCI_CAP_PCIX_SIZEOF_V2 PCI_CAP_PCIX_SIZEOF_V1 /* Same for v2 */ /* PCI Bridge Subsystem ID registers */ @@ -475,7 +462,6 @@ #define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ #define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ #define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20 /* v1 endpoints end here */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ #define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ @@ -535,7 +521,6 @@ #define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ #define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ #define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 44 /* v2 endpoints end here */ #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ #define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ @@ -544,43 +529,23 @@ #define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) #define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) -#define PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ -#define PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel Capability */ -#define PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ -#define PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ -#define PCI_EXT_CAP_ID_RCLD 0x05 /* Root Complex Link Declaration */ -#define PCI_EXT_CAP_ID_RCILC 0x06 /* Root Complex Internal Link Control */ -#define PCI_EXT_CAP_ID_RCEC 0x07 /* Root Complex Event Collector */ -#define PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function VC Capability */ -#define PCI_EXT_CAP_ID_VC9 0x09 /* same as _VC */ -#define PCI_EXT_CAP_ID_RCRB 0x0A /* Root Complex RB? */ -#define PCI_EXT_CAP_ID_VNDR 0x0B /* Vendor Specific */ -#define PCI_EXT_CAP_ID_CAC 0x0C /* Config Access - obsolete */ -#define PCI_EXT_CAP_ID_ACS 0x0D /* Access Control Services */ -#define PCI_EXT_CAP_ID_ARI 0x0E /* Alternate Routing ID */ -#define PCI_EXT_CAP_ID_ATS 0x0F /* Address Translation Services */ -#define PCI_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MRIOV 0x11 /* Multi Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MCAST 0x12 /* Multicast */ -#define PCI_EXT_CAP_ID_PRI 0x13 /* Page Request Interface */ -#define PCI_EXT_CAP_ID_AMD_XXX 0x14 /* reserved for AMD */ -#define PCI_EXT_CAP_ID_REBAR 0x15 /* resizable BAR */ -#define PCI_EXT_CAP_ID_DPA 0x16 /* dynamic power alloc */ -#define PCI_EXT_CAP_ID_TPH 0x17 /* TPH request */ -#define PCI_EXT_CAP_ID_LTR 0x18 /* latency tolerance reporting */ -#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe */ -#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ -#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PASID - -#define PCI_EXT_CAP_DSN_SIZEOF 12 -#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 +#define PCI_EXT_CAP_ID_ERR 1 +#define PCI_EXT_CAP_ID_VC 2 +#define PCI_EXT_CAP_ID_DSN 3 +#define PCI_EXT_CAP_ID_PWR 4 +#define PCI_EXT_CAP_ID_VNDR 11 +#define PCI_EXT_CAP_ID_ACS 13 +#define PCI_EXT_CAP_ID_ARI 14 +#define PCI_EXT_CAP_ID_ATS 15 +#define PCI_EXT_CAP_ID_SRIOV 16 +#define PCI_EXT_CAP_ID_PRI 19 +#define PCI_EXT_CAP_ID_LTR 24 +#define PCI_EXT_CAP_ID_PASID 27 /* Advanced Error Reporting */ #define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ #define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ #define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ -#define PCI_ERR_UNC_SURPDN 0x00000020 /* Surprise Down */ #define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ #define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ #define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ @@ -590,11 +555,6 @@ #define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ #define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ #define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ -#define PCI_ERR_UNC_INTN 0x00400000 /* internal error */ -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */ -#define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */ -#define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */ #define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ /* Same bits as above */ #define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ @@ -605,9 +565,6 @@ #define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ #define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ #define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ -#define PCI_ERR_COR_ADV_NFAT 0x00002000 /* Advisory Non-Fatal */ -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ -#define PCI_ERR_COR_LOG_OVER 0x00008000 /* Header Log Overflow */ #define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ /* Same bits as above */ #define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ @@ -639,18 +596,12 @@ /* Virtual Channel */ #define PCI_VC_PORT_REG1 4 -#define PCI_VC_REG1_EVCC 0x7 /* extended vc count */ #define PCI_VC_PORT_REG2 8 -#define PCI_VC_REG2_32_PHASE 0x2 -#define PCI_VC_REG2_64_PHASE 0x4 -#define PCI_VC_REG2_128_PHASE 0x8 #define PCI_VC_PORT_CTRL 12 #define PCI_VC_PORT_STATUS 14 #define PCI_VC_RES_CAP 16 #define PCI_VC_RES_CTRL 20 #define PCI_VC_RES_STATUS 26 -#define PCI_CAP_VC_BASE_SIZEOF 0x10 -#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C /* Power Budgeting */ #define PCI_PWR_DSR 4 /* Data Select Register */ @@ -663,7 +614,6 @@ #define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ #define PCI_PWR_CAP 12 /* Capability */ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ -#define PCI_EXT_CAP_PWR_SIZEOF 16 /* * Hypertransport sub capability types @@ -696,8 +646,6 @@ #define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ #define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ #define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ -#define HT_CAP_SIZEOF_LONG 28 /* slave & primary */ -#define HT_CAP_SIZEOF_SHORT 24 /* host & secondary */ /* Alternative Routing-ID Interpretation */ #define PCI_ARI_CAP 0x04 /* ARI Capability Register */ @@ -708,7 +656,6 @@ #define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ #define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ #define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ -#define PCI_EXT_CAP_ARI_SIZEOF 8 /* Address Translation Service */ #define PCI_ATS_CAP 0x04 /* ATS Capability Register */ @@ -718,7 +665,6 @@ #define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ #define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ #define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ -#define PCI_EXT_CAP_ATS_SIZEOF 8 /* Page Request Interface */ #define PCI_PRI_CTRL 0x04 /* PRI control register */ @@ -730,7 +676,6 @@ #define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */ #define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */ #define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */ -#define PCI_EXT_CAP_PRI_SIZEOF 16 /* PASID capability */ #define PCI_PASID_CAP 0x04 /* PASID feature register */ @@ -740,7 +685,6 @@ #define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */ #define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */ #define PCI_PASID_CTRL_PRIV 0x04 /* Priviledge Mode Enable */ -#define PCI_EXT_CAP_PASID_SIZEOF 8 /* Single Root I/O Virtualization */ #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ @@ -772,14 +716,12 @@ #define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ #define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ #define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ -#define PCI_EXT_CAP_SRIOV_SIZEOF 64 #define PCI_LTR_MAX_SNOOP_LAT 0x4 #define PCI_LTR_MAX_NOSNOOP_LAT 0x6 #define PCI_LTR_VALUE_MASK 0x000003ff #define PCI_LTR_SCALE_MASK 0x00001c00 #define PCI_LTR_SCALE_SHIFT 10 -#define PCI_EXT_CAP_LTR_SIZEOF 8 /* Access Control Service */ #define PCI_ACS_CAP 0x04 /* ACS Capability Register */ @@ -790,38 +732,7 @@ #define PCI_ACS_UF 0x10 /* Upstream Forwarding */ #define PCI_ACS_EC 0x20 /* P2P Egress Control */ #define PCI_ACS_DT 0x40 /* Direct Translated P2P */ -#define PCI_ACS_EGRESS_BITS 0x05 /* ACS Egress Control Vector Size */ #define PCI_ACS_CTRL 0x06 /* ACS Control Register */ #define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ -#define PCI_VSEC_HDR 4 /* extended cap - vendor specific */ -#define PCI_VSEC_HDR_LEN_SHIFT 20 /* shift for length field */ - -/* sata capability */ -#define PCI_SATA_REGS 4 /* SATA REGs specifier */ -#define PCI_SATA_REGS_MASK 0xF /* location - BAR#/inline */ -#define PCI_SATA_REGS_INLINE 0xF /* REGS in config space */ -#define PCI_SATA_SIZEOF_SHORT 8 -#define PCI_SATA_SIZEOF_LONG 16 - -/* resizable BARs */ -#define PCI_REBAR_CTRL 8 /* control register */ -#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */ -#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */ - -/* dynamic power allocation */ -#define PCI_DPA_CAP 4 /* capability register */ -#define PCI_DPA_CAP_SUBSTATE_MASK 0x1F /* # substates - 1 */ -#define PCI_DPA_BASE_SIZEOF 16 /* size with 0 substates */ - -/* TPH Requester */ -#define PCI_TPH_CAP 4 /* capability register */ -#define PCI_TPH_CAP_LOC_MASK 0x600 /* location mask */ -#define PCI_TPH_LOC_NONE 0x000 /* no location */ -#define PCI_TPH_LOC_CAP 0x200 /* in capability */ -#define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */ -#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* st table mask */ -#define PCI_TPH_CAP_ST_SHIFT 16 /* st table shift */ -#define PCI_TPH_BASE_SIZEOF 12 /* size with no st table */ - #endif /* LINUX_PCI_REGS_H */