>From d7d9760bf7052ee53e50beb7e89fc14371e33cfa Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Sat, 17 Oct 2009 21:17:16 +0200 Subject: [PATCH 4/6] Use MTRR for pci_mmap_resource_wc if PAT is not available X.org uses libpciaccess which tries to mmap with write combining enabled via /sys/bus/pci/devices/*/resource0_wc. Currently, when PAT is not enabled, we fall back to uncached mmap. Then libpciaccess thinks it succeeded mapping with write combining anabled and does not set up suited MTRR entries. ;-( So when falling back to uncached mapping, we better try to set up MTRR entries automatically. When the resource file is closed, we remove the MTRR entries again. Signed-off-by: Thomas Schlichter --- drivers/pci/pci-sysfs.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 0f6382f..604a063 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -23,6 +23,11 @@ #include #include #include +#include +#ifdef CONFIG_X86 +# include +# include +#endif #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -692,9 +697,10 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); struct resource *res = (struct resource *)attr->private; + struct bin_buffer *bb = (struct bin_buffer *)vma->vm_file->private_data; enum pci_mmap_state mmap_type; resource_size_t start, end; - int i; + int rc, i; for (i = 0; i < PCI_ROM_RESOURCE; i++) if (res == &pdev->resource[i]) @@ -716,7 +722,18 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start)) return -EINVAL; - return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); + rc = pci_mmap_page_range(pdev, vma, mmap_type, write_combine); +#ifdef CONFIG_X86 + if (!rc && !pat_enabled && write_combine) { + if (!bb->private) + bb->private = kzalloc(num_var_ranges * sizeof(int), + GFP_KERNEL); + mtrr_add_unaligned(vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, + MTRR_TYPE_WRCOMB, true, bb->private); + } +#endif // CONFIG_X86 + return rc; } static int @@ -733,6 +750,29 @@ pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr, return pci_mmap_resource(kobj, attr, vma, 1); } +static int +pci_release(struct kobject *kobj, struct bin_attribute *attr, struct file *file) +{ +#ifdef CONFIG_X86 + struct bin_buffer *bb = (struct bin_buffer *)file->private_data; + int i, *mtrr_usage = (int *)bb->private; + + if (!mtrr_usage) + return 0; + + for (i = 0; i < num_var_ranges; ++i) { + while (mtrr_usage[i] > 0) { + mtrr_del(i, 0, 0); + --mtrr_usage[i]; + } + } + + kfree(bb->private); + bb->private = NULL; +#endif // CONFIG_X86 + return 0; +} + /** * pci_remove_resource_files - cleanup resource files * @pdev: dev to cleanup @@ -782,6 +822,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) sprintf(res_attr_name, "resource%d", num); res_attr->mmap = pci_mmap_resource_uc; } + res_attr->release = pci_release; res_attr->attr.name = res_attr_name; res_attr->attr.mode = S_IRUSR | S_IWUSR; res_attr->size = pci_resource_len(pdev, num); -- 1.6.5