gpu/drm, x86, PAT: io_mapping_create_wc and resource_size_t
io_mapping_create_wc should take a resource_size_t parameter in place of unsigned long. With unsigned long, there will be no way to map greater than 4GB address in i386/32 bit. On x86, greater than 4GB addresses cannot be mapped on i386 without PAE. Return error for such a case. Patch also adds a structure for io_mapping, that saves the base, size and type on HAVE_ATOMIC_IOMAP archs, that can be used to verify the offset on io_mapping_map calls. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Dave Airlie <airlied@redhat.com> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: Eric Anholt <eric@anholt.net> Cc: Keith Packard <keithp@keithp.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Родитель
6644107d57
Коммит
4ab0d47d0a
|
@ -23,6 +23,9 @@
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
is_io_mapping_possible(resource_size_t base, unsigned long size);
|
||||||
|
|
||||||
void *
|
void *
|
||||||
iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
|
iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,24 @@
|
||||||
#include <asm/pat.h>
|
#include <asm/pat.h>
|
||||||
#include <linux/module.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'
|
/* Map 'pfn' using fixed map 'type' and protections 'prot'
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
|
|
|
@ -30,11 +30,14 @@
|
||||||
* See Documentation/io_mapping.txt
|
* See Documentation/io_mapping.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* this struct isn't actually defined anywhere */
|
|
||||||
struct io_mapping;
|
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_ATOMIC_IOMAP
|
#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
|
* For small address space machines, mapping large objects
|
||||||
* into the kernel virtual space isn't practical. Where
|
* into the kernel virtual space isn't practical. Where
|
||||||
|
@ -43,23 +46,40 @@ struct io_mapping;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline 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
|
static inline void
|
||||||
io_mapping_free(struct io_mapping *mapping)
|
io_mapping_free(struct io_mapping *mapping)
|
||||||
{
|
{
|
||||||
|
kfree(mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Atomic map/unmap */
|
/* Atomic map/unmap */
|
||||||
static inline void *
|
static inline void *
|
||||||
io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
|
io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
|
||||||
{
|
{
|
||||||
offset += (unsigned long) mapping;
|
resource_size_t phys_addr;
|
||||||
return iomap_atomic_prot_pfn(offset >> PAGE_SHIFT, KM_USER0,
|
unsigned long pfn;
|
||||||
__pgprot(__PAGE_KERNEL_WC));
|
|
||||||
|
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
|
static inline void
|
||||||
|
@ -71,8 +91,9 @@ io_mapping_unmap_atomic(void *vaddr)
|
||||||
static inline void *
|
static inline void *
|
||||||
io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
|
io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
|
||||||
{
|
{
|
||||||
offset += (unsigned long) mapping;
|
BUG_ON(offset >= mapping->size);
|
||||||
return ioremap_wc(offset, PAGE_SIZE);
|
resource_size_t phys_addr = mapping->base + offset;
|
||||||
|
return ioremap_wc(phys_addr, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -83,9 +104,12 @@ io_mapping_unmap(void *vaddr)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
/* this struct isn't actually defined anywhere */
|
||||||
|
struct io_mapping;
|
||||||
|
|
||||||
/* Create the io_mapping object*/
|
/* Create the io_mapping object*/
|
||||||
static inline 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 *) ioremap_wc(base, size);
|
return (struct io_mapping *) ioremap_wc(base, size);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче