mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	Pull mem-attribute into release branch
This commit is contained in:
		
						commit
						d29182534c
					
				
					 6 changed files with 392 additions and 58 deletions
				
			
		
							
								
								
									
										247
									
								
								Documentation/ia64/aliasing-test.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								Documentation/ia64/aliasing-test.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,247 @@ | |||
| /*
 | ||||
|  * Exercise /dev/mem mmap cases that have been troublesome in the past | ||||
|  * | ||||
|  * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. | ||||
|  *	Bjorn Helgaas <bjorn.helgaas@hp.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <fnmatch.h> | ||||
| #include <string.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| int sum; | ||||
| 
 | ||||
| int map_mem(char *path, off_t offset, size_t length, int touch) | ||||
| { | ||||
| 	int fd, rc; | ||||
| 	void *addr; | ||||
| 	int *c; | ||||
| 
 | ||||
| 	fd = open(path, O_RDWR); | ||||
| 	if (fd == -1) { | ||||
| 		perror(path); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); | ||||
| 	if (addr == MAP_FAILED) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if (touch) { | ||||
| 		c = (int *) addr; | ||||
| 		while (c < (int *) (offset + length)) | ||||
| 			sum += *c++; | ||||
| 	} | ||||
| 
 | ||||
| 	rc = munmap(addr, length); | ||||
| 	if (rc == -1) { | ||||
| 		perror("munmap"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	close(fd); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch) | ||||
| { | ||||
| 	struct dirent **namelist; | ||||
| 	char *name, *path2; | ||||
| 	int i, n, r, rc, result = 0; | ||||
| 	struct stat buf; | ||||
| 
 | ||||
| 	n = scandir(path, &namelist, 0, alphasort); | ||||
| 	if (n < 0) { | ||||
| 		perror("scandir"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < n; i++) { | ||||
| 		name = namelist[i]->d_name; | ||||
| 
 | ||||
| 		if (fnmatch(".", name, 0) == 0) | ||||
| 			goto skip; | ||||
| 		if (fnmatch("..", name, 0) == 0) | ||||
| 			goto skip; | ||||
| 
 | ||||
| 		path2 = malloc(strlen(path) + strlen(name) + 3); | ||||
| 		strcpy(path2, path); | ||||
| 		strcat(path2, "/"); | ||||
| 		strcat(path2, name); | ||||
| 
 | ||||
| 		if (fnmatch(file, name, 0) == 0) { | ||||
| 			rc = map_mem(path2, offset, length, touch); | ||||
| 			if (rc == 0) | ||||
| 				fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable"); | ||||
| 			else if (rc > 0) | ||||
| 				fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length); | ||||
| 			else { | ||||
| 				fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length); | ||||
| 				return rc; | ||||
| 			} | ||||
| 		} else { | ||||
| 			r = lstat(path2, &buf); | ||||
| 			if (r == 0 && S_ISDIR(buf.st_mode)) { | ||||
| 				rc = scan_sysfs(path2, file, offset, length, touch); | ||||
| 				if (rc < 0) | ||||
| 					return rc; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		result |= rc; | ||||
| 		free(path2); | ||||
| 
 | ||||
| skip: | ||||
| 		free(namelist[i]); | ||||
| 	} | ||||
| 	free(namelist); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| char buf[1024]; | ||||
| 
 | ||||
| int read_rom(char *path) | ||||
| { | ||||
| 	int fd, rc; | ||||
| 	size_t size = 0; | ||||
| 
 | ||||
| 	fd = open(path, O_RDWR); | ||||
| 	if (fd == -1) { | ||||
| 		perror(path); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	rc = write(fd, "1", 2); | ||||
| 	if (rc <= 0) { | ||||
| 		perror("write"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	do { | ||||
| 		rc = read(fd, buf, sizeof(buf)); | ||||
| 		if (rc > 0) | ||||
| 			size += rc; | ||||
| 	} while (rc > 0); | ||||
| 
 | ||||
| 	close(fd); | ||||
| 	return size; | ||||
| } | ||||
| 
 | ||||
| int scan_rom(char *path, char *file) | ||||
| { | ||||
| 	struct dirent **namelist; | ||||
| 	char *name, *path2; | ||||
| 	int i, n, r, rc, result = 0; | ||||
| 	struct stat buf; | ||||
| 
 | ||||
| 	n = scandir(path, &namelist, 0, alphasort); | ||||
| 	if (n < 0) { | ||||
| 		perror("scandir"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < n; i++) { | ||||
| 		name = namelist[i]->d_name; | ||||
| 
 | ||||
| 		if (fnmatch(".", name, 0) == 0) | ||||
| 			goto skip; | ||||
| 		if (fnmatch("..", name, 0) == 0) | ||||
| 			goto skip; | ||||
| 
 | ||||
| 		path2 = malloc(strlen(path) + strlen(name) + 3); | ||||
| 		strcpy(path2, path); | ||||
| 		strcat(path2, "/"); | ||||
| 		strcat(path2, name); | ||||
| 
 | ||||
| 		if (fnmatch(file, name, 0) == 0) { | ||||
| 			rc = read_rom(path2); | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * It's OK if the ROM is unreadable.  Maybe there | ||||
| 			 * is no ROM, or some other error ocurred.  The | ||||
| 			 * important thing is that no MCA happened. | ||||
| 			 */ | ||||
| 			if (rc > 0) | ||||
| 				fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc); | ||||
| 			else { | ||||
| 				fprintf(stderr, "PASS: %s not readable\n", path2); | ||||
| 				return rc; | ||||
| 			} | ||||
| 		} else { | ||||
| 			r = lstat(path2, &buf); | ||||
| 			if (r == 0 && S_ISDIR(buf.st_mode)) { | ||||
| 				rc = scan_rom(path2, file); | ||||
| 				if (rc < 0) | ||||
| 					return rc; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		result |= rc; | ||||
| 		free(path2); | ||||
| 
 | ||||
| skip: | ||||
| 		free(namelist[i]); | ||||
| 	} | ||||
| 	free(namelist); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| main() | ||||
| { | ||||
| 	int rc; | ||||
| 
 | ||||
| 	if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0) | ||||
| 		fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n"); | ||||
| 	else | ||||
| 		fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * It's not safe to blindly read the VGA frame buffer.  If you know | ||||
| 	 * how to poke the card the right way, it should respond, but it's | ||||
| 	 * not safe in general.  Many machines, e.g., Intel chipsets, cover | ||||
| 	 * up a non-responding card by just returning -1, but others will | ||||
| 	 * report the failure as a machine check. | ||||
| 	 */ | ||||
| 	if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0) | ||||
| 		fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n"); | ||||
| 	else | ||||
| 		fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n"); | ||||
| 
 | ||||
| 	if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0) | ||||
| 		fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n"); | ||||
| 	else | ||||
| 		fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Often you can map all the individual pieces above (0-0xA0000, | ||||
| 	 * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole | ||||
| 	 * thing at once.  This is because the individual pieces use different | ||||
| 	 * attributes, and there's no single attribute supported over the | ||||
| 	 * whole region. | ||||
| 	 */ | ||||
| 	rc = map_mem("/dev/mem", 0, 1024*1024, 0); | ||||
| 	if (rc == 0) | ||||
| 		fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n"); | ||||
| 	else if (rc > 0) | ||||
| 		fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n"); | ||||
| 	else | ||||
| 		fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n"); | ||||
| 
 | ||||
| 	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1); | ||||
| 	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0); | ||||
| 	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1); | ||||
| 	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0); | ||||
| 
 | ||||
| 	scan_rom("/sys/devices", "rom"); | ||||
| } | ||||
|  | @ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES | |||
| 
 | ||||
| 	The /dev/mem mmap constraints apply. | ||||
| 
 | ||||
| 	However, since this is for mapping legacy MMIO space, WB access | ||||
| 	does not make sense.  This matters on machines without legacy | ||||
| 	VGA support: these machines may have WB memory for the entire | ||||
| 	first megabyte (or even the entire first granule). | ||||
| 
 | ||||
| 	On these machines, we could mmap legacy_mem as WB, which would | ||||
| 	be safe in terms of attribute aliasing, but X has no way of | ||||
| 	knowing that it is accessing regular memory, not a frame buffer, | ||||
| 	so the kernel should fail the mmap rather than doing it with WB. | ||||
| 
 | ||||
|     read/write of /dev/mem | ||||
| 
 | ||||
| 	This uses copy_from_user(), which implicitly uses a kernel | ||||
|  | @ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES | |||
| 
 | ||||
|     ioremap() | ||||
| 
 | ||||
| 	This returns a kernel identity mapping for use inside the | ||||
| 	kernel. | ||||
| 	This returns a mapping for use inside the kernel. | ||||
| 
 | ||||
| 	If the region is in kern_memmap, we should use the attribute | ||||
| 	specified there.  Otherwise, if the EFI memory map reports that | ||||
| 	the entire granule supports WB, we should use that (granules | ||||
| 	that are partially reserved or occupied by firmware do not appear | ||||
| 	in kern_memmap).  Otherwise, we should use a UC mapping. | ||||
| 	specified there. | ||||
| 
 | ||||
| 	If the EFI memory map reports that the entire granule supports | ||||
| 	WB, we should use that (granules that are partially reserved | ||||
| 	or occupied by firmware do not appear in kern_memmap). | ||||
| 
 | ||||
| 	If the granule contains non-WB memory, but we can cover the | ||||
| 	region safely with kernel page table mappings, we can use | ||||
| 	ioremap_page_range() as most other architectures do. | ||||
| 
 | ||||
| 	Failing all of the above, we have to fall back to a UC mapping. | ||||
| 
 | ||||
| PAST PROBLEM CASES | ||||
| 
 | ||||
|  | @ -158,7 +154,7 @@ PAST PROBLEM CASES | |||
|       succeed.  It may create either WB or UC user mappings, depending | ||||
|       on whether the region is in kern_memmap or the EFI memory map. | ||||
| 
 | ||||
|     mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled | ||||
|     mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled | ||||
| 
 | ||||
|       See https://bugzilla.novell.com/show_bug.cgi?id=140858. | ||||
| 
 | ||||
|  | @ -171,28 +167,25 @@ PAST PROBLEM CASES | |||
|       so it is safe to use WB mappings. | ||||
| 
 | ||||
|       The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000, | ||||
|       which will use a granule-sized UC mapping covering 0-0xFFFFF.  This | ||||
|       granule covers some WB-only memory, but since UC is non-speculative, | ||||
|       the processor will never generate an uncacheable reference to the | ||||
|       WB-only areas unless the driver explicitly touches them. | ||||
|       which uses a granule-sized UC mapping.  This granule will cover some | ||||
|       WB-only memory, but since UC is non-speculative, the processor will | ||||
|       never generate an uncacheable reference to the WB-only areas unless | ||||
|       the driver explicitly touches them. | ||||
| 
 | ||||
|     mmap of 0x0-0xFFFFF legacy_mem by "X" | ||||
| 
 | ||||
|       If the EFI memory map reports this entire range as WB, there | ||||
|       is no VGA MMIO hole, and the mmap should fail or be done with | ||||
|       a WB mapping. | ||||
|       If the EFI memory map reports that the entire range supports the | ||||
|       same attributes, we can allow the mmap (and we will prefer WB if | ||||
|       supported, as is the case with HP sx[12]000 machines with VGA | ||||
|       disabled). | ||||
| 
 | ||||
|       There's no easy way for X to determine whether the 0xA0000-0xBFFFF | ||||
|       region is a frame buffer or just memory, so I think it's best to | ||||
|       just fail this mmap request rather than using a WB mapping.  As | ||||
|       far as I know, there's no need to map legacy_mem with WB | ||||
|       mappings. | ||||
|       If EFI reports the range as partly WB and partly UC (as on sx[12]000 | ||||
|       machines with VGA enabled), we must fail the mmap because there's no | ||||
|       safe attribute to use. | ||||
| 
 | ||||
|       Otherwise, a UC mapping of the entire region is probably safe. | ||||
|       The VGA hole means the region will not be in kern_memmap.  The | ||||
|       HP sx1000 chipset doesn't support UC access to the memory surrounding | ||||
|       the VGA hole, but X doesn't need that area anyway and should not | ||||
|       reference it. | ||||
|       If EFI reports some of the range but not all (as on Intel firmware | ||||
|       that doesn't report the VGA frame buffer at all), we should fail the | ||||
|       mmap and force the user to map just the specific region of interest. | ||||
| 
 | ||||
|     mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled | ||||
| 
 | ||||
|  | @ -202,6 +195,16 @@ PAST PROBLEM CASES | |||
|       This is a special case of the previous case, and the mmap should | ||||
|       fail for the same reason as above. | ||||
| 
 | ||||
|     read of /sys/devices/.../rom | ||||
| 
 | ||||
|       For VGA devices, this may cause an ioremap() of 0xC0000.  This | ||||
|       used to be done with a UC mapping, because the VGA frame buffer | ||||
|       at 0xA0000 prevents use of a WB granule.  The UC mapping causes | ||||
|       an MCA on HP sx[12]000 chipsets. | ||||
| 
 | ||||
|       We should use WB page table mappings to avoid covering the VGA | ||||
|       frame buffer. | ||||
| 
 | ||||
| NOTES | ||||
| 
 | ||||
|     [1] SDM rev 2.2, vol 2, sec 4.4.1. | ||||
|  |  | |||
|  | @ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phys_addr) | |||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| efi_memmap_intersects (unsigned long phys_addr, unsigned long size) | ||||
| { | ||||
| 	void *efi_map_start, *efi_map_end, *p; | ||||
| 	efi_memory_desc_t *md; | ||||
| 	u64 efi_desc_size; | ||||
| 	unsigned long end; | ||||
| 
 | ||||
| 	efi_map_start = __va(ia64_boot_param->efi_memmap); | ||||
| 	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size; | ||||
| 	efi_desc_size = ia64_boot_param->efi_memdesc_size; | ||||
| 
 | ||||
| 	end = phys_addr + size; | ||||
| 
 | ||||
| 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { | ||||
| 		md = p; | ||||
| 
 | ||||
| 		if (md->phys_addr < end && efi_md_end(md) > phys_addr) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| u32 | ||||
| efi_mem_type (unsigned long phys_addr) | ||||
| { | ||||
|  | @ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phys_addr, unsigned long size) | |||
| int | ||||
| valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size) | ||||
| { | ||||
| 	unsigned long phys_addr = pfn << PAGE_SHIFT; | ||||
| 	u64 attr; | ||||
| 
 | ||||
| 	attr = efi_mem_attribute(phys_addr, size); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * MMIO regions are often missing from the EFI memory map. | ||||
| 	 * We must allow mmap of them for programs like X, so we | ||||
| 	 * currently can't do any useful validation. | ||||
| 	 * /dev/mem mmap uses normal user pages, so we don't need the entire | ||||
| 	 * granule, but the entire region we're mapping must support the same | ||||
| 	 * attribute. | ||||
| 	 */ | ||||
| 	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Intel firmware doesn't tell us about all the MMIO regions, so | ||||
| 	 * in general we have to allow mmap requests.  But if EFI *does* | ||||
| 	 * tell us about anything inside this region, we should deny it. | ||||
| 	 * The user can always map a smaller region to avoid the overlap. | ||||
| 	 */ | ||||
| 	if (efi_memmap_intersects(phys_addr, size)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| /*
 | ||||
|  * (c) Copyright 2006 Hewlett-Packard Development Company, L.P. | ||||
|  * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P. | ||||
|  *	Bjorn Helgaas <bjorn.helgaas@hp.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  | @ -10,51 +10,101 @@ | |||
| #include <linux/compiler.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/efi.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/vmalloc.h> | ||||
| #include <asm/io.h> | ||||
| #include <asm/meminit.h> | ||||
| 
 | ||||
| static inline void __iomem * | ||||
| __ioremap (unsigned long offset, unsigned long size) | ||||
| __ioremap (unsigned long phys_addr) | ||||
| { | ||||
| 	return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset); | ||||
| 	return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr); | ||||
| } | ||||
| 
 | ||||
| void __iomem * | ||||
| ioremap (unsigned long offset, unsigned long size) | ||||
| ioremap (unsigned long phys_addr, unsigned long size) | ||||
| { | ||||
| 	void __iomem *addr; | ||||
| 	struct vm_struct *area; | ||||
| 	unsigned long offset; | ||||
| 	pgprot_t prot; | ||||
| 	u64 attr; | ||||
| 	unsigned long gran_base, gran_size; | ||||
| 	unsigned long page_base; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * For things in kern_memmap, we must use the same attribute | ||||
| 	 * as the rest of the kernel.  For more details, see | ||||
| 	 * Documentation/ia64/aliasing.txt. | ||||
| 	 */ | ||||
| 	attr = kern_mem_attribute(offset, size); | ||||
| 	attr = kern_mem_attribute(phys_addr, size); | ||||
| 	if (attr & EFI_MEMORY_WB) | ||||
| 		return (void __iomem *) phys_to_virt(offset); | ||||
| 		return (void __iomem *) phys_to_virt(phys_addr); | ||||
| 	else if (attr & EFI_MEMORY_UC) | ||||
| 		return __ioremap(offset, size); | ||||
| 		return __ioremap(phys_addr); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some chipsets don't support UC access to memory.  If | ||||
| 	 * WB is supported for the whole granule, we prefer that. | ||||
| 	 */ | ||||
| 	gran_base = GRANULEROUNDDOWN(offset); | ||||
| 	gran_size = GRANULEROUNDUP(offset + size) - gran_base; | ||||
| 	gran_base = GRANULEROUNDDOWN(phys_addr); | ||||
| 	gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base; | ||||
| 	if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB) | ||||
| 		return (void __iomem *) phys_to_virt(offset); | ||||
| 		return (void __iomem *) phys_to_virt(phys_addr); | ||||
| 
 | ||||
| 	return __ioremap(offset, size); | ||||
| 	/*
 | ||||
| 	 * WB is not supported for the whole granule, so we can't use | ||||
| 	 * the region 7 identity mapping.  If we can safely cover the | ||||
| 	 * area with kernel page table mappings, we can use those | ||||
| 	 * instead. | ||||
| 	 */ | ||||
| 	page_base = phys_addr & PAGE_MASK; | ||||
| 	size = PAGE_ALIGN(phys_addr + size) - page_base; | ||||
| 	if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) { | ||||
| 		prot = PAGE_KERNEL; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Mappings have to be page-aligned | ||||
| 		 */ | ||||
| 		offset = phys_addr & ~PAGE_MASK; | ||||
| 		phys_addr &= PAGE_MASK; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Ok, go for it.. | ||||
| 		 */ | ||||
| 		area = get_vm_area(size, VM_IOREMAP); | ||||
| 		if (!area) | ||||
| 			return NULL; | ||||
| 
 | ||||
| 		area->phys_addr = phys_addr; | ||||
| 		addr = (void __iomem *) area->addr; | ||||
| 		if (ioremap_page_range((unsigned long) addr, | ||||
| 				(unsigned long) addr + size, phys_addr, prot)) { | ||||
| 			vunmap((void __force *) addr); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		return (void __iomem *) (offset + (char __iomem *)addr); | ||||
| 	} | ||||
| 
 | ||||
| 	return __ioremap(phys_addr); | ||||
| } | ||||
| EXPORT_SYMBOL(ioremap); | ||||
| 
 | ||||
| void __iomem * | ||||
| ioremap_nocache (unsigned long offset, unsigned long size) | ||||
| ioremap_nocache (unsigned long phys_addr, unsigned long size) | ||||
| { | ||||
| 	if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB) | ||||
| 	if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	return __ioremap(offset, size); | ||||
| 	return __ioremap(phys_addr); | ||||
| } | ||||
| EXPORT_SYMBOL(ioremap_nocache); | ||||
| 
 | ||||
| void | ||||
| iounmap (volatile void __iomem *addr) | ||||
| { | ||||
| 	if (REGION_NUMBER(addr) == RGN_GATE) | ||||
| 		vunmap((void *) ((unsigned long) addr & PAGE_MASK)); | ||||
| } | ||||
| EXPORT_SYMBOL(iounmap); | ||||
|  |  | |||
|  | @ -659,8 +659,6 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma) | |||
| 		return -EINVAL; | ||||
| 	prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, | ||||
| 				    vma->vm_page_prot); | ||||
| 	if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	addr = pci_get_legacy_mem(bus); | ||||
| 	if (IS_ERR(addr)) | ||||
|  |  | |||
|  | @ -421,11 +421,7 @@ __writeq (unsigned long val, volatile void __iomem *addr) | |||
| 
 | ||||
| extern void __iomem * ioremap(unsigned long offset, unsigned long size); | ||||
| extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); | ||||
| 
 | ||||
| static inline void | ||||
| iounmap (volatile void __iomem *addr) | ||||
| { | ||||
| } | ||||
| extern void iounmap (volatile void __iomem *addr); | ||||
| 
 | ||||
| /* Use normal IO mappings for DMI */ | ||||
| #define dmi_ioremap ioremap | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Tony Luck
						Tony Luck