aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-02-26 06:30:42 +0100
committerIngo Molnar <mingo@elte.hu>2009-02-26 06:30:42 +0100
commit13b2eda64d14d0a0c15c092664c7351ea58ea851 (patch)
treee0c82eb79a20f515f37ab3ffb9e5039b531eaa8c
parenta852cbfaaf8122827602027b1614971cfd832304 (diff)
parent55d8085671863fe4ee6a17b7814bd38180a44e1d (diff)
Merge branch 'x86/urgent' into x86/core
Conflicts: arch/x86/mach-voyager/voyager_smp.c
-rw-r--r--arch/x86/include/asm/iomap.h3
-rw-r--r--arch/x86/mm/iomap_32.c18
-rw-r--r--arch/x86/xen/enlighten.c3
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c9
-rw-r--r--include/linux/io-mapping.h46
5 files changed, 67 insertions, 12 deletions
diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h
index c1f06289b14..86af26091d6 100644
--- a/arch/x86/include/asm/iomap.h
+++ b/arch/x86/include/asm/iomap.h
@@ -23,6 +23,9 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+int
+is_io_mapping_possible(resource_size_t base, unsigned long size);
+
void *
iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c
index ca53224fc56..6c2b1af1692 100644
--- a/arch/x86/mm/iomap_32.c
+++ b/arch/x86/mm/iomap_32.c
@@ -20,6 +20,24 @@
#include <asm/pat.h>
#include <linux/module.h>
+#ifdef CONFIG_X86_PAE
+int
+is_io_mapping_possible(resource_size_t base, unsigned long size)
+{
+ return 1;
+}
+#else
+int
+is_io_mapping_possible(resource_size_t base, unsigned long size)
+{
+ /* There is no way to map greater than 1 << 32 address without PAE */
+ if (base + size > 0x100000000ULL)
+ return 0;
+
+ return 1;
+}
+#endif
+
/* Map 'pfn' using fixed map 'type' and protections 'prot'
*/
void *
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 86497d5f44c..c52f4034c7f 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -940,6 +940,9 @@ asmlinkage void __init xen_start_kernel(void)
possible map and a non-dummy shared_info. */
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+ local_irq_disable();
+ early_boot_irqs_off();
+
xen_raw_console_write("mapping kernel into physical memory\n");
pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2d797ffe813..6949c2d58f1 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1090,6 +1090,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->mm.gtt_mapping =
io_mapping_create_wc(dev->agp->base,
dev->agp->agp_info.aper_size * 1024*1024);
+ if (dev_priv->mm.gtt_mapping == NULL) {
+ ret = -EIO;
+ goto out_rmmap;
+ }
+
/* Set up a WC MTRR for non-PAT systems. This is more common than
* one would think, because the kernel disables PAT on first
* generation Core chips because WC PAT gets overridden by a UC
@@ -1122,7 +1127,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!I915_NEED_GFX_HWS(dev)) {
ret = i915_init_phys_hws(dev);
if (ret != 0)
- goto out_rmmap;
+ goto out_iomapfree;
}
/* On the 945G/GM, the chipset reports the MSI capability on the
@@ -1161,6 +1166,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
return 0;
+out_iomapfree:
+ io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap:
iounmap(dev_priv->regs);
free_priv:
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 82df31726a5..cbc2f0cd631 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -30,11 +30,14 @@
* See Documentation/io_mapping.txt
*/
-/* this struct isn't actually defined anywhere */
-struct io_mapping;
-
#ifdef CONFIG_HAVE_ATOMIC_IOMAP
+struct io_mapping {
+ resource_size_t base;
+ unsigned long size;
+ pgprot_t prot;
+};
+
/*
* For small address space machines, mapping large objects
* into the kernel virtual space isn't practical. Where
@@ -43,23 +46,40 @@ struct io_mapping;
*/
static inline struct io_mapping *
-io_mapping_create_wc(unsigned long base, unsigned long size)
+io_mapping_create_wc(resource_size_t base, unsigned long size)
{
- return (struct io_mapping *) base;
+ struct io_mapping *iomap;
+
+ if (!is_io_mapping_possible(base, size))
+ return NULL;
+
+ iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
+ if (!iomap)
+ return NULL;
+
+ iomap->base = base;
+ iomap->size = size;
+ iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL));
+ return iomap;
}
static inline void
io_mapping_free(struct io_mapping *mapping)
{
+ kfree(mapping);
}
/* Atomic map/unmap */
static inline void *
io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
{
- offset += (unsigned long) mapping;
- return iomap_atomic_prot_pfn(offset >> PAGE_SHIFT, KM_USER0,
- __pgprot(__PAGE_KERNEL_WC));
+ resource_size_t phys_addr;
+ unsigned long pfn;
+
+ BUG_ON(offset >= mapping->size);
+ phys_addr = mapping->base + offset;
+ pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
+ return iomap_atomic_prot_pfn(pfn, KM_USER0, mapping->prot);
}
static inline void
@@ -71,8 +91,9 @@ io_mapping_unmap_atomic(void *vaddr)
static inline void *
io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
{
- offset += (unsigned long) mapping;
- return ioremap_wc(offset, PAGE_SIZE);
+ BUG_ON(offset >= mapping->size);
+ resource_size_t phys_addr = mapping->base + offset;
+ return ioremap_wc(phys_addr, PAGE_SIZE);
}
static inline void
@@ -83,9 +104,12 @@ io_mapping_unmap(void *vaddr)
#else
+/* this struct isn't actually defined anywhere */
+struct io_mapping;
+
/* Create the io_mapping object*/
static inline struct io_mapping *
-io_mapping_create_wc(unsigned long base, unsigned long size)
+io_mapping_create_wc(resource_size_t base, unsigned long size)
{
return (struct io_mapping *) ioremap_wc(base, size);
}